Основы программировния морских роботов

Управление нодой ROS

logo
smtu logo

План занятия

  • База по Python

  • Моя первая нода ROS

  • Нода, которая отправляет одну команду

  • Нода, которая отправляет серию команд

Курс не посвящен изучению Python!

База по Python

  • Создан Гвидо ван Россумом в 1991 году

  • Относительно простой язык

  • Python подходит почти для всего

  • Огромная экосистема библиотек: NumPy, Pandas, TensorFlow, PyTorch, Django, Flask, FastAPI…​

  • The Zen of Python

    $ python3
    > import this
python logo

Переменные, операции, комментарии, вывод на консоль

x = 10        # переменная
y = x + 5     # операция
print("Результат:", y)

Массивы, кортежи

arr = [1, 2, 3]      # массив (изменяемый)
tpl = (10, 20, 30)   # кортеж (неизменяемый)

Ветвление

x = 7
if x > 10:
    print("Больше 10")
elif x == 7:
    print("Равно 7")
else:
    print("Другое значение")

Подключение библиотек

import math
print(math.sqrt(25))

Функция

def add(a, b):
    return a + b

print(add(3, 4))

Точка входа

def run():
    print("Старт программы")

if __name__ == "__main__":
    run()

Циклы

for i in range(3):
    print("Итерация", i)
x = 3
while x > 0:
    print(x)
    x -= 1

Классы

class Counter:
    def __init__(self):
        self.value = 0

    def inc(self):
        self.value += 1

c = Counter()
c.inc()
print(c.value)

Наследование

class Figure:
    def square(self):
        raise NotImplementedError("Метод square() должен быть реализован в подклассе")

class Rectangle(Figure):
    def init(self, w, h):
        self.w = w
        self.h = h

    def square(self):
        return self.w * self.h


class Circle(Figure):
    def init(self, r):
        self.r = r

    def square(self):
        return math.pi * self.r * self.r

figures = [Rectangle(3, 4), Circle (10)]

for f in figures:
    print(f.square())

Принцип подстановки Барбары Лисков

если q(x) является свойством, верным относительно объектов x некоторого типа T, тогда q(y) также должно быть верным для объектов y типа S, где S является подтипом типа T
— Барбара Лисков
Liskov

Более простыми словами

Всякая селёдка — рыба, но не всякая рыба — селёдка
— капитан Врунгель
Vrungel

Дальнейшее освоение

Примеры промптов

  • Напиши на python программу для перевода градусов в радианы и поясни что значит каждая строчка для человека, никогда не писавшего на python

  • Напиши программу на python выводящую первые 10 чисел Фибоначчи и поясни что значит каждая строчка для человека, никогда не писавшего на python

IDE

  • VS Code

  • PyCharm

vscode
pycharm

Мой первый пакет ROS

~ $ cd ros2
~/ros2 $ mkdir ws
~/ros2 $ cd ws
~/ros2/ws $ mkdir src
~/ros2/ws $ cd src

!! Важно выйти на уровень выше src !!

~/ros2/ws/src $ ros2 pkg create --build-type ament_python lesson_04_my
~/ros2/ws/src $ cd ~/ros2/ws
~/ros2/ws $ colcon build

альтернатива

~/ros2/ws $ colcon build --packages-select lesson_04_my

Из чего состоит пакет

~/ros2/ws/src $ tree .
.
└── lesson_04_my
    ├── lesson_04_my           # Папка с исходным кодом конкретной ноды
    │   └── __init__.py
    ├── package.xml            # Информация о пакете ROS2
    ├── resource               # Различные ресурсы нод (картинки и т.д.)
    │   └── lesson_04_my
    ├── setup.cfg              # Конфигурационный файл для установки пакета Python
    ├── setup.py               # Скрипт для установки пакета Python
    └── test
        ├── test_copyright.py
        ├── test_flake8.py     # Автоматическая проверка оформления
        └── test_pep257.py     # Автоматическая проверка генерируемой документации

Моя первая нода

Файл, который можно запустить

step_0.py:

import rclpy


def main(args=None):
    rclpy.init(args=args)
    rclpy.shutdown()

if __name__ == '__main__':
    main()

Для того, чтобы запустить:

В файле setup.py

entry_points={
        'console_scripts': [
            f'step_0 = {package_name}.step_0:main',
]
$ cd ~/ros2/ws
$ colcon build
$ source ~/ros2/ws/install/local_setup.bash
$ ros2 run lesson_04 step_0

Наконец-то, нода

step_1.py:

import rclpy
from rclpy.node import Node

class SimpleMover(Node):
    def __init__(self):
        super().__init__('lesson_4_1')

def main(args=None):
    rclpy.init(args=args)
    mover = SimpleMover()

    rclpy.spin(mover)

    mover.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()
$ ros2 node list

Publisher:

step_2.py:

class SimpleMover(Node):
    def __init__(self):
        super().__init__('lesson_4_2')
        self.publisher_twist = self.create_publisher(Twist,
            'ws/twist_autopilot', 10)


    def main(self):
        msg = Twist()
        msg.linear.x = 2.0
        msg.angular.z = -3.14
        self.publisher_twist.publish(msg)

Publisher, технические моменты

def main(args=None):
    rclpy.init(args=args)
    mover = SimpleMover()

    time.sleep(1)
    mover.main()
    rclpy.spin(mover)

    mover.destroy_node()
    rclpy.shutdown()
$ ros2 run turtlesim turtlesim_node -r /turtle1/cmd_vel:=/ws/twist_autopilot

Аналогично - катамаран

Нода, которая отправляет серию команд: step_3.py

    def publish_twist(self, linear, angular):
        msg = Twist()
        msg.linear.x = float(linear)
        msg.angular.z = math.radians(float(angular))
        self.publisher_twist.publish(msg)

    def main(self):
        self.publish_twist(0, 90.0)
        self.publish_twist(3, 0.0)
        self.publish_twist(0, -120.0)
        self.publish_twist(1, 0.0)
        self.publish_twist(0, -120.0)
        self.publish_twist(1, 0.0)
        self.publish_twist(0, 60.0)
        self.publish_twist(2, 0.0)
flag

Проблемы

  • команды отправляются без задержек

    self.get_clock().sleep_for(Duration(seconds=1.0))
  • хочется отладочной информации

    self.get_logger().info(f'Linear={linear},
        Angular={angular} deg/s')
  • нельзя управлять длительностью команды

    • Для тех кто силён духом - mover.py

Цикл и квадрат

    def main(self):
        while True:
            self.publish_twist(0, 90.0)
            self.publish_twist(3.0, 0.0)
square problems1
square problems2

Сегодня я многое понял

  • База по Python

  • Моя первая нода ROS

  • Нода, которая отправляет одну команду

  • Нода, которая отправляет серию команд

KyleBroflovski

Дополнительные материалы

Официальная справка https://docs.ros.org/en/jazzy/Tutorials/Beginner-Client-Libraries.html

https://docs.ros.org/en/jazzy/Tutorials/Beginner-Client-Libraries.html

Пример прохождения задания

Домашнее задание

  • Написать код, который заставит катамаран пройти через ворота, развернуться вокруг одного из шаров и вернуться на исходну точку

  • Базовый код: https://sdb.smtu.ru/gitlab/marinerobotics/lesson-04/

  • Работаем как и ранее - в своей ветке

  • Задача со звёздочкой: высказать гипотезу, почему наше движение по квадрату не срабатывает