見出し画像

Self Driving and ROS 2 - Learn by Doing! Odometry & Control: 回転行列 (セクション6-2/13)

  • ロボットの姿勢を2D空間で表現するために、回転行列と変換行列の概念を学習します。

  • PythonとC++でTurtlesimを用いて、2つのタートル間の回転行列と変換行列を計算するROS 2ノードを実装します。

  • これらの行列を使って、ロボットの位置と向きを正確に制御し、障害物の位置を世界座標系で特定します。

ロボット運動学の魅力的な世界をさらに探求する中で、『Self Driving and ROS 2 - Learn by Doing! Odometry & Control』コースのセクション6の後半は、回転行列と変換行列の詳細に深入りします。これらの概念は、ロボットの姿勢を2D空間で定義するために不可欠であり、その位置と方向の両方を含みます。これらの高度なトピックと、ROS 2およびTurtlesimを使用した実際の応用について見ていきましょう。

回転行列:方向の理解

回転行列は、ロボットの方向を記述するために不可欠です。これは、回転による変位を考慮して、ある参照フレームから別の参照フレームへの座標を変換します。

  1. ロボットの方向:

  • 参照フレーム: ロボットのフレーム(R)と世界のフレーム(W)を定義します。

  • 座標: これらのフレーム内のポイントは、世界のフレームではPx、Py、ロボットのフレームではPx'、Py'で表されます。

  • 回転角(θ): 2つのフレーム間の変位角です。

  1. 投影と計算:

  • 投影の式:

  • Px = Px' * cos(θ) - Py' * sin(θ)

  • Py = Px' * sin(θ) + Py' * cos(θ)

  • 回転行列:

| cos(θ) -sin(θ) |
| sin(θ)  cos(θ) |

PythonでのTurtlesimを使用した実際の応用

次に、Pythonを使用して2つのタートル間の回転行列を計算する実際の例を見てみましょう。

  1. Turtlesimの設定:

  • Turtlesimノードを起動します:

ros2 run turtlesim turtlesim_node
  • 2つ目のタートルをスポーンします:

ros2 service call /spawn turtlesim/srv/Spawn "x: 1.0 y: 4.0 theta: 0.0 name: 'turtle2'"
  1. 回転行列を計算するPythonスクリプト:

import rclpy
from rclpy.node import Node
from turtlesim.msg import Pose
import math

class SimpleTurtlesimKinematics(Node):
       
       def __init__(self):
           super().__init__("simple_turtlesim_kinematics")
           self.turtle1_pose_sub_ = self.create_subscription(Pose, "/turtle1/pose", self.turtle1PoseCallback, 10) 
           self.turtle2_pose_sub_ = self.create_subscription(Pose, "/turtle2/pose", self.turtle2PoseCallback, 10)
           self.last_turtle1_pose_ = Pose()
           self.last_turtle2_pose_ = Pose()
       
       def turtle1PoseCallback(self, pose):
           self.last_turtle1_pose_ = pose
       
       def turtle2PoseCallback(self, pose):
           self.last_turtle2_pose_ = pose
           Tx = self.last_turtle2_pose_.x - self.last_turtle1_pose_.x
           Ty = self.last_turtle2_pose_.y - self.last_turtle1_pose_.y
           theta_rad = self.last_turtle2_pose_.theta - self.last_turtle1_pose_.theta
           theta_deg = 180 * theta_rad / math.pi
           R11 = math.cos(theta_rad)
           R12 = -math.sin(theta_rad)
           R21 = math.sin(theta_rad)
           R22 = math.cos(theta_rad)
           self.get_logger().info(f"""
           Translation Vector turtle1 -> turtle2
           Tx: {Tx}
           Ty: {Ty}
           Rotation Matrix turtle1 -> turtle2
           theta (rad): {theta_rad}
           theta (deg): {theta_deg}
           |R11   R12|:  |{R11} {R12}|
           |R21   R22|   |{R21} {R22}|
           """)

def main():
       rclpy.init()
       simple_turtlesim_kinematics = SimpleTurtlesimKinematics()
       rclpy.spin(simple_turtlesim_kinematics)
       simple_turtlesim_kinematics.destroy_node()
       rclpy.shutdown()

if __name__ == '__main__':
       main()
  1. Pythonスクリプトの実行:

  • ワークスペースをビルドします:

colcon build
  • セットアップファイルをソースします:

. install/setup.bash
  • スクリプトを実行します:

ros2 run bumperbot_py_examples simple_turtlesim_kinematics

C++でのTurtlesimを使用した実際の応用

次に、同じ機能をC++で実装します。

  1. 回転行列を計算するC++コード:

#include "bumperbot_cpp_examples/simple_turtlesim_kinematics.hpp"

using std::placeholders::_1;

SimpleTurtlesimKinematics::SimpleTurtlesimKinematics(const std::string& name)
       : Node(name)
{
       turtle1_pose_sub_ = create_subscription<turtlesim::msg::Pose>(
           "/turtle1/pose", 10, std::bind(&SimpleTurtlesimKinematics::turtle1PoseCallback, this, _1));
       turtle2_pose_sub_ = create_subscription<turtlesim::msg::Pose>(
           "/turtle2/pose", 10, std::bind(&SimpleTurtlesimKinematics::turtle2PoseCallback, this, _1));
}

void SimpleTurtlesimKinematics::turtle1PoseCallback(const turtlesim::msg::Pose& pose)
{
       last_turtle1_pose_ = pose;
}

void SimpleTurtlesimKinematics::turtle2PoseCallback(const turtlesim::msg::Pose& pose)
{
       last_turtle2_pose_ = pose;
       float Tx = last_turtle2_pose_.x - last_turtle1_pose_.x;
       float Ty = last_turtle2_pose_.y - last_turtle1_pose_.y;
       float theta_rad = last_turtle2_pose_.theta - last_turtle1_pose_.theta;
       float theta_deg = 180 * theta_rad / 3.14;
       RCLCPP_INFO_STREAM(get_logger(), "\nTranslation Vector turtle1 -> turtle2 \n" <<
                           "Tx: " << Tx << "\n" <<
                           "Ty: " << Ty << "\n" <<
                           "Rotation Matrix turtle1 -> turtle2 \n" << 
                           "theta (rad): " << theta_rad << "\n" <<
                           "theta (deg): " << theta_deg << "\n" <<
                           "|R11   R12|:  |" << std::cos(theta_rad) << "\t" << -std::sin(theta_rad) << "|\n" <<
                           "|R21   R22|   |" << std::sin(theta_rad) << "\t\t" << std::cos(theta_rad) << "|\n");
}

int main(int argc, char* argv[])
{
       rclcpp::init(argc, argv);
       auto node = std::make_shared<SimpleTurtlesimKinematics>("simple_turtlesim_kinematics");
       rclcpp::spin(node);
       rclcpp::shutdown();
       return 0;
}
  1. C++スクリプトの実行:

  • ワークスペースをビルドします:

colcon build
  • セットアップファイルをソースします:

. install/setup.bash
  • スクリプトを実行します:

ros2 run bumperbot_cpp_examples simple_turtlesim_kinematics

変換行列:平行移動と回転の組み合わせ

変換行列は、平行移動と回転の両方を組み合わせ、2D空間におけるロボットの姿勢を完全に記述します。

  1. 変換行列の構成要素:

  • 平行移動ベクトル (T): ロボットの位置を記述します。

  • 回転行列 (R): ロボットの方向を記述します。

  • 組み合わせ行列:

| R  T |
| 0  1 |
  1. **ワールドフレーム

での位置の計算:**

  • ロボットフレームでの座標 (xP, yP) と変換行列を考慮して、ワールドフレームでの位置を計算します:

| xwP | = | cos(θ) -sin(θ) Tx | | xP |
| ywP |   | sin(θ)  cos(θ) Ty | | yP |
|  1  |   |   0       0      1 | |  1 |
  1. 実際の応用:

  • 変換行列に値を代入することで、ロボットのセンサーで検出された障害物のグローバル位置を決定できます。

結論

回転行列と変換行列を理解し実装することで、2D空間でロボットを正確に制御しナビゲートする能力が向上します。これらの概念は、高度な自律システムを開発するための基本であり、ROS 2とTurtlesimを使用した実際の応用により、理論と現実世界のロボット工学のギャップを埋めます。この包括的なアプローチにより、技術的なスキルが向上するだけでなく、ロボット工学分野の複雑な課題に取り組む準備が整います。

「超本当にドラゴン」へ

この記事が気に入ったらサポートをしてみませんか?