Image

Руководство для начинающих по робототехнике на Python

Создавайте 3D-симуляции с помощью PyBullet

Делиться

aa04f3044c21c912d4db92b7082e0630

Вступление

Роботы — это машины, способные выполнять задачи и принимать решения, копируя или заменяя действия человека. Робототехника — это научная область, занимающаяся проектированием и созданием роботов. Она представляет собой междисциплинарное сочетание:

  • Электротехника для датчиков и исполнительных механизмов. Датчики собирают данные из окружающей среды, преобразуя физические свойства в электрические сигналы (как наши пять чувств). Исполнительные механизмы преобразуют эти сигналы в физические действия или движения (например, наши мышцы).
  • Машиностроение для проектирования и движения физической конструкции.
  • Информатика для программного обеспечения и алгоритмов искусственного интеллекта.

В настоящее время ROS (операционная система для роботов) — это основной фреймворк для робототехники, который управляет всеми различными компонентами робота (датчиками, двигателями, контроллерами, камерами и т. д.), где все компоненты обмениваются данными по модульному принципу. Фреймворк ROS предназначен для реальных прототипов роботов и может использоваться как с Python, так и с C++. Учитывая его популярность, существует множество библиотек, созданных на основе ROS, например, Gazebo — самый продвинутый 3D-симулятор.

beff7955f5f8606e89c1fceba22e4733

Несмотря на сложность Gazebo, основы робототехники и удобные симуляции можно изучить и вне экосистемы ROS . Основные библиотеки Python:

  • PyBullet (для начинающих) — отлично подходит для экспериментов с URDF (Unified Robot Description Format), представляющим собой XML-схему для описания корпусов, частей и геометрии робота.
  • Веботы (средний) — физика более точная, поэтому можно строить более сложные симуляции.
  • MuJoCo (продвинутый) — симулятор реального мира, используется для исследовательских экспериментов. Библиотека RoboGYM от OpenAI построена на основе MuJoCo.
ce2c711276d27de6b16b3994426ff59a

Поскольку это руководство для начинающих, я покажу, как создавать простые 3D-модели с помощью PyBullet . Я покажу несколько полезных фрагментов кода на Python, которые можно легко применить в других подобных случаях (просто скопируйте, вставьте и запустите), и прокомментирую каждую строку кода, чтобы вы могли повторить этот пример.

Настраивать

PyBullet — самый удобный физический симулятор для игр, визуальных эффектов, робототехники и обучения с подкреплением. Вы можете легко установить его одной из следующих команд (если pip не работает, conda точно должен подойти):

pip install pybullet conda install -c conda-forge pybullet

PyBullet можно запустить в двух основных режимах:

  • p.GUI → открывает окно и показывает симуляцию в реальном времени.
  • p.DIRECT → без графического режима, используется для скриптов.

импортировать pybullet как p p.connect(p.GUI) #или p.connect(p.DIRECT)

24bc948ec85349e5cf919a3041431cfa

Поскольку это физический симулятор, первое, что нужно сделать, это настроить гравитацию :

p.resetSimulation() p.setGravity(gravX=0, gravY=0, gravZ=-9.8)

Задаёт вектор глобальной гравитации для моделирования. «-9,8» по оси Z означает ускорение 9,8 м/с² вниз, как на Земле. Без этого ваш робот и самолёт парили бы в невесомости, как в космосе.

URDF-файл

Если бы робот был человеческим телом, файл URDF был бы скелетом, определяющим его физическую структуру. Он написан на XML и, по сути, представляет собой чертеж машины, определяющий, как будет выглядеть ваш робот и как он будет двигаться.

Я собираюсь показать, как создать простой куб , который является 3D-эквивалентом печати («hello world»).

urdf_string = «»»» «»»

Вы можете сохранить код XLM как файл URDF или использовать его как строку.

import pybullet as p import tempfile ## setup p.connect(p.GUI) p.resetSimulation() p.setGravity(gravX=0, gravY=0, gravZ=-9.8) ## создать временный файл URDF в памяти с помощью tempfile.NamedTemporaryFile(suffix=».urdf», mode=»w», delete=False) as f: f.write(urdf_string) urdf_file = f.name ## загрузить URDF p.loadURDF(fileName=urdf_file, basePosition=[0,0,1]) ## отрисовать симуляцию for _ in range(240): p.stepSimulation()

20676330868aed407de22f58ada81a56

Обратите внимание, что цикл выполнялся с 240 шагами. Почему 240? Это фиксированный временной шаг, обычно используемый в разработке видеоигр для обеспечения плавного и отзывчивого игрового процесса без перегрузки процессора. 60 кадров в секунду (FPS) с отображением одного кадра каждую 1/60 секунды, что означает, что шаг физики в 1/240 секунды обеспечивает 4 обновления физики для каждого отрисованного кадра.

В предыдущем коде я визуализировал куб с помощью p.stepSimulation(). Это означает, что симуляция происходит не в реальном времени, и вы сами управляете моментом выполнения следующего шага физики. В качестве альтернативы можно использовать time sleep для привязки к часам реального мира.

import time ## рендер симуляции для _ в диапазоне (240): p.stepSimulation() #добавление шага физики (скорость ЦП = 0,1 секунды) time.sleep(1/240) #замедление до реального времени (240 шагов × 1/240 секунды, сон = 1 секунда)

756caa92ade8c7ba3f538a2f416317e0

В дальнейшем XML-код для роботов станет значительно сложнее. К счастью, PyBullet поставляется с набором готовых URDF-файлов. Вы можете легко загрузить куб по умолчанию, не создавая для него XML.

импорт pybullet_data p.setAdditionalSearchPath(path=pybullet_data.getDataPath()) p.loadURDF(fileName=»cube.urdf», basePosition=[0,0,1])

По сути, файл URDF определяет два основных элемента: звенья и сочленения . Звенья — это жёсткие части робота (например, наши кости), а сочленение — это соединение двух жёстких звеньев (например, наши мышцы). Без сочленений ваш робот был бы просто статуей, но с сочленениями он становится машиной, обладающей движением и функцией.

Вкратце, каждый робот представляет собой дерево звеньев, соединённых шарнирами. Каждый шарнир может быть неподвижным (неподвижным), вращаться («вращательный шарнир») и скользить («призматический шарнир»). Поэтому вам необходимо знать, какого робота вы используете.

Давайте рассмотрим пример знаменитого робота R2D2 из «Звездных войн».

61713f2f3962bed0f7fa61a8e73c9d45

Суставы

На этот раз нам придётся импортировать ещё и плоскость , чтобы создать поверхность для робота. Без плоскости у объектов не было бы поверхности, с которой они могли бы столкнуться, и они бы просто падали бесконечно.

## настройка p.connect(p.GUI) p.resetSimulation() p.setGravity(gravX=0, gravY=0, gravZ=-9.8) p.setAdditionalSearchPath(path=pybullet_data.getDataPath()) ## загрузка URDF plane = p.loadURDF(«plane.urdf») robo = p.loadURDF(fileName=»r2d2.urdf», basePosition=[0,0,0.1]) ## рендеринг симуляции для _ в диапазоне (240): p.stepSimulation() time.sleep(1/240) p.disconnect()

e1502b68949d3f7f0ac3dd97c6ae2599

Прежде чем использовать робота, необходимо разобраться в его компонентах. PyBullet стандартизировал структуру данных, чтобы каждый импортируемый робот всегда определялся одними и теми же 17 универсальными атрибутами . Поскольку я хочу просто запустить скрипт, я подключусь к физическому серверу без графического интерфейса (p.DIRECT). Основная функция для анализа сочленения — p.getJointInfo().

p.connect(p.DIRECT) dic_info = { 0:»Индекс сочленения», #начинается с 0 1:»Имя сочленения», 2:»Тип сочленения», #0 = вращательное, 1 = призматическое, 4 = фиксированное 3:»Индекс вектора состояния», 4:»Индекс вектора скорости», 5:»Флаги», #nvm всегда 0 6:»Демпфирование сочленения», 7:»Трение сочленения», #коэффициент 8:»Нижний предел сочленения», #минимальный угол 9:»Верхний предел сочленения», #максимальный угол 10:»Сила сочленения», #максимально допустимая сила 11:»Скорость сочленения», #максимальная скорость 12:»Имя ссылки», #дочерняя ссылка, подключенная к этому сочленению 13:»Ось сочленения», 14:»Положение родительского кадра», #позиция 15:»Возврат родительского кадра», #ориентация 16:»Индекс родительского кадра» #−1 = основание } for i in range(p.getNumJoints(bodyUniqueId=robo)): print(f»— JOINT {i} —«) joint_info = p.getJointInfo(bodyUniqueId=robo, jointIndex=i) print({dic_info[k]:joint_info[k] for k in dic_info.keys()})

f4c8e9e56f32191ab0e7947f941c12e3

Каждый сустав, будь то колесо, локоть или захват, должен обладать теми же свойствами. Код выше показывает, что у R2D2 15 суставов. Давайте проанализируем первый, называемый «от основания к правой ноге»:

  • Тип сочленения — 4, что означает, что оно неподвижно. Родительское звено — -1, что означает, что оно соединено с основанием , корневой частью робота (например, позвоночником нашего скелета). Для R2D2 основание — это основной цилиндрический корпус, большой сине-белый ствол.
  • Название соединения — «правая нога», поэтому мы понимаем, что это сочленение соединяет основание робота с правой ногой, но оно не моторизовано. Это подтверждается нулем в параметрах оси сочленения , амортизации сочленения и трения сочленения .
  • Положение и ориентация родительской рамы определяют, где правая ножка крепится к основанию.

Ссылки

С другой стороны, для анализа связей (сегментов физического тела) необходимо выполнить цикл по сочленениям, чтобы извлечь имя связи. Затем можно использовать две основные функции: p.getDynamicsInfo() для определения физических свойств связи и p.getLinkState() для определения её пространственного состояния.

p.connect(p.DIRECT) for i in range(p.getNumJoints(robo)): link_name = p.getJointInfo(robo, i)[12].decode('utf-8') #field 12=»Имя ссылки» dyn = p.getDynamicsInfo(robo, i) pos, orn, *_ = p.getLinkState(robo, i) dic_info = {«Масса»:dyn[0], «Трение»:dyn[1], «Положение»:pos, «Ориентация»:orn} print(f»— LINK {i}: {link_name} —«) print(dic_info)

134ef26e2d94e9d5a46e2a65992e12f7

Рассмотрим первый элемент, «правую ногу». Масса 10 кг влияет на силу тяжести и инерцию, а трение влияет на степень скольжения при соприкосновении с землёй. Ориентация (0,707 = sin(45°)/cos(45°)) и положение указывают на то, что звено правой ноги представляет собой цельную деталь, слегка выдвинутую вперёд (5 см) и наклонённую на 90° относительно основания.

Движения

Давайте посмотрим на сустав, который действительно может двигаться.

Например, сочленение 2 — это правое переднее колесо. Это сочленение типа 0, поэтому оно вращается. Оно соединяет правую ногу (индекс связи 1) с правым передним колесом: base_link → right_leg → right_front_wheel. Ось сочленения — (0,0,1), поэтому мы знаем, что колесо вращается вокруг оси Z. Пределы (нижний = 0, верхний = -1) указывают на то, что колесо может вращаться бесконечно, что нормально для роторов.

Мы можем легко перемещать это сочленение . Основная команда для управления приводами вашего робота — p.setJointMotorControl2(). Она позволяет контролировать силу, скорость и положение сочленения. В данном случае я хочу, чтобы колесо вращалось, поэтому я буду прилагать силу, чтобы постепенно увеличить скорость от нуля до заданного значения, а затем поддерживать её, балансируя приложенную силу и силы сопротивления (например, трение, демпфирование, гравитацию).

p.setJointMotorControl2(bodyUniqueId=robo, jointIndex=2, controlMode=p.VELOCITY_CONTROL, targetVelocity=10, force=5)

Теперь, если мы приложим одинаковую силу ко всем четырём колёсам , наш маленький робот будет двигаться вперёд. Из проведённого ранее анализа мы знаем, что сочленения для колеса — это сочленения 2 и 3 (правая сторона), а также 6 и 7 (левая сторона).

8b3016d0ea2810a160714d23574328a7

Учитывая это, я сначала заставлю R2D2 развернуться, вращая только одну сторону, а затем приложу силу к каждому колесу одновременно, чтобы заставить его двигаться вперед.

import pybullet as p import pybullet_data import time ## настройка p.connect(p.GUI) p.resetSimulation() p.setGravity(gravX=0, gravY=0, gravZ=-9.8) p.setAdditionalSearchPath(path=pybullet_data.getDataPath()) ## загрузка URDF plane = p.loadURDF(«plane.urdf») robo = p.loadURDF(fileName=»r2d2.urdf», basePosition=[0,0,0.1]) ## стабилизация for _ in range(240): p.stepSimulation() right_wheels = [2,3] left_wheels = [6,7] ### первый поворот for _ in range(240): for j in right_wheels: p.setJointMotorControl2(bodyUniqueId=robo, jointIndex=j, controlMode=p.VELOCITY_CONTROL, targetVelocity=-100, force=50) for j in left_wheels: p.setJointMotorControl2(bodyUniqueId=robo, jointIndex=j, controlMode=p.VELOCITY_CONTROL, targetVelocity=100, force=50) p.stepSimulation() time.sleep(1/240) ### затем двигаться вперед for _ in range(500): for j in right_wheels + left_wheels: p.setJointMotorControl2(bodyUniqueId=robo, jointIndex=j, controlMode=p.VELOCITY_CONTROL, targetVelocity=-100, force=10) p.stepSimulation() time.sleep(1/240) p.disconnect()

885e9366e65de052cfbc7a23a248e85e

Обратите внимание, что каждый робот имеет разную массу (вес), поэтому движения могут отличаться в зависимости от физических условий моделирования (например, гравитации). Вы можете экспериментировать, пробуя разные значения силы и скорости, пока не найдёте желаемый результат.

0a92b3f648ecab3f845e1e79127848e2

Заключение

Эта статья представляет собой руководство по использованию PyBullet и созданию простейших 3D-моделей для робототехники . Мы научились импортировать объекты URDF и анализировать сочленения и звенья. Мы также поработали со знаменитым роботом R2D2. В будущем появятся новые руководства с более продвинутыми роботами.

Полный код для этой статьи: GitHub

Надеюсь, вам понравилось! Обращайтесь ко мне с вопросами и отзывами, а также просто делитесь своими интересными проектами.

👉 Давайте общаться 👈

ce8d744ae62c3400aeea2115a68376cf

(Все изображения принадлежат автору, если не указано иное)

Источник: towardsdatascience.com

Каталог бесплатных опенсорс-решений, которые можно развернуть локально и забыть о подписках

галерея

ИИ почти всех обгонит? Прогнозы звучат громко, но есть нюансы…
Компания Anthropic получила от Amazon 5 миллиардов долларов и в обмен пообещала инвестировать 100 миллиардов долларов в облачные сервисы.
dummy-img
Загрузка: обход банковских систем кибермошенниками и проблемы с удалением углерода.
Загрузка: обход банковских систем кибермошенниками и проблемы с удалением углерода.
dummy-img
dummy-img
Взаимодействие человека и машины погружается под воду.
Взаимодействие человека и машины погружается под воду.
Image Not Found
Компания Anthropic получила от Amazon 5 миллиардов долларов и в обмен пообещала инвестировать 100 миллиардов долларов в облачные сервисы.

Компания Anthropic получила от Amazon 5 миллиардов долларов и в обмен пообещала инвестировать 100 миллиардов долларов в облачные сервисы.

Вкратце Опубликовано: Изображение предоставлено: Thos Robinson/Getty Images для The New York Times (откроется в новом окне) Джули Борт Компания Anthropic получила от Amazon 5 миллиардов долларов и в обмен пообещала инвестировать 100 миллиардов долларов в облачные сервисы.…

Апр 21, 2026
dummy-img

Как почистить виниловые пластинки (2026): пылесос, ультразвук, чистящий раствор, щетка.

Эти щелчки и треск недопустимы. Приведите свою музыку в порядок с помощью этого удобного руководства. Источник: www.wired.com

Апр 21, 2026
Загрузка: обход банковских систем кибермошенниками и проблемы с удалением углерода.

Загрузка: обход банковских систем кибермошенниками и проблемы с удалением углерода.

Это сегодняшний выпуск The Download, нашей ежедневной новостной рассылки, которая предоставляет вам ежедневную порцию событий в мире технологий. Кибермошенники обходят системы безопасности банков с помощью незаконных инструментов, продаваемых в Telegram. В центре по отмыванию денег в Камбодже…

Апр 21, 2026
Загрузка: обход банковских систем кибермошенниками и проблемы с удалением углерода.

Загрузка: обход банковских систем кибермошенниками и проблемы с удалением углерода.

Это сегодняшний выпуск The Download, нашей ежедневной новостной рассылки, которая предоставляет вам ежедневную порцию событий в мире технологий. Кибермошенники обходят системы безопасности банков с помощью незаконных инструментов, продаваемых в Telegram. В центре по отмыванию денег в Камбодже…

Апр 21, 2026

Впишите свой почтовый адрес и мы будем присылать вам на почту самые свежие новости в числе самых первых