commit
ea013ce71a
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
Build:
|
||||
|
||||
```bash
|
||||
docker-compose -f ros2/docker/docker-compose.yml build
|
||||
```
|
||||
|
||||
Up:
|
||||
|
||||
```bash
|
||||
docker-compose -f ros2/docker/docker-compose.yml up
|
||||
```
|
||||
|
@ -0,0 +1,23 @@
|
||||
# Используем официальный образ ROS 2 Humble
|
||||
FROM osrf/ros:humble-desktop
|
||||
|
||||
# Установка необходимых инструментов
|
||||
RUN apt-get update && apt-get install -y \
|
||||
python3-colcon-common-extensions \
|
||||
python3-pip \
|
||||
&& apt-get clean
|
||||
|
||||
# Создание рабочей директории
|
||||
WORKDIR /ros2_ws
|
||||
|
||||
# Копируем рабочее пространство в контейнер
|
||||
COPY ros2_ws /ros2_ws
|
||||
|
||||
# Устанавливаем зависимости Python
|
||||
RUN pip3 install -r /ros2_ws/src/my_python_pkg/requirements.txt
|
||||
|
||||
# Сборка рабочего пространства
|
||||
RUN /bin/bash -c "source /opt/ros/humble/setup.bash && colcon build"
|
||||
|
||||
# Настройка контейнера для запуска ROS 2
|
||||
CMD ["/bin/bash", "-c", "source /opt/ros/humble/setup.bash && source install/setup.bash && bash"]
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0"?>
|
||||
<package format="3">
|
||||
<name>my_python_pkg</name>
|
||||
<version>0.0.1</version>
|
||||
<description>Пример Python-пакета для ROS 2</description>
|
||||
<maintainer email="your.email@example.com">Ваше Имя</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
<exec_depend>rclpy</exec_depend>
|
||||
<exec_depend>std_msgs</exec_depend>
|
||||
</package>
|
@ -0,0 +1,23 @@
|
||||
# /ros2_ws/src/my_python_pkg/setup.py
|
||||
from setuptools import setup
|
||||
|
||||
package_name = 'my_python_pkg'
|
||||
|
||||
setup(
|
||||
name=package_name,
|
||||
version='0.0.0',
|
||||
packages=[package_name],
|
||||
install_requires=['setuptools'],
|
||||
zip_safe=True,
|
||||
maintainer='Ваше Имя',
|
||||
maintainer_email='your.email@example.com',
|
||||
description='Пример Python-пакета для ROS 2',
|
||||
license='Apache License 2.0',
|
||||
tests_require=['pytest'],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'publisher = my_python_pkg.publisher:main',
|
||||
'subscriber = my_python_pkg.subscriber:main',
|
||||
],
|
||||
},
|
||||
)
|
@ -0,0 +1,118 @@
|
||||
from pymodbus.client import ModbusTcpClient
|
||||
from pymodbus.exceptions import ModbusException
|
||||
|
||||
class RobotGripper:
|
||||
def __init__(self, ip, port=502):
|
||||
"""
|
||||
Инициализация класса управления захватом робота.
|
||||
:param ip: IP-адрес устройства
|
||||
:param port: Порт Modbus TCP (по умолчанию 502)
|
||||
"""
|
||||
self.ip = ip
|
||||
self.port = port
|
||||
self.client = ModbusTcpClient(ip, port)
|
||||
self.connected = False
|
||||
|
||||
def connect(self):
|
||||
"""Подключение к захвату"""
|
||||
try:
|
||||
self.client.connect()
|
||||
self.connected = True
|
||||
except ModbusException as e:
|
||||
print(f"Ошибка подключения: {e}")
|
||||
|
||||
def disconnect(self):
|
||||
"""Отключение от захвата"""
|
||||
if self.connected:
|
||||
self.client.close()
|
||||
self.connected = False
|
||||
|
||||
def initialize(self, full=False):
|
||||
"""
|
||||
Инициализация захвата.
|
||||
:param full: Если True, выполнить полную инициализацию
|
||||
:return: Ответ устройства
|
||||
"""
|
||||
if not self.connected:
|
||||
raise ModbusException("Нет подключения к захвату.")
|
||||
|
||||
value = 0xA5 if full else 0x01
|
||||
address = 0x0100
|
||||
response = self.client.write_register(address, value, slave=1)
|
||||
return response
|
||||
|
||||
def set_force(self, force):
|
||||
"""
|
||||
Установка силы захвата.
|
||||
:param force: Значение силы (20-100%)
|
||||
:return: Ответ устройства
|
||||
"""
|
||||
if not 20 <= force <= 100:
|
||||
raise ValueError("Сила захвата должна быть в диапазоне 20-100%.")
|
||||
|
||||
if not self.connected:
|
||||
raise ModbusException("Нет подключения к захвату.")
|
||||
|
||||
address = 0x0101
|
||||
response = self.client.write_register(address, force, slave=1)
|
||||
return response
|
||||
|
||||
def set_position(self, position):
|
||||
"""
|
||||
Установка позиции захвата.
|
||||
:param position: Значение позиции (0-1000)
|
||||
:return: Ответ устройства
|
||||
"""
|
||||
if not 0 <= position <= 1000:
|
||||
raise ValueError("Позиция должна быть в диапазоне 0-1000.")
|
||||
|
||||
if not self.connected:
|
||||
raise ModbusException("Нет подключения к захвату.")
|
||||
|
||||
address = 0x0103
|
||||
response = self.client.write_register(address, position, slave=1)
|
||||
return response
|
||||
|
||||
def read_register(self, address):
|
||||
"""
|
||||
Чтение значения из регистра.
|
||||
:param address: Адрес регистра
|
||||
:return: Значение регистра
|
||||
"""
|
||||
if not self.connected:
|
||||
raise ModbusException("Нет подключения к захвату.")
|
||||
|
||||
response = self.client.read_holding_registers(address, count=1, slave=1)
|
||||
if response.isError():
|
||||
raise ModbusException(f"Ошибка чтения регистра {address}.")
|
||||
return response.registers[0]
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Получение статуса захвата.
|
||||
:return: Словарь статусов (инициализация, состояние захвата, позиция)
|
||||
"""
|
||||
if not self.connected:
|
||||
raise ModbusException("Нет подключения к захвату.")
|
||||
|
||||
status = {
|
||||
"initialization_state": self.read_register(0x0200),
|
||||
"gripper_state": self.read_register(0x0201),
|
||||
"current_position": self.read_register(0x0202)
|
||||
}
|
||||
return status
|
||||
|
||||
# Пример использования
|
||||
if __name__ == "__main__":
|
||||
gripper = RobotGripper("10.27.1.80")
|
||||
try:
|
||||
gripper.connect()
|
||||
gripper.initialize(full=True)
|
||||
gripper.set_force(50)
|
||||
gripper.set_position(800)
|
||||
status = gripper.get_status()
|
||||
print("Статус захвата:", status)
|
||||
except Exception as e:
|
||||
print(f"Ошибка: {e}")
|
||||
finally:
|
||||
gripper.disconnect()
|
@ -0,0 +1 @@
|
||||
pymodbus
|
@ -0,0 +1,40 @@
|
||||
import socket
|
||||
import math
|
||||
import time
|
||||
|
||||
IP = "192.168.1.201"
|
||||
PORT = 6000
|
||||
|
||||
def get_integer_and_fractional_parts(number):
|
||||
integer_fractional = str(abs(number)).split('.')
|
||||
return list(map(int, integer_fractional))
|
||||
|
||||
def pad_number(number):
|
||||
integer_part, fractional_part = get_integer_and_fractional_parts(number)
|
||||
pad_length = 6
|
||||
integer_part = str(integer_part)[:pad_length].rjust(pad_length, '0')
|
||||
fractional_part = str(fractional_part)[:pad_length].ljust(pad_length, '0')
|
||||
prefix = "+"
|
||||
if number < 0:
|
||||
prefix = "-"
|
||||
return (f"{prefix}{integer_part}.{fractional_part}", 2 + pad_length * 2)
|
||||
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
sock.connect((IP, PORT))
|
||||
|
||||
# data = sock.recv(1024)
|
||||
# print(data)
|
||||
|
||||
while True:
|
||||
|
||||
t = time.time()
|
||||
frequency = 0.1
|
||||
|
||||
target = 1 * math.sin(frequency * 2.0 * math.pi * t)
|
||||
|
||||
for i in range(6):
|
||||
padded, _ = pad_number(target)
|
||||
print(padded)
|
||||
message = padded.encode('utf-8')
|
||||
sock.sendall(message)
|
||||
time.sleep(0.05)
|
@ -0,0 +1,26 @@
|
||||
# Используем базовый образ ROS 2 Humble
|
||||
FROM ros:humble
|
||||
|
||||
# Устанавливаем необходимые зависимости
|
||||
RUN apt-get update && apt-get install -y \
|
||||
python3-colcon-common-extensions \
|
||||
python3-pip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Устанавливаем Python зависимости
|
||||
RUN pip3 install pymodbus
|
||||
|
||||
# Создаем рабочую директорию
|
||||
WORKDIR /ros2_ws
|
||||
|
||||
# Копируем исходный код
|
||||
COPY ./src /ros2_ws/src
|
||||
|
||||
# Сборка ROS 2 workspace
|
||||
RUN . /opt/ros/humble/setup.sh && colcon build
|
||||
|
||||
# Указываем рабочее окружение
|
||||
RUN echo "source /ros2_ws/install/setup.bash" >> ~/.bashrc
|
||||
|
||||
# Точка входа
|
||||
CMD ["bash"]
|
@ -0,0 +1,21 @@
|
||||
version: "3.8"
|
||||
services:
|
||||
manipulator:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: ros2/docker/Dockerfile
|
||||
container_name: manipulator_node
|
||||
network_mode: host
|
||||
environment:
|
||||
- ROS_DOMAIN_ID=0
|
||||
command: bash -c "source /opt/ros/humble/setup.bash && source /ros2_ws/install/setup.bash && ros2 run robotic_complex manipulator_node"
|
||||
|
||||
gripper:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: ros2/docker/Dockerfile
|
||||
container_name: gripper_node
|
||||
network_mode: host
|
||||
environment:
|
||||
- ROS_DOMAIN_ID=0
|
||||
command: bash -c "source /opt/ros/humble/setup.bash && source /ros2_ws/install/setup.bash && ros2 run robotic_complex gripper_node"
|
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0"?>
|
||||
<package format="2">
|
||||
<name>robotic_complex</name>
|
||||
<version>0.0.1</version>
|
||||
<description>ROS 2 пакет для управления манипулятором и захватом</description>
|
||||
|
||||
<maintainer email="your.email@example.com">Ваше Имя</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<buildtool_depend>ament_python</buildtool_depend>
|
||||
<build_type>ament_python</build_type>
|
||||
|
||||
<exec_depend>rclpy</exec_depend>
|
||||
<exec_depend>std_msgs</exec_depend>
|
||||
<exec_depend>geometry_msgs</exec_depend>
|
||||
<exec_depend>pymodbus</exec_depend>
|
||||
|
||||
<export>
|
||||
</export>
|
||||
</package>
|
@ -0,0 +1,22 @@
|
||||
from setuptools import setup
|
||||
|
||||
package_name = 'robotic_complex'
|
||||
|
||||
setup(
|
||||
name=package_name,
|
||||
version='0.0.1',
|
||||
packages=[package_name],
|
||||
install_requires=['setuptools'],
|
||||
zip_safe=True,
|
||||
maintainer='Ваше Имя',
|
||||
maintainer_email='your.email@example.com',
|
||||
description='ROS 2 пакет для управления манипулятором и захватом',
|
||||
license='Apache License 2.0',
|
||||
tests_require=['pytest'],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'manipulator_node = robotic_complex.manipulator_node:main',
|
||||
'gripper_node = robotic_complex.gripper_node:main',
|
||||
],
|
||||
},
|
||||
)
|
Loading…
Reference in new issue