Bu, konunun uzun ve teknik rehberi (ESP-IDF, MicroPython, rclcpp gibi alternatiflerle). Adım adım yol için Porti görevlerine dön.

Ana rota · Hafta 5 · 9–18 saat

Aynı robot, iki dünya

ros2_control: mock, Gazebo ve gerçek robot tek launch'ta

Robotunun dijital ikizini kuruyorsun. diff_drive_controller hem Gazebo'da hem gerçek robotta aynı; aradaki tek fark bir launch argümanı. Bunun için ESP32'yle seri porttan konuşan ilk C++ ros2_control donanım arayüzünü yazıyorsun. Robotik yazılım ilanlarının çoğu tam olarak bu katmanı istiyor.

Günün sonunda elinde
  • ros2_control_demos'taki DiffBot'u çalıştırıp içini okudun
  • Robotun Gazebo Harmonic'te teleop ile sürülüyor
  • C++ SystemInterface eklentisi: seri port, bloklamayan okuma, watchdog
  • hw:=mock | gazebo | real tek launch dosyası
  • Aynı komut dizisinde sim ve gerçek odometry aynı grafikte
5.1

Hazır örnekte ros2_control'ü gör

ros2_control_demos example 2 çalışıyor; controller ve donanım arayüzlerini CLI ile inceleyebiliyor, mock donanımla robotu sürebiliyorsun.

Yap
Kod
demo.sh
# ros2_control'ü önce hazır örnekte gör (mock donanım)
sudo apt install -y ros-jazzy-ros2-control ros-jazzy-ros2-controllers ros-jazzy-ros2-control-demos
ros2 launch ros2_control_demo_example_2 diffbot.launch.py
ros2 control list_controllers          # diffbot_base_controller active
ros2 control list_hardware_interfaces  # left_wheel_joint/velocity [claimed]
ros2 topic pub --rate 10 /diffbot_base_controller/cmd_vel geometry_msgs/msg/TwistStamped \
  "{twist: {linear: {x: 0.3}, angular: {z: 0.5}}}"
Kanıt: list_hardware_interfaces çıktısı ve "read → update → write" döngüsünü kendi cümlelerinle anlatan 3 satır.
Daha derin
5.2

Kendi robotun Gazebo'da

3. haftanın URDF'i Gazebo Harmonic'te doğuyor, gz_ros2_control ile diff_drive_controller çalışıyor, teleop ile sürülüyor.

Önce simülasyonda
Dene:
  • Tarayıcıdaki simülasyon "idealleştirilmiş" bir ikiz: Gazebo da öyle. Tekerlek sürtünmesi, kütle ve ataletin simdeki değerleri gerçeği belirler.
Simülasyon yükleniyor…
Yap
Kod
urdf/rover.ros2_control.xacro
<!-- urdf/rover.ros2_control.xacro — aynı controller, üç farklı donanım -->
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
  <xacro:arg name="hw" default="mock"/>   <!-- mock | gazebo | real -->
  <ros2_control name="RoverSystem" type="system">
    <hardware>
      <xacro:if value="${'$(arg hw)' == 'gazebo'}">
        <plugin>gz_ros2_control/GazeboSimSystem</plugin>
      </xacro:if>
      <xacro:if value="${'$(arg hw)' == 'mock'}">
        <plugin>mock_components/GenericSystem</plugin>
        <param name="calculate_dynamics">true</param>
      </xacro:if>
      <xacro:if value="${'$(arg hw)' == 'real'}">
        <plugin>rover_hardware/RoverSystem</plugin>
        <param name="device">/dev/ttyUSB0</param>
        <param name="baud">115200</param>
        <param name="ticks_per_rev">1400</param>
      </xacro:if>
    </hardware>
    <joint name="left_wheel_joint">
      <command_interface name="velocity"><param name="min">-30</param><param name="max">30</param></command_interface>
      <state_interface name="position"/>
      <state_interface name="velocity"/>
    </joint>
    <joint name="right_wheel_joint">
      <command_interface name="velocity"><param name="min">-30</param><param name="max">30</param></command_interface>
      <state_interface name="position"/>
      <state_interface name="velocity"/>
    </joint>
  </ros2_control>

  <xacro:if value="${'$(arg hw)' == 'gazebo'}">
    <gazebo>
      <plugin filename="gz_ros2_control-system" name="gz_ros2_control::GazeboSimROS2ControlPlugin">
        <parameters>$(find rover_bringup)/config/controllers.yaml</parameters>
      </plugin>
    </gazebo>
  </xacro:if>
</robot>
Kanıt: Gazebo'da sürülen robotun ekran kaydı.
Tuzaklar
  • Gazebo'da robot zıplıyor ya da kayıyorsa atalet değerleri gerçekçi değil ya da çarpışma geometrileri iç içe.
  • Robot simde düz gitmiyorsa tekerlek ekseni yönünü (axis) kontrol et.
  • teleop_twist_keyboard varsayılanı Twist; Jazzy diff_drive_controller TwistStamped ister: -p stamped:=true.
5.3

C++ donanım arayüzün

ros2_control, ESP32'ye seri porttan tekerlek hızı yazıyor ve tick okuyor. Aynı controller gerçek robotu sürüyor.

Yap
Kod
include/rover_hardware/rover_system.hpp
// rover_hardware/include/rover_hardware/rover_system.hpp
#pragma once
#include <hardware_interface/system_interface.hpp>
#include <hardware_interface/types/hardware_interface_return_values.hpp>
#include <rclcpp/rclcpp.hpp>
#include <string>
#include <vector>

namespace rover_hardware {

class RoverSystem : public hardware_interface::SystemInterface {
 public:
  RCLCPP_SHARED_PTR_DEFINITIONS(RoverSystem)

  CallbackReturn on_init(const hardware_interface::HardwareInfo& info) override;
  CallbackReturn on_activate(const rclcpp_lifecycle::State&) override;
  CallbackReturn on_deactivate(const rclcpp_lifecycle::State&) override;
  std::vector<hardware_interface::StateInterface> export_state_interfaces() override;
  std::vector<hardware_interface::CommandInterface> export_command_interfaces() override;
  hardware_interface::return_type read(const rclcpp::Time&, const rclcpp::Duration&) override;
  hardware_interface::return_type write(const rclcpp::Time&, const rclcpp::Duration&) override;

 private:
  bool openPort();
  void closePort();

  std::string device_;
  int baud_ = 115200;
  double ticksPerRev_ = 1400;
  int fd_ = -1;
  std::string rx_;                       // satır biriktirme tamponu
  int32_t lastTicks_[2] = {0, 0};
  bool haveTicks_ = false;
  // ros2_control bu dizilere pointer tutar: boyutları on_init'te sabitlenir
  std::vector<double> pos_, vel_, cmd_;
};

}  // namespace rover_hardware
Kanıt: Gerçek robot ros2_control ile sürülüyor; ros2 control list_hardware_components çıktısında RoverSystem active.
Tuzaklar
  • Seri port izni: kullanıcını dialout grubuna ekle (sudo usermod -aG dialout $USER), oturumu yeniden aç.
  • Port adı her takışta değişiyorsa udev kuralı yaz: /dev/rover sabit olsun.
  • read/write içinde log yazma, bellek ayırma, bloklama yapma: döngü 100 Hz'i tutturamaz.
Daha derin
  • Seri protokolü ikili (binary) ve CRC'li yap; bozuk satır yüzünden hız sıçramasın.
  • Donanım arayüzünü gtest ile test et: sahte bir seri port (pty çifti) ile.
5.4

Tek launch, üç mod, bir karşılaştırma

Aynı komut dizisini mock, Gazebo ve gerçek robotta koşturup üç odometry'yi aynı grafikte karşılaştırdın.

Önce simülasyonda
Dene:
  • Simde patinaj ve aks hatasını gerçek robotta ölçtüğün değerlere ayarla. Gazebo'yu da aynı yöne nasıl itebilirsin?
Simülasyon yükleniyor…
Yap
Kod
mujoco.sh
# MuJoCo ile aynı ros2_control (Jazzy için paket var)
sudo apt install -y ros-jazzy-mujoco-ros2-control ros-jazzy-mujoco-ros2-control-demos
ros2 launch mujoco_ros2_control_demos 01_basic_robot.launch.py
# Kendi robotun için: ros2_control etiketinde plugin
#   mujoco_ros2_control/MujocoSystemInterface
# ve param mujoco_model → MJCF sahne dosyan (ya da URDF'ten çalışma anında üretilen MJCF).
Kanıt: Üç odometry aynı grafikte ve "sim-to-real farkının 3 sebebi" notu.
Daha derin
  • Aynı ros2_control yapısını MuJoCo ile çalıştır (mujoco_ros2_control); temas modellerini Gazebo ile karşılaştır.
  • Gazebo'ya sensör gürültüsü ekle; tarayıcıdaki simülasyonla aynı davranışı yakalayabiliyor musun?

Kavramlar

ros2_controlDonanımı controller'lardan ayıran çerçeve. Controller aynı kalır, altındaki donanım arayüzü değişir.
controller_managerController'ları yükleyen, etkinleştiren ve read → update → write döngüsünü sabit hızda koşturan süreç.
State / command interfaceEklemin okunabilen (konum, hız) ve yazılabilen (hız komutu) değerleri. Donanım bunlara pointer verir.
Lifecycleon_init → on_configure → on_activate: donanım hazır olmadan komut gönderilmez.
Gazebo HarmonicJazzy ile eşleşen simülatör. gz_ros2_control eklentisi aynı controller'ları simde çalıştırır.
use_sim_timeSimde zaman simülatörün saatinden gelir. Unutulursa TF ve odometry zaman hataları verir.

Kaynaklar