Первый узел-издатель на rclpy
Пишем первый настоящий узел — издатель, который шлёт команды скорости нашему роботу.
Издатель (publisher) — объект узла, созданный методом
create_publisher, через который узел отправляет сообщения в топик.
Что мы строим
Сделаем узел, который каждые полсекунды публикует команду «ехать вперёд» в топик /cmd_vel. Наш base_controller подхватит её и закрутит колёса. Это минимальный «мозг», заставляющий робота двигаться.
Полный код издателя
Код помечен language-text: для запуска нужен ROS-рантайм, в браузере он не исполнится.
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
class DriveForward(Node):
def __init__(self):
super().__init__('drive_forward')
# издатель: тип Twist, топик /cmd_vel, глубина очереди 10
self.pub = self.create_publisher(Twist, '/cmd_vel', 10)
# таймер: вызывать tick каждые 0.5 секунды
self.timer = self.create_timer(0.5, self.tick)
def tick(self):
msg = Twist()
msg.linear.x = 0.2 # 0.2 м/с вперёд
msg.angular.z = 0.0 # без поворота
self.pub.publish(msg)
self.get_logger().info('Еду вперёд: 0.2 м/с')
def main():
rclpy.init()
node = DriveForward()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()Разбор по строкам
create_publisher(Twist, '/cmd_vel', 10)— создаёт издателя: тип сообщения, имя топика и глубина очереди (QoS depth) 10. Очередь буферизует сообщения, если подписчик не успевает.create_timer(0.5, self.tick)— просит executor вызыватьtickдважды в секунду. Это правильный способ периодической работы — безtime.sleep, который заблокировал бы узел.msg.linear.x = 0.2— заполняем поле скорости. Единицы — метры в секунду.self.pub.publish(msg)— отправляем сообщение в топик.
Как проверить
Запустив узел, в другом терминале смотрим, что он реально шлёт:
ros2 topic echo /cmd_velВывод:
linear: x: 0.2 y: 0.0 z: 0.0 angular: x: 0.0 y: 0.0 z: 0.0 ---
Как работает под капотом
Таймер — это событие внутри executor. Каждые 0.5 с executor вызывает tick. Метод publish не отправляет данные мгновенно по сети сам: он передаёт сообщение в очередь издателя DDS, а DDS уже доставляет его всем подписчикам топика согласно QoS. Поэтому publish почти не блокирует узел — тяжёлую работу по доставке берёт на себя middleware.
Частые ошибки
- Использовать time.sleep в цикле вместо таймера. Это блокирует executor, и узел перестаёт реагировать на остальное.
- Создавать издателя внутри tick. Издателя создают один раз в __init__, иначе будут утечки и хаос в discovery.
- Забыть импортировать тип сообщения. from geometry_msgs.msg import Twist обязателен.
Итоги
- Издателя создают методом create_publisher один раз в __init__.
- Периодическую публикацию делают через create_timer, а не time.sleep.
- publish кладёт сообщение в очередь DDS, дальше доставкой занимается middleware.
- Проверять издателя удобно командой ros2 topic echo.