Отдел передовых технологий работает над мультимодальным обучением с подкреплением, включая изображения с камер и тактильные датчики. Помимо прочего, для реализации так называемого Sim2Real, в котором результаты обучения с подкреплением в симуляторе также выполняются на реальной машине, роботизированная рука и камера реальной машины должны управляться совместно. Поэтому в данном случае мы протестировали связанный 6-осевой роботизированный манипулятор myCobot (производства Elephant Robotics) и камеру глубины RealSense D455 (производства Intel) с использованием ROS, процесс и результаты будут подробно описаны ниже.
Операционная среда:
PC:Ubuntu 20.04, ROS Noetic, Python 3.8.10
Роботизированная рука: myCobot280 M5Stack
Камера глубины: RealSense D455
В этом блоге описывается, как создать и запустить простую программу, но я предполагаю, что среды ROS и Python уже настроены.
Сначала подготовьте myCobot, но я немного запутался, потому что некоторые детали изменились в процессе использования из-за обновлений прошивки и так далее. Эта работа находится в 2021 Год 3 Оно было завершено около 2 месяцев назад, когда myStudio версия 1.3.<>。Я не думаю, что будут какие-то серьезные изменения,Но если посмотреть на разницу в приезжать,Смотрите официальное описание.
Для запуска myCobot необходимы следующие три подготовки.
● Обновить прошивку(базовый,атом)
● Калибровка суставов роботизированной руки.
● Последовательная связь между манипулятором робота и ПК.
myCobot 280 M5 имеет M5Stack Basic в основании и ATOM (Basic, ATOM) на конце роботизированной руки для записи прошивки в эти два модуля.
Во-первых, используйте USB подключиться к ПК и использование chmod Разрешить чтение и запись на устройство. также,Для последовательной связи USB на Windows или Mac,Требуется установкаспециальный водитель。
$ sudo chmod 666 /dev/ttyUSB*
Следующий,Загрузите обновленную прошивкуПриложение-myStudio(существовать На момент написания,до настоящего времениверсия3.1.4,Но только для Windows,3.1.3 доступна для Linux).
После извлечения исходного кода и выполнения AppImage запустится Basic и ATOM соответственно. Как показано на рисунке 1 и рисунке 2.
В myStudio 3.1.3 появится экран, показанный на рисунках 3 и 4, затем загрузите последнюю версию Minirobot для Basic и AtomMain для ATOM, выберите Flash и запишите прошивку. После завершения написания с использованием Basic на панели отобразится вывод мини-робота. (Обратите внимание, что если вы не напишете последнюю версию с использованием Basic и ATOM, манипулятор робота может работать некорректно).
После Обновить прошивку следующим шагом будет калибровка угла шарнира.
Сначала выберите «Калибровка» на панели «Основные» и нажмите «ОК».
На каждом сочленении myCobot есть выемка, обозначающая начало координат, как показано на рис. 5, поэтому выемки выравниваются друг с другом вручную.
В этом состоянии выберите «Калибровать сервопривод» на панели «Основные» и нажмите «Далее», чтобы завершить калибровку. Запуск тестового сервопривода позволит двигателю слегка вращаться вокруг выемки, чтобы подтвердить правильную калибровку.
Наконец, когда вы запустите транспондер, вы сможете управлять myCobot со своего ПК через последовательную связь. Это легко сделать: просто выберите транспондер на панели «Основные» и нажмите «ОК». Затем на дисплее появится изображение, как показано на рисунке 6. Нажмите кнопку «Основные».
В других меню панели Basic Master Control в Basic управляет ATOM, а Information проверяет правильность подключения каждого соединения. Если myCobot не работает должным образом на вашем компьютере, вы можете проверить, есть ли проблема с самим myCobot.
После завершения подготовки мы можем управлять myCobot на ПК. На этот раз я попробовал метод работы из скрипта Python с использованием pymycobot и метод работы MoveIt из ROS с использованием библиотеки mycobot_moveit.
первый,Установитьpymycobot。
$ pip install pymycobot --upgrade
Вы также можете выбрать из Github Загрузите и установите исходный код.
Примеры сценариев включаются в тестовый каталог при загрузке из исходного кода. Однако в исходном виде это не сработает, поэтому будьте осторожны. Я сделал пример ниже вместо того, чтобы переписывать его.
# mycobot_control_test.py#!/usr/bin/env pythonimport time from pymycobot.mycobot import MyCobotfrom pymycobot.genre import Angle, Coord if __name__ == "__main__":port = "/dev/ttyUSB0"mycobot = MyCobot(port, baudrate="115200", timeout=0.1, debug=False) #After the baud rate are the default values #Get the operation of the joint angleprint("get angles")print(" degrees: {}\n".format(mycobot.get_angles()))time.sleep(0.5) print("get radians")print(" radians: {}\n".format(mycobot.get_radians()))time.sleep(0.5) print("send angles: [0, 0, 0, 0, -90, 0]")mycobot.send_angles([0, 0, 0, 0, 0, 0], 80)time.sleep(1.5)mycobot.send_angles([0, 0, 0, 0, -90, 0], 80)print(" Is moving: {}\n".format(mycobot.is_moving()))time.sleep(1.5) print("send radians: [0, 0, 0, 0, 1.57, 0]\n")mycobot.send_radians([0, 0, 0, 0, 1.57, 0], 80)time.sleep(1.5) print("send angle to joint 4: -90\n")mycobot.send_angle(Angle.J4.value, -90, 80)time.sleep(1.5) # Operations to get coordinatesprint("get coordination")print(" coordination {}\n".format(mycobot.get_coords()))time.sleep(0.5) print("send coordination: [50, 50, 300, 0, 0, 0] → [50, 50, 300, 90, 90, 0]\n")coord_list = [50, 50, 300, 0, 0, 0]mycobot.send_coords(coord_lis, 70, 0)time.sleep(3.0)coord_list = [50, 50, 300, 90, 90, 0]mycobot.send_coords(coord_lis ,70, 0)time.sleep(1.5) # Scenarios using grippers# print("open gripper")# mycobot.set_gripper_state(0,0)# time.sleep(1.0)# print("close gripper")# mycobot.set_gripper_state(1,80)# time.sleep(1.0) time.sleep(1.5)print("release all servos")mycobot.release_all_servos()
бегатьmycobot_control_test.pyдокумент
$ python3 mycobot_control_test.py
Создайте экземпляр класса MyCobot в модуле mycobot и используйте геттеры и сеттеры для проверки и изменения состояния.
Создать экземпляр
mycobot = MyCobot(port, baudrate="115200", timeout=0.1, debug=False)
Установите четыре параметра. Введите значение по умолчанию после скорости передачи данных. порт USB последовательный порт связи。Вы можете пройтисуществоватьв терминалебегатьls / dev /Приходите и посмотритеподключиться список устройств к ПК. существует Linux, если нет другого USB-порта для последовательной связи, то это Воля. dev / ttyUSB0。Я думаюMacиWindowsотличается,Поэтому проверьте соответственно.
get_angles ( ) и get_radians () — функция, которая получает угол соединения в градусах и радианах. Возвращаемое значение представляет собой список из шести значений угла соединения.
Есть еще одинget_coords( )функция,Он получает нижний центр в качестве начала координат.координироватьсистема*кончик средней рукикоординировать。Возвращаемое значение представляет собой 6 Список размеров, содержащий наконечники x、y、z координировать (mm) и направление rx、ry、rz(угол)。существовать Нет MoveIt В этом случае действительно приятно реализовать инверсную кинематику.
*координироватьсистема:к“базовый”Панель задняя,Каждое положительное направление x: вперед, y: влево и з: Вверх. Обратите внимание, что MoveIt Векторы немного отличаются, о чем речь пойдет позже.
кстепеньи弧степеньдля单位发送закрывать节角изфункциядаsend_angles ( ) и send_radians ( ),И имеет два типа настройки параметров.
Сначала после указания и отправки всех 6 сустав, первый параметр такой же, как getter То же, поместите в список 6 Значение с плавающей запятой, второй параметр — скорость движения сустава. *(int: 0 ~ 100)。
mycobot .send_angles ( [ 0 , 0 , 0 , 0 , 0 , 0 ] , 80 )
Далее вы берете угол сустава и отправляете его. Пожалуйста, укажите код угла шарнира в первом параметре, значение угла во втором параметре и скорость в третьем параметре.
mycobot .send_angle ( Angle.J4.value , -90,80 )
Вы также можете получить действие, используя координацию, например геттер. существуют В данном случае помещаются 6 список элементов [x, y, z, rx, ry, rz],Первый параметр согласован,Второй параметр — скорость,Третий параметр — это режим. Есть два типа узоров,0: Угол и 1: Линейный
mycobot .send_coords ( [ [ 80 , 50 , 300 , 0 , 90 , 0 ] , 70 , 0 )
Поскольку единицы скорости не указаны подробно в исходном коде, я предполагаю, что вы измеряете их там, где это необходимо.
Как только роботизированная рука начнет двигаться,Двигатель Воля продолжает подавать крутящий момент, пытаясь сохранить текущее состояние.,Так что, если мы оставим все как есть,Двигатель перегружен. поэтому,Давайтесуществоватьдействовать После завершенияиспользоватьфункцияrelease_all_servos(y)Сбросьте крутящий момент двигателя。
Если робот-манипулятор продолжает работать,и вы приказываете ему выполнить другое действие,произойдет ошибка,После этого Воля переходит к следующему действию. существовать пример сценария,pythonвстроенныйфункцияtime.sleep()Используется для ожидания завершения каждого действия,Но ты можешькиспользоватьфункцияis_moving()Чтобы узнать, исправен ли двигательсуществоватьбегать,чтобы вы могли зацикливаться в то время как и т.д. (Я думаю, что эта функция неправильная,и возвращает постоянно движущееся состояние.
Есть и другие API Может использоваться для включения и выключения питания, изменения LED цвета, а также проверку состояния мотора, но на этот раз я их пропустил, поскольку цель — переместить руку.
Затем используйте MoveIt в ROS для управления myCobot.
слон роботвыполнитьmycobot action, его можно установить иМожетк Установить
Существует добровольная реализация MoveIt, и я решил ее использовать. Установка основана на вышеизложенном. GitHub Файл Readme написан.
$ cd /src$ git clone https://github.com/Tiryoh/mycobot_ros$ git clone https://github.com/nisshan-x/mycobot_moveit$ rosdep update$ rosdep install -i –from-paths mycobot_moveit$ cd .$ catkin_make #Set up work area$ source devel/setup.bash
После завершения установки и настройки рабочего пространства
$ roslaunch mycobot_moveit mycobot_moveit_control.launch
MoveIt и Rviz GUI начнется, как показано на рисунке 7 Рассчитайте положение конечного положения руки робота, перетащив зеленый шарик, затем нажмите кнопку плана и выполнения в левом нижнем углу, Rviz. Двигайтесь вместе с настоящим роботом.
* Когда модель и фактическая машина не работают вместе
Я не знаю, является ли это ошибкой, которая возникает во всех средах.,А модели и реальные машины не всегда работают вместе. Это ошибка, возникающая при изменении направления вращения двигателя на противоположное.,Так что это немного сложно,Но сравните, пожалуйста, модель Воли с реальной машиной.,Ищите вращение суставов в противоположных направлениях.
Убедившись, сколько суставов вращается в противоположных направлениях, перепишите файл URDF, описывающий модель робота.
/ src / mycobot_moveit / urdf / mycobot_urdf_gazebo.urdf
Описание определенной совместной информации выглядит следующим образом.
mycobot_urdf_gazebo.urdf ~~ <joint name="arm1_joint" type="revolute"> <parent link="body_link" /> <child link="arm1_link" /> <origin xyz="0 0 0.0706" rpy="0 0 0" /> <axis xyz="0 0 1" /> <limit effort="30" lower="-2.88" upper="2.88" velocity="1.5" /> </joint> ~~
Arm1 ~ arm6_joint Те же инструкции。Направление оси вращения установлено на<осьxyz = “0 0 1”> </ось>,А установка 1→-1 инвертирует вращение сустава в противоположную сторону.
В моем окружении кажется, что все суставы, кроме третьего, перевернуты. Я не знаю, связано ли это с индивидуальными различиями сервоприводов роботов или с другими причинами, если знаете, подскажите.
Вот и все, от настройки myCobot до основ работы.
На этот раз я тестировал его с D455.,Но в принципе серию D400 можно использовать точно так же. Только D435i и D455 имеют встроенные датчики IMU.,Но в этой статье не используется приезжать (поскольку недостатки накопления ошибок более очевидны, чем преимущества существующего использованияIMU в фиксированном состоянии). В дополнение к серии D400 с инфракрасным стереоскопическим,Еще есть L515 с LiDAR.,Но цель та же. кроме того,Я думаю, что новый работает лучше всего,Так что куплю Д455. Я думаю, что перед покупкой лучше проконсультироваться со средой, которую вы хотите использовать.,Потому что есть некоторые детали (предыдущие модели в основном обратно совместимы,Таким образом, существует компромисс между ценой и производительностью).
Установочная библиотека librealsense Чтобы запустить настоящий смысл. Без этого realsense_ros, о котором будет рассказано далее, работать не будет. Возникает вопрос о том, как Linux Документация по его установке. При необходимости Windows начальствоиз Установитьметод также находится там жедокументбиблиотека。
# Server Public Key Registration$ sudo apt-key adv –keyserver keyserver.ubuntu.com –recv-key F6E65AC044F831AC80A06380C8B3A55A6F3EFCDE|| Adding a Repository$ sudo add-apt-repository “deb https://librealsense.intel.com/Debian/apt- repo $(lsb_release -cs) main” -u# install lib$ sudo apt install librealsense2-dkms librealsense2- utils# install dev$ sudo apt install librealsense2-dev librealsense2-dbg
После завершения установки запустите RealSense Viewer в терминале, чтобы просмотреть его. Если это не помогло, попробуйте отключить и снова подключить USB-соединение RealSense и перезагрузить компьютер. Если запуск прошел успешно, программа просмотра отобразится, как показано на рисунке 8.
Вы можете использовать 2D | 3D кнопка в 2D и 3D Переключайтесь между зрителями. Кроме того, вы можете просмотреть информацию о глубине и информацию RGB, открыв стереомодуль и камеру RGB слева. существовать 2D , ты можешь 2D Посмотреть в RGB и информация о глубине. В существующем 3D облако точек, оцененное инфракрасной стереокамерой, оценивающей глубину, окрашено в соответствии с информацией о цвете глубины изображения и RGB-камерой и может просматриваться под всеми углами. Кроме того, встроенный IMU датчик D435i и D455 Информацию об отношении также можно получить с помощью модуля движения. Далее давайте рассмотрим использование ROS Пакет realsense_ros Rviz Облако точек. Это можно сделать с помощью apt Установить.
$ sudo apt install ros-$ROS_DISTRO-realsense2-camera
Камеры RealSense запускаются на первом терминале и помимо информации с каждой камеры предоставляется цветное облако точек, а на втором терминале запускается Rviz для визуализации.
$ roslaunch realsense2_camera rs_camera.launch filter:=pointcloud$rviz
Чтобы просмотреть облако точек, как показано на рисунке 9, мы будем использовать графический интерфейс для настройки параметров.
первый,потому чтолевая сторонапоказыватьв панелиГлобальные вариантыиз фиксированная рамаДакартина,Пожалуйста, нажмите на него и Воляэто изменилось наcamera_link。
Затем нажмите кнопку «Добавить» в нижней части панели дисплея, и появится новое окно со списком доступных Rviz показано в ROS Тип сообщения. выбирать rviz середина группы PointCloud2 и нажмите OK Воля PointCloud2 Добавить на панель отображения.
также,Если нажать в группе"тема”Столбец правыйизпустойи Выберите, чтобы появитьсяиз /camera/depth/color/points,Тогда облако точек Воляпоказыватьсуществовать Rviz начальство. По умолчанию размер облака точек установлен на 0.01 м, что является большим значением, поэтому облака точек перекрывают друг друга, но если Воля установлено значение 0.001 m Справа и слева вы можете видеть, что облако точек получено очень четко.
также,Если от "Добавить" выберите "TF" и добавьте его,则Можеткпоказыватьположение камерыи направление(ось К)。По умолчанию,RGB происхождение камерыитрехмерныйпроисхождение камерысоответственнопоказыватьсуществоватьмиркоординироватьсистемаи Оптикакоординироватьсистемасередина。(camera_linkПохоже, имеет то же происхождение, что и стереокамеры.)
Сохраните настройки, так как будет сложно каждый раз выскакивать эту кнопку.
Создайте конфигурацию каталога в рабочей области для сохранения настроек в Rviz издокументсередина选择Воля Конфигурация Другойсохранить как,Создать имяизКонфигурациякаталог и сохраните。
$ rviz -d .rviz
Если вы что-то измените,则Можетк每次通过保存КонфигурацияОбновите то же самоеиздокумент.Если вы просто смотрите на облако точекиположение камеры,Вы можете легко это сделать с помощью Realsense_viewer.,Но ты можешькиспользовать ROS для обработки необработанных данных. С этого момента это похоже на понимание ROS Упражнение на значение данных сообщения.
(Но лично для меня это большой камень преткновения)
осуществлятьrs_camera.launch после фильтра:=облако точек。
давайте посмотрим Отправлено с другого терминала /camera/depth/color/points Исходные данные субъекта.
$ rostopic echo /camera/depth/color/points
Конечно, этот массив значений представляет собой данные облака точек,его следует использовать xyz координироватьи Расположениесерединаиз RGB Представление значения, но его трудно прочитать напрямую. Если вы посмотрите на цифры, вы увидите, что каждое значение находится в 0 приезжать 255 диапазон, и подобные значения встречаются регулярно и по регулярной схеме. Но угадайте отсюда x Неразумно представлять, где и где представляет красный цвет.
Итак, сначала выясните, что это за тип сообщения.
$ rostopic type /camera/depth/color/pointssensor_msgs/PointCloud2
Теперь мы знаем, что тип сообщения sensor_msgs/PointCloud2。
Кроме того, если вы начинаете с ROS документ Посмотреть вэто,您Можетксмотретьприезжать Следующее содержание。
Header header # header uint32 height # number of rows of datauint32 width # Number of columns of dataPointField[] fields # 1 point data structurebool is_bigendian # whether the big enduint32 point_step # number of bytes in a point (number of 8-bit numbers)uint32 row_step # number of data in a row (= width * point_step)uint8[] data # raw data (8bit row_step * height data array)bool is_dense # if true, then no invalid data
Так как это облако точек,Поэтому оно отличается от 2D-изображения.,Что означает порядок данных? Как следует из вопроса,Высота и ширина, кажется, не имеют смысла.
Непонятно, что значит хранить переменную, которую можно вычислить из других значений и вряд ли использовать, но структура такая. Если вы хотите увидеть фактическую ценность каждого из них,
$ rostopic echo /camera/depth/color/points/<Variable Name>
Сделав это, активируйте,В данных можно вывести только одну переменную. Например,показыватьразpoint_stepиполе дает。
$ rostopic echo /camera/depth/color/points/point_step–20—$ rostopic echo /camera/depth/color/points/fields–name: “x”offset: 0datatype: 7count: 1–name: “y”offset: 4datatype: 7count: 1–name: “z”offset: 8datatype: 7count: 1–name: “rgb”offset: 16datatype: 7count: 1—
Выход Воля потому что point_step = 20, вы можете увидеть данные о прибытии в одну точку, 20 байтовое представление, вы можете увидеть содержимое поля от в этом 20 Как составляются байты.
Значение каждой переменной
имя:выражатьизданныеизимя
Компенсировать:переписыватьсяизбайт
Тип данных:представленныйданныеизкод типа
считать:Включатьизданные Количество предметов
Например,х координироватьсоответствуетот 0 приезжать 3 Данные, код типа 7 (соответствует float32), представляет данные. y и z следует обращаться таким же образом, но RGB Тоже выражается таким же образом. Когда я просматриваю RGB Соответствующий 16 приезжать 19 ценность, есть GBRA Последовательное шестнадцатеричное значение. приезжать float32 Преобразование xyz координироватьи RGB。
Теперь, когда мы знаем, как представлять данные, давайте поработаем с ними.
(Я думаю, что есть более разумный и быстрый способ обработать следующий скрипт, поэтому, если у вас есть какие-либо предложения, пожалуйста)
В каталог скриптов «Воля» добавлен пакет mycobot_test, и туда добавлен скрипт Python.
$ cd /src/mycobot_test$ mkdir scripts$ cd scripts$ touch red_point_detection.py$ touch object_position_search.py
Воля Добавлены зависимостиприезжать CMakeLists.txt и упакуйте .xml.
# CMakeLists.txtfind_package(catkin REQUIRED COMPONENTS # Add rospy and sensor_msgs modules to be able to import rospy sensor_msgs ) catkin_package( # Add build package sensor_msgs ) # Add scripts to the executable directory catkin_install_python(PROGRAMS DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}/scripts )Python<!-- package.xml --><!-- add --> <build>rospy</build> <build>sensor_msgs</build> <!-- package.xml --><!-- add --> <build>rospy</build> <build>sensor_msgs</build>
к Внизred_point_detection.pyэто сценарий,Он только извлекает красный цвет из облака точек и создает новое сообщение.
#!/usr/bin/env python3 import time, os, sys, signal, threading import numpy as np import rospy from sensor_msgs.msg import PointCloud2 class RedPointsDetectionNode(object): def __init__(self): super(RedPointsDetectionNode, self).__init__() self.data = PointCloud2() self.point_step = 20 self.R_COL = 18 self.G_COL = 17 self.B_COL = 16 rospy.init_node("red_points_detection_node") rospy.loginfo("red points detection start") # Subscriber def sub_pointcloud(self): def callback(data): self.sub_data = data sub = rospy.Subscriber("camera/depth/color/points", PointCloud2, callback = callback) rospy.spin() # Publisher def pub_red_pointcloud(self): pub = rospy.Publisher("red_point_cloud", PointCloud2, queue_size = 1) while not rospy.is_shutdown(): pub_data = self.red_point_detection(self.sub_data) pub.publish(pub_data) def red_point_detection(sub_data): red_point_data = sub_data red_pointcloud = np.array([d for d in sub_data.data]).reshape(-1, self.point_step) r_flags = red_pointcloud < 180 g_flags = red_pointcloud > 150 b_flags = red_pointcloud > 150 R_under_threshold_row = np.where(r_flags)[0][np.where(np.where(r_flags)[1]==self.R_COL)] G_over_threshold_row = np.where(g_flags)[0][np.where(np.where(g_flags)[1]==self.G_COL)] B_over_threshold_row = np.where(b_flags)[0][np.where(np.where(b_flags)[1]==self.B_COL)] not_red_row = np.unique(np.concatenate([R_under_threshold_row, G_over_threshold_row, B_over_threshold_row])) red_pointcloud = np.delete(red_pointcloud, not_red_row, axis=0).ravel().tolist() red_point_data.width = int(len(red_pointcloud) / self.point_step) red_point_data.height = 1 red_point_data.row_step = pub_pc2_data.width * self.point_step red_point_data.data = red_pointcloud rospy.loginfo("red pointcloud {}".format(int(len(red_pointcloud) / self.point_step))) return red_point_data # node start to subscribe and publish def start_node(self): sub_pointcloud = threading.Thread(target = self.sub_pointcloud) pub_red_pointcloud = threading.Thread(target = self.pub_red_pointcloud) sub_pointcloud.setDaemon(True) sub_pointcloud.start() pub_red_pointcloud.setDaemon(True) pub_red_pointcloud.start() sub_pointcloud.join() pub_red_pointcloud.join() if __name__ == "__main__": color_points_detector = ColorPointsDetectionNode() color_points_detector.start_node() pass
Подписчик читаеткамера/глубина/цвет/данные точки,Только издательотданныесередина提取красная точкаираспределениеэтоих。иметь дело скрасная точкакот原始точка云середина删除 RGB ценитьдляf R < 180、G > 150 и B > 150 източка。использоватьHSVСравниватьRGBлучше,На RGB легко влияют условия освещения,Но на этот разсуществоватьиметь дело сPointCloud2данные сложные Преобразовать вHSV, поэтому был отложен. Если это C++, используйте PCL кажется легко сделать python преобразование, но для python Это бесполезно, потому что другие процедуры писать сложно).
После написания,Мобильное рабочее место Volyaits,catkin_make и выполните его.
$ roslaunch realsense2_camera rs_camera.launch filters:=pointcloud$ rosrun mycobot_test red_point_detection.py$ rviz -d .rviz
если в Rviz Выберите Добавить место проживания. PointCloud2 в сообщении /red_point_cloud,Вы можете увидеть облако точек, полученное с помощью приезжать.,нравитьсякартина 10 показано.
object_position_search.pyэто сценарий,Используется для нахождения среднего значения извлеченных координированных красных точек.
# object_position_search.py#!/usr/bin/env python3 import time, os, sys, signal, threading import numpy as np import rospy from sensor_msgs.msg import PointCloud2 import sensor_msgs.point_cloud2 as pc2 from geometry_msgs.msg import Point class ObjectPositionSearchNode(object): def __init__(self): super(ObjectPositionSearchNode, self).__init__() rospy.init_node("object_position_search_node") rospy.loginfo("object position search start") self.object_position = Point() # Subscriber def sub_pointcloud(self): def callback(data): rospy.loginfo("subscribed pointcloud") xyz_generator = pc2.read_points(data, field_names = ("x", "y", "z"), skip_nans=True) xyz_list = [gen for gen in xyz_generator] list_num = len(xyz_list) x = np.array([xyz_list[i][0] for i in range(list_num) if (xyz_list[i][2] < 1.0 and xyz_list[i][2] > -1.0)]) y = np.array([xyz_list[i][1] for i in range(list_num) if (xyz_list[i][2] < 1.0 and xyz_list[i][2] > -1.0)]) z = np.array([xyz_list[i][2] for i in range(list_num) if (xyz_list[i][2] < 1.0 and xyz_list[i][2] > -1.0)]) self.object_position.x = np.average(x) self.object_position.y = np.average(y) self.object_position.z = np.average(z) sub = rospy.Subscriber("red_point_cloud", PointCloud2, callback = callback) rospy.spin() # Publisher def pub_target_position(self): pub = rospy.Publisher("object_position", Point, queue_size=1) while not rospy.is_shutdown(): rospy.loginfo("published object position: {:.5f}, {:.5f}, {:.5f}\n".format(self.object_position.x, self.object_position.y, self.object_position.z)) pub.publish(self.object_position) def start_node(self): sub_pointcloud = threading.Thread(target = self.sub_pointcloud) pub_target_position = threading.Thread(target = self.pub_target_position) sub_pointcloud.setDaemon(True) sub_pointcloud.start() pub_target_position.setDaemon(True) pub_target_position.start() sub_pointcloud.join() pub_target_position.join() if __name__ == "__main__": object_position_searcher = ObjectPositionSearchNode() object_position_searcher.start_node() pass
существовать Добегатьred_point_search.pyиз情况Вниз,Запустите новый терминал и запустите его.
$ rosrun mycobot_test object_position_search.py
Он принимает среднее значение red_point_cloudкоординировать. и распределяйте их, записывая значения. координировать в метрах, этот скрипт получает 1.0 точки в пределах метров. потому что чтоиспользовать rospy.loginfo Полученная координация протоколируется, поэтому координация выводится на терминал прибытия.
sensor_msgsбиблиотекаесть одинpoint_cloud2модуль,используется дляиметь дело сичитать PointCloud2 данные,Волякоординироватьценитьот 4Byte Преобразовать в float32。Содержание очень простое,Но мне сложно понять хранение этого модуля. Если у вас есть другие сложные данные сообщения,Лучше всего проверить, есть ли в комплекте модуль обработки. Это действительно настройка и обработка данных. Об обработке данных,Я думаю, вам все еще нужно найти метод более быстрой обработки (или улучшенного алгоритма).,Зависит от приложения.
В настоящее время обработка реально-сенсорных данных завершена.,Я хочу объединить его с myCobot. поэтому,самое важноеиздаот Камера RealSenseкоординироватьсистемаприезжатьmyCobotкоординироватьсистемаиз Конвертировать。Rviz Есть один на TF (Transform) показывает ось камеры, но это нужно знать. Как следует из названия, оно описывает координационное преобразование, которое описывает отношения между одной координационной линией и другой координационной линией. Сначала посмотрим, не установлено ли это TF Что происходит.
$ roslaunch realsense2_camera rs_camera.launch filter:=pointcloud$ roslaunch mycobot_moveit mycobot_moveit_control.launch
Тогда ты Волясуществовать Rviz См. предупреждение на панели отображения, например, изображение. 11 показано.消息да相机изкаждыйкоординироватьсистема Все Неттрансформироватьприезжатьbase_link(myCobotизисточник)。
поэтому,Давайте создадим пакет,Воля TF (координировать преобразование)от трансляции камеры прибытия myCobot。ужасно жальсуществоватьC++иPythonмеждураз,но на этот раз я Воляиспользоватьroscpp。первый Создать пакет。
$ cd <your_ros_ws_for_MyCobot>/src$ catkin_create_pkg tf_broadcaster roscpp$ cd tf_broadcaster$ touch src/tf_broadcaster.cpp
переписатьгенерироватьизtf_broadcaster.cpp CMakeLists.txt、package.xmlнравиться Внизпоказано.пожалуйста, обрати внимание,Файл C++ — это класс,Потому что он создан для практики создания узлов в существующем классе,Но можно написать проще.
// tf_broadcaster.cpp#include <ros/ros.h> #include <geometry_msgs/TransformStamped.h> #include <tf2_ros/static_transform_broadcaster.h> #include <tf2_geometry_msgs/tf2_geometry_msgs.h> class TfBroadcaster { public: TfBroadcaster(); ~TfBroadcaster(); // Broadcast void BroadcastStaticTfFromCameraToMyCobot(); private: ros::NodeHandle nh_; // TF Broadcaster tf2_ros::StaticTransformBroadcaster static_tf_broadcaster_; // constant double PI_ = 3.1419265; }; TfBroadcaster::TfBroadcaster(){} TfBroadcaster::~TfBroadcaster(){} void TfMyCobotBroadcaster::BroadcastStaticTfFromCameraToMyCobot() { geometry_msgs::TransformStamped transformStamped; transformStamped.header.stamp = ros::Time::now(); transformStamped.header.frame_id = "camera_color_frame"; //link transformStamped.child_frame_id = "base_link"; // son link // Parallel movement transformStamped.transform.translation.x = -0.3; transformStamped.transform.translation.y = -0.3; transformStamped.transform.translation.z = -0.3; // Turning back tf2::Quaternion q; q.setEuler(0, 0, 0); transformStamped.transform.rotation.x = q.x(); transformStamped.transform.rotation.y = q.y(); transformStamped.transform.rotation.z = q.z(); transformStamped.transform.rotation.w = q.w(); static_tf_broadcaster_.sendTransform(transformStamped); } int main(int argc, char** argv) { ros::init(argc, argv, "tf_mycobot_broadcaster"); TfMyCobotBroadcaster tf_mycobot_broadcaster; tf_mycobot_broadcaster.BroadcastStaticTfFromCameraToMyCobot(); ros::Rate loop_rate(10); while(ros::ok()){ ros::spinOnce(); loop_rate.sleep(); } return 0; }# CMakeLists.txtcmake_minimum_required(VERSION 3.0.2) project(tf_broadcaster) find_package(catkin REQUIRED COMPONENTS roscpp geometry_msgs tf2_geometry_msgs) catkin_package( CATKIN_DEPENDS geometry_msgs tf2_geometry_msgs) include_directories(${catkin_INCLUDE_DIRS}) add_executable(tf_mycobot_broadcaster src/tf_mycobot_broadcaster.cpp) target_link_libraries(tf_mycobot_broadcaster ${catkin_LIBRARIES})<!-- package.xml --><?xml version="1.0"?> <package format="2"> <name>tf_broadcaster</name> <version>0.0.0</version> <description>The transform broadcaster package</description> <maintainer email="root@todo.todo">root</maintainer> <license>TODO</license> <buildtool_depend>catkin</buildtool_depend> <depend>tf2_geometry_msgs</depend> <depend>geometry_msgs</depend> </package>
Как видите, мы установили transformStamped Переменные экземпляра класса и трансляция этого экземпляра. Тип широковещательной переменной — tf2_ros::StaticTransformBroadcaster, но на этот раз мы используем статический TF, поскольку положение иробота камеры фиксировано. Для тех, кто заинтересован, также можно использовать динамику, когда отношения позиций меняются со временем. TF。
существоватьздесь,Отношения между локациями пока неизвестны.,Так что ценность временная,Но мы можем сформировать шоу,Итак, давайте попробуем. также,родительская ссылкаcamera_color_frameвместоcamera_link,因дляродительская ссылкаиз原точка与точка云координироватьсистемасоответствовать。 catkin_makeназад,картинак То же, что и раньшебегать rs_camera.launch и mycobot_moveit_control.launch,исуществовать Другойодин Запустить в терминалеtf_broadcaster。
$ rosrun tf_broadcaster tf_broadcaster
Это вещательный имидж-сканер Воля и myCobot base_linkмеждуиз Расположениезакрыватьсистема,поэтомуTFпредупреждение исчезает。если в этом состоянии добавляется облако точек, похожее на картину 12 Конечно, позиционная взаимосвязь между камерой и myCobot является временной, поэтому камера видит положение myCobot в пункте прибытия и Рвизпоказано. в Позиции моделей не пересекаются.
поэтому,Следующийнас Волякалибровкаотсмотреть в камеруприезжатьизроботизотносительная позаи Расположение。
Я думаю, что есть другой способ указать метод позиционных отношений, зафиксировав существующую конкретную позицию с помощью камеры Воля.,Но на этот раз мы отметим три пункта, чтобы определить роботокоординировать,Мы калибруем позиционное соотношение, находя единичный вектор прибытия и вычисляя его относительно кадра камеры.
Некоторые из вас, возможно, заметили приезжать,Предыдущее фото было сделано, когда существование уже было подключено отметка,Но отметка размещена так, как показано на картинке 13.
продовольственная отметка
myCobot Начало координат (внизу в центре) находится на отметке 2 и 3 середина, отметка 1 Отрезок, перпендикулярный началу координат 2 и 3。
1.первый,переписатьred_point_detection.pyисоздаватьblue_point_detection.pyкпосинетьотметкаизточка云。Сценарий здесь опущен,因дляэто只дапереписать Быть извлеченнымиз RGB объем. После этого я подумал, что есть несколько способов получить координированное преобразование, но на этот раз оно было получено с помощью следующего процесса. ОК отметка координировать Подписаться на облако тегированных точек
один. Облако точек Воли, сгруппированное в три (средним методом k)
2. Определите начало координат и единичный вектор отметка 2 и 3 Средняя точка — это начало координат V_robot.
один. Х и Y Орты V_XиV_Y соответственно V_robot →отметка 1、V_robot →отметка 2。
б. Единичный вектор Z — это векторное произведение плоскости и вектора нормали с отметкой.
3. использовать углы Эйлера создать позу камеры приезжатьповорот робота позы theta_1 = Угол возвышения камеры относительно горизонтальной плоскости
a.theta_2 = угол поворота к передней части камеры
b.theta_3 = Угол между камерой и направлением перед роботом
4. Воля V-Z Зарождение направления Преобразовать в myCobot фиксированная база (2,7 сантиметр)
* Ось, от которой начинается вращение Эйлера, произвольна, поэтому результаты будут различаться в зависимости от рассматриваемой библиотеки. (Думаю, не все удосуживаются это сделать, поэтому мне было интересно, передадите ли вы единичный вектор и начало координат двух координационных систем и есть ли какая-нибудь библиотека Воля, Преобразовать которую в TF。
Следующий скрипт Воля добавлен в каталог скриптов приезжать.
/*
* Совет: Эта строка кода слишком длинная, и система автоматически комментирует ее, не выделяя. Один клик копировать удалит системные комментарии
* # mycobot_position_calibration.py#!/usr/bin/env python3 import time, os, sys, signal, threading import numpy as np import rospy from sensor_msgs.msg import PointCloud2 from geometry_msgs.msg import Point import sensor_msgs.point_cloud2 as pc2 class MyCobotPositionCalibrationNode(object): def __init__(self): super(MyCobotPositionCalibrationNode, self).__init__() rospy.init_node("mycobot_position_calibration_node") rospy.loginfo("mycobot position calibration start") # Subscriber def sub_pointcloud(self): def callback(data): self.data = data rospy.loginfo("subscribed pointcloud") xyz_generator = pc2.read_points(self.data, field_names = ("x", "y", "z"), skip_nans=True) xyz_list = [xyz for xyz in xyz_generator if (abs(xyz[0]) < 0.8 and abs(xyz[1]) < 0.8 and abs(xyz[2]) < 0.8)] xyz_array = np.array(xyz_list) if len(xyz_list) > 3: marker_centroids = self.kmeans(3, xyz_array) rospy.loginfo("\n marker positions\n{}".format(marker_centroids)) translation = self.cal_translation(marker_centroids) rospy.loginfo("\n translation\n{}".format(translation)) sub = rospy.Subscriber("blue_point_cloud", PointCloud2, callback = callback) rospy.spin() # node start def start_node(self): sub_pointcloud = threading.Thread(target = self.sub_pointcloud) sub_pointcloud.setDaemon(True) sub_pointcloud.start() sub_pointcloud.join() # clustering method def kmeans(self, k, X, max_iter=30): # k: cluster num, X: numpy array data_size, n_features = X.shape centroids = X[np.random.choice(data_size, k)] new_centroids = np.zeros((k, n_features)) cluster = np.zeros(data_size) for epoch in range(max_iter): for i in range(data_size): distances = np.sum((centroids - X[i]) ** 2, axis=1) cluster[i] = np.argsort(distances)[0] for j in range(k): new_centroids[j] = X[cluster==j].mean(axis=0) if np.sum(new_centroids == centroids) == k: break centroids = new_centroids max_norm = 0 min_norm = 0 sorted_centroids = [] for centroid in centroids: norm = centroid[2] if norm > max_norm: sorted_centroids.append(centroid) max_norm = norm if min_norm == 0: min_norm = sorted_centroids[0][2] else: if norm > min_norm and min_norm != 0: sorted_centroids.insert(1, centroid) else: sorted_centroids.insert(0, centroid) min_norm = norm sorted_centroids = np.array(sorted_centroids) return sorted_centroids # translation angles calculation ## calculation def cal_translation(self, marker_points): # マーカー1, 2, 3-позиционный вектор #Position vector of marker 1, 2, 3 a_1, a_2, a_3 = marker_points # カメラからロボットへのベクトル #Vector from camera to robot V_robot = self.cal_robot_position_vector(a_2, a_3) # Единичный вектор робота XYZ #XYZ unit vector of the robot V_X = (a_2 - V_robot) / (np.linalg.norm(a_2 - V_robot)) V_Y = (a_1 - V_robot) / (np.linalg.norm(a_1 - V_robot)) V_Z = self.cal_normal_vector(marker_points) # Угол подъема камеры относительно горизонтальной плоскости # Elevation angle of the camera relative to the horizontal plane theta_1 = - (np.pi/2 - self.cal_subtended_angle(-V_robot, V_Z)) # Угол поворота камеры вперед #Rotation angle of the camera in the frontal direction V_Y_camera = np.array([0, 1, 0]) V_Y_camera_rotated = self.cal_rotate_vector_xaxis(V_Y_camera, -theta_1) theta_2 = - self.cal_subtended_angle(V_Z, -V_Y_camera_rotated) # Угол между камерой и направлением движения робота вперед #Angle between the camera and the respective frontal direction of the robot _, V_robot_projected_to_plane = self.cal_vector_projection(V_robot, V_Z) theta_3 = self.cal_subtended_angle(V_Y, V_robot_projected_to_plane) # положение микобота до базовой высоты 0,027 m, Перевод в направлении В_З # mycobot position at foundation height 0.027 m, parallel to V_Z direction V_robot = V_robot + 0.027*V_Z return V_robot, theta_1, theta_2, theta_3 ## vector and angle caluculation def cal_robot_position_vector(self, a_2, a_3): return (a_2 + a_3) / 2 def cal_normal_vector(self, marker_points): a_1 = marker_points[0] a_2 = marker_points[1] a_3 = marker_points[2] A_12 = a_2 - a_1 A_13 = a_3 - a_1 cross = np.cross(A_13, A_12) return cross / np.linalg.norm(cross) def cal_subtended_angle(self, vec_1, vec_2): dot = np.dot(vec_1, vec_2) norm_1 = np.linalg.norm(vec_1) norm_2 = np.linalg.norm(vec_2) return np.arccos( dot / (norm_1 * norm_2) ) def cal_vector_projection(self, org_vec, normal_vec): # org_vec: вектор, который вы хотите проецировать # org_vec: the vector you want to project # normal_vec: Нормальный вектор плоскости, которую вы хотите проецировать. # normal_vec: Normal vector of the plane to be projected projected_to_vertical = np.dot(org_vec, normal_vec) * normal_vec projected_to_horizontal = org_vec + projected_to_vertical return projected_to_vertical, projected_to_horizontal def cal_rotate_vector_xaxis(self, vec, angle): rotate_mat = np.array([[1, 0, 0], [0, np.cos(angle), np.sin(angle)], [0, -np.sin(angle), np.cos(angle)]]) return vec.dot(rotate_mat) def cal_rotate_vector_yaxis(self, vec, angle): rotate_mat = np.array([[np.cos(angle), 0, -np.sin(angle)], [0, 1, 0], [np.sin(angle), 0, np.cos(angle)]]) return vec.dot(rotate_mat) def cal_rotate_vector_zaxis(self, vec, angle): rotate_mat = np.array([[np.cos(angle), np.sin(angle), 0], [-np.sin(angle), np.cos(angle), 0], [0, 0, 1]]) return vec.dot(rotate_mat) if __name__ == "__main__": mycobot_position_calibrator = MyCobotPositionCalibrationNode() mycobot_position_calibrator.start_node() pass
*/
на этот разнасотнедавноизmarker_1Настроить камеруиробот,в соответствии сэтоихиз Расположениезакрыватьсистемаmarker_2иmarker_3,Но следует отметить, что,Необходимо отрегулировать в зависимости от положения камеры.
После завершения строительства в трех терминалах запускаются камера и узлы цветового поиска и калибровки «Волясуществовать» соответственно.
$ roslaunch realsense2_camera rs_camera.launch filter:=pointcloud$ rosrun mycobot_test blue_point_detection.py$ rosrun mycobot_test mycobot_position_calibration.py
Это рекордное перевоплощение Воля t_x, y, z (m) и угол Эйлера theta_1, 2, 3 (радиан) приезжать mycobot_position_calibration.py Терминал. Эти ценности потомому чтоточка云данныесобиратьи Колебания из-за кластеризации,Поэтому значения усредняются несколько раз. (существовать в этой настройке,Параллельный переводи угол Эйлера колеблются ок. 1%)
После получения значения перезапишите временное значение в tf_broadcaster.cpp.
// tf_broadcaster.cpp~~ # それぞれ t_x,y,z と theta_1,_2,_3 поместите полученное значение в # Put the obtained values in t_x,y,z and theta_1,_2,_3 respectively transformStamped.transform.translation.x = t_z; transformStamped.transform.translation.y = -t_x; transformStamped.transform.translation.z = -t_y; tf2::Quaternion q; q.setEuler(theta_1, theta_2, theta_3); ~~
Ясуществоватьнаходясь в поискеотcamera_color_frameприезжатьbase_linkизTF,Группировка точек обнаружения координирует систему camera_length_optical_frame,вычислитьназадxyzРазные направления(я Нет Уведомлениеприезжатьразница,Я запутался) Итак x = t_z,y = - t_x,z = - t_y。
После переписывания и catkin_make запустите узел.
$ roslaunch realsense2_camera rs_camera.launch filter:=pointcloud$ roslaunch mycobot_moveit mycobot_moveit_control.launch$ rosrun tf_broadcaster tf_broadcaster
Затемотражение Камераироботиз Расположениезакрыватьсистема,роботиRviz Модель робота, показанная на облаке точек, может быть наложена,нравитьсякартина14показано.
картина 14: Значения, полученные при калибровке Воляот, установлены на TF итранслироватьэтои Несовершенный,Но мне удалось удержать отклонение в допустимых пределах.,Чтобы легко доставать и брать предметы.
Вы можете увидеть это при перемещении облака точек и наложенной модели робота.
Суставы myCobot имеют небольшой люфт, что затрудняет точные движения.
потому Облако точек, полученное с помощью чтоот, получено с помощью Преобразовать Система координации вmyCobot, поэтому мы пытаемся позиционировать кончик ВоляmyCobot как объект. (Я пытался картинуиспользовать MoveIt чтобы получить к нему доступ, но он застрял в C++, поэтому я сделал тот, который работает, используя pymycobot Удобный скрипт)
потому то, что координирует, находится в оптической системе камеры, поэтому переведите и поверните их, полученные ранее вmyCobotкоординировать отдел. Воля В каталог сценариев приезжать добавлен следующий контент.
# mycobot_reaching.py#!/usr/bin/env python3 import time, os, sys import numpy as np import quaternion from pymycobot.mycobot import MyCobot import rospy from geometry_msgs.msg import Point from tf.transformations import quaternion_from_euler class MyCobotReachingNode(object): def __init__(self): super(MyCobotReachingNode, self).__init__() rospy.init_node("mycobot_reaching_node") rospy.loginfo("mycobot reaching start") # переменная-член # mycobot インスタンス # member variable # mycobot instance port = "/dev/ttyUSB0" self.mycobot = MyCobot(port, baudrate="115200", timeout=0.1, debug=False) # Перевод и вращение # Обратите внимание, что оси XYZ отличаются от раздела 4.2, поскольку оптическая система координат → система координат микобото. # Translation and rotation # Note that the XYZ axes are different from those in section 4.2 because the optical coordinate system is a mycoboto coordinate system self.translation_from_camera_to_mycobot = np.array([t_x, t_y, t_z]) q = quaternion_from_euler(-theta_2, -theta_3, theta_1) self.rotation_from_camera_to_mycobot = quaternion.as_quat_array(q) # subscriber self.sub_point() # Subscriber def sub_point(self): def callback(data): rospy.loginfo("subscribed target point") self.mycobot_move(data) sub = rospy.Subscriber("object_position", Point, callback = callback) rospy.spin() # move mycobot def mycobot_move(self, point_data): # Преобразование в систему координат mycobot # Convert to mycobot coordinate system target_point = np.array([point_data.x, point_data.y, point_data.z]) target_point -= self.translation_from_camera_to_mycobot target_point = quaternion.rotate_vectors(self.rotation_from_camera_to_mycobot, target_point) # *1000 для миллиметровых блоков, x-20 мм для достижения ближе к центру передней части, z+40mm # *1000 for mm increments, x-20mm, z+40mm for reaching around the center of the front coord_list = [target_point[0]*1000-20, -target_point[2]*1000, target_point[1]*1000+40, 0, 90, 0] self.mycobot.send_coords(coord_list, 70, 0) time.sleep(1.5) if __name__ == "__main__": reaching = MyCobotReachingNode() pass
На этот раз я, Воля, мобилизовал все библиотеки, которые использую, и сделал Скрипт.
Ты можешь 6 Запустить в терминале rs_camera.launch、mycobot_moveit_control.launch、tf_broadcaster、red_point_detection.py、object_position_search.py、mycobot_reaching.py,Но каждый раз, когда я открываю терминал,Вам всем придется его настроить... отладка будет затруднена.,поэтому请создавать自己иззапускатьдокумент.
Трансфер на рабочее место,Создать каталог и файлы для запуска,И добавьте CMakeLists.txt в путь запуска.
$ cd <your_ros_ws_for_MyCobot>/src/mycobot_test$ mkdir launch$ cd launch$ touch mycobot_reaching.launch<!-- mycobot_reaching.launch --><launch> <include file="$(find mycobot_moveit)/launch/mycobot_moveit_control.launch" /> <include file="$(find realsense2_camera)/launch/rs_camera.launch"> <arg name="filters" value="pointcloud"/> </include> <node name="tf_broadcaster" pkg="tf_broadcaster" type="tf_broadcaster" /> <node name="color_points_detectior" pkg="mycobot_test" type="red_points_detection.py" output="screen" /> <node name="object_position_searcher" pkg="mycobot_test" type="object_position_search.py" output="screen" /> <node name="mycobot_reaching_node" pkg="mycobot_test" type="mycobot_reaching.py" /> </launch># CMakeLists.txt~~# Add launch fileinstall(FILES DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch ) ~~
Структура стартового файла очень проста.,Просто расположите файлы запуска узлов, которые вы хотите запускать одновременно, и файлы запуска на вкладке запуска. Узел для выполнения,Пожалуйста, напишите любое имя узла в отметке существования узла.,И напишите имя пакета и имя исполняемого файла, как это делает rosrun. добавить вывод = "экран",Если вы хотите, чтобы вывод отображался в командной строке.
существующий загрузочный файл выполняется при запуске существования, содержит отметку, содержит путь к файлу. Попробуйте catkin_make и запустите его.
$ roslaunch mycobot_test mycobot_reaching.launch
Я могу перемещать своего Кобота, чтобы отслеживать красный объект, захваченный RealSense, как в первом фильме.
До реализации проекта было много задержек, и я всегда чувствовал, что недостаточно учился во всех аспектах.
В этой статье я расскажу, как использовать ROS координировать 6 осевой манипулятор myCobot Глубина камеры Реальный смысл Д455. У меня нет опыта разработки роботов, в том числе ROS. Я не думаю, что есть блог Подвести итог Понял меняприезжатьдо сих порот Начните пробоватьизсодержание,Итак, если вы купили роботизированную руку или камеру глубины, но не знаете, как ею пользоваться,Надеюсь, это поможет тем, кто задается вопросом, как его использовать. кроме того,Если бы кто-то, имеющий опыт разработки роботов или хорошо разбирающийся в обработке данных, мог бы указать, как лучше всего сделать что-то подобное.,Я Воля был бы очень благодарен.
На этот раз я Воля Я существовал в симуляторе, чтобы применить модель обучения с подкреплением для передвижения к myCobot.,и провел эксперимент по сбору,Так что я могу написать еще один блог как часть 2.
ссылка
1. Сунлин Дажи, 2022.12.21, Управляйте myCobot, используя пространственное распознавание с помощью Practice D455. https://blog.albert2005.co.jp/2022/12/21/realsense-d455_mycobot/
2. Альберт Ко. https://www.albert2005.co.jp/english/