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

Обратная связь в ROS

logo
smtu logo

Организационная информация

  • Слышу информацию, что достаточно тяжело проходить курс в заданном темпе

  • Только под высокой нагрузкой возможно эффективное обучение

    Так тяжкий млат,
    Дробя стекло, кует булат
    
    А. С. Пушкин, «Полтава»

План занятия

  • Упрощение рутины: сборка, запуск

  • Почему черепаха не каталась по квадрату?

  • Построение графиков в ROS

  • Обратная связь в ROS

  • Изучим робототехнику 200-летней давности (регуляторы)

Подготовка рабочего места и упрощение жизни

Доустановка пакета

sudo apt install ros-jazzy-aruco-opencv-msgs

Рабочая папка

mik@mik-ubuntu-24:~/ros2$ tree -L 2
.
├── ros-usv-teleop
│   ├── README.md
│   └── usv_ws
├── sim
│   ├── libdecor-0.so.0
│   ├── libdecor-cairo.so
│   ├── UnityPlayer.so
│   ├── waterstriderunityURP_BurstDebugInformation_DoNotShip
│   ├── WS_SIM_UBUNTU
│   └── WS_SIM_UBUNTU_Data
└── ws
    ├── build
    ├── install
    ├── log
    └── src

Файл .bashrc

$ tail ~/.bashrc --line 5

source /opt/ros/jazzy/setup.bash
source ~/ros2/ros-usv-teleop/usv_ws/install/setup.bash
source ~/ros2/ws/install/setup.bash

Подготовка рабочего места: симулятор и взаимодействие с ним

Обновить симулятор с облака (https://sdb.smtu.ru/nextcloud/s/simulator) , а также исходный код пакета ros-usv-teleop

~/ros2/ros-usv-teleop$ git pull
~/ros2/ros-usv-teleop$ cd usw_ws
~/ros2/ros-usv-teleop/usw_ws$ colcon build

Подготовка рабочего места: новый репозиторий

$ cd ~/ros2/ws/src
$ git clone http://sdb.smtu.ru/gitlab/marinerobotics/lesson_05.git
$ git clone http://sdb.smtu.ru/gitlab/robotics/ros_aruco_opencv.git
$ cd ..
$ colcon build --symlink-install

colcon build --symlink-install

Упрощаем жизнь: автоматическое сохранение файлов

  • File → Preferences → Settings

  • Text Editor → Files → Auto Save

    • After Delay

vs autosave

Упрощаем жизнь: launch-файл

  • Launch-файлы — средства для одновременного запуска сразу нескольких нод + и настройка их параметров.

  • Могут быть написаны на python, xml, yaml

  • Могут быть вложенными

    ros2 launch <package_name> <launch_file_name>
    ros2 launch lesson_05 mouse_teleop.launch.py

Пример из прошлого урока

from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():
    return LaunchDescription([
        Node(
            package='turtlesim',
            namespace='turtlesim',
            executable='turtlesim_node',
        ),
         Node(
            package="mouse_teleop",
            executable='mouse_teleop',
            namespace='turtlesim',
        ),
        Node(
            package="twist_stamper",
            executable='twist_unstamper',
            namespace='turtlesim',
            remappings=[
                ('cmd_vel_in','mouse_vel'),
                ('cmd_vel_out', 'turtle1/cmd_vel')
            ],
        ),
    ])

Подробнее

from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
   return LaunchDescription([

   ])
Node(
    package='turtlesim',
    namespace='turtlesim1',
    executable='turtlesim_node',
),

Пример 'launch/main.launch.py'

ros2 launch lesson_05 main.launch.py lesson_num:=0

И если мы поменяем код и перезапустим launch - изменения сразу применятся

Материалы

Учебный материал по Launch

https://docs.ros.org/en/jazzy/Tutorials/Intermediate/Launch/Creating-Launch-Files.html

Дизайн-документ по системе Launch

https://design.ros2.org/articles/roslaunch.html

Почему черепаха не двигалась по квадрату?

В предыдущих сериях

  • мы поворачивали не на угол, а в течение какого-то времени

  • мы не знали свою ошибку и не могли корректировать её (система не была 'робастной')

square problems1
square problems2

Примеры принципиально неизвестных внешних воздействий

  • сцепление колёс автомобиля с поверхностью

  • космическая ракета и порывы ветра

  • колебания температуры окружающей среды вокруг инкубатора

  • для древней паровой машины:

    • параметры топлива (угля)

    • скорость подачи угля

Страница истории

  • 16** - Христиан Гюйгенс создаёт центробежный регулятор для ветряной мельницы

  • 1788 - Джеймс Уатт адаптирует регулятор для паровой машины

    Без регулятора с обратной связи паровая машина не могла применяться массово.

Centrifugal governor
Boulton and Watt centrifugal governor MJ

Построение графиков в ROS

  • запускаем:

    ros2 launch lesson_05 \
      main.launch.py lesson_num:=0
  • rqt

  • Plugins → Visualization → Plot

  • /ws/turtle1/pose/theta

    x: 5.544444561004639
    y: 5.544444561004639
    theta: 0.0
    linear_velocity: 0.0
    angular_velocity: 0.0
rqt plot
rqt plot example

Как получить данные в ноде ROS?

Пример 1: subscriber, callback

self.pose_subscriber = self.create_subscription(Pose, 'turtle1/pose',
                                                self.pose_callback, 10)
    def pose_callback(self, msg):
        self.get_logger().info('Current heading: "%f"' % msg.theta)
ros2 launch lesson_05 main.launch.py lesson_num:=2

Решаем проблему с потоками

Было:

self.main()

# ...
def main(self):
    while True:
        self.publish_twist(0, 90.0)
        self.publish_twist(3.0, 0.0)

# ...

self.get_clock().sleep_for(Duration(seconds=1.0))

Стало:

self.SIDE_TIME = 2.0
self.timer = self.create_timer(self.SIDE_TIME, self.pub_timer_callback)
self.step = 0

#...
def pub_timer_callback(self):
    if self.step % 2:
        self.publish_twist(0, 90.0)
    else:
        self.publish_twist(3.0, 0.0)
    self.step += 1

И более никакого sleep_for !

Пример 2: улучшаем main

def main():
    rclpy.init()
    node = AngleMover()

    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()
        try:
            rclpy.shutdown()
        except Exception:
            pass
ros2 launch lesson_05 main.launch.py lesson_num:=1

Регуляторы (обратная связь)

Пример 3: уставка/целевое значение/setpoint

self.desired_heading - уставка/целевое значение/setpoint

def pub_timer_callback(self):
    self.desired_heading += math.pi / 2
    if self.desired_heading >= math.pi:
        self.desired_heading -= 2 * math.pi
    self.get_logger().info('New angle setpoint: "%f"' % self.desired_heading)

Пример 3: дискретный регулятор

    if msg.theta - self.desired_heading < 0:
        msg_pub.angular.z = math.radians(90.0)
        self.get_logger().info('Turn left')
    else:
        msg_pub.angular.z = math.radians(-90.0)
        self.get_logger().info('Turn right')
ros2 launch lesson_05 main.launch.py lesson_num:=3

Пример 3: проблема с углами

1° - 359° = ?

def angle_diff(a1, a2):
    a = a1-a2
    return (a+math.pi)%(2*math.pi)-math.pi

Пример 4: Проблема дискретного регулятора

ros2 launch lesson_05 main.launch.py lesson_num:=4
heading plot

ПИД-регулятор

Просто_о_ПИД-алгоритмах

http://wiki.roboforum.ru/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D0%B2%D0%BE%D0%B4_%D1%81%D1%82%D0%B0%D1%82%D1%8C%D0%B8_%22%D0%9F%D1%80%D0%BE%D1%81%D1%82%D0%BE_%D0%BE_%D0%9F%D0%98%D0%94-%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%B0%D1%85%22

PID Without a PhD Tim Wescott, Wescott Design Services https://web2.qatar.cmu.edu/~gdicaro/16311-Fall17/slides/PID-without-PhD.pdf

https://web2.qatar.cmu.edu/~gdicaro/16311-Fall17/slides/PID-without-PhD.pdf

Как получить курс от катамарана в симуляторе?

from waterstrider_interfaces.msg import WsPose

# ...

self.pose_subscriber = self.create_subscription(WsPose,
                  'unity_pose', self.pose_callback, 10)

# ...

Пример 5: Дискретный регулятор для симулятора

ros2 launch lesson_05 main.launch.py lesson_num:=5

П-регулятор

ws p

Автоколебательный процесс

ws p problem

ПД-регулятор

ws pd

ПД-регулятор

Как получить курс от катамарана в жизни? (Спойлер: сложно)

  • Магнитные компасы работают плохо, особенно в бассейне

  • Спутниковые компасы дорогие и в помещении не работают

  • Механические, волоконно-оптические, лазерные гироскопы очень дорогие и большие

  • Но печать - дешёвая!

gyro
fizoptika

Слежение за Aruco-маркером

  • В симуляторе - "aruco маркеры"

    • Маркер по центру бассейна поворачивается по alt

      ros2 launch lesson_05 main.launch.py lesson_num:=6

Aruco c нормальным регулятором

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

  • symlink-install

  • Launch-файлы

  • Зачем нужны регуляторы?

  • Построение графиков в ROS

  • Обратная связь в ROS

  • Регуляторы

KyleBroflovski

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

Официальная информация про RQT https://docs.ros.org/en/jazzy/Concepts/Intermediate/About-RQt.html

https://docs.ros.org/en/jazzy/Concepts/Intermediate/About-RQt.html

Просто о ПИД-алгоритмах http://wiki.roboforum.ru/index.php?title=Перевод_статьи_"Просто_о_ПИД-алгоритмах"

http://wiki.roboforum.ru/index.php?title=Перевод_статьи_"Просто_о_ПИД-алгоритмах"

PID Without a PhD Tim Wescott, Wescott Design Services https://web2.qatar.cmu.edu/~gdicaro/16311-Fall17/slides/PID-without-PhD.pdf

https://web2.qatar.cmu.edu/~gdicaro/16311-Fall17/slides/PID-without-PhD.pdf

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

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

    • Попроще - адаптировать и настроить П-регулятор для катамарана в симуляторе (step_5.py)

    • Посложнее - написать свой ПД-регулятор и подобрать коэффициенты, он будет работать лучше

  • Практическое задание на настоящем катамаране (но отлаживаться можно и на симуляторе): следовать за курсовым углом Aruco-маркера (step_6.py)

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