ros2-robotics について
ロボットソフトウェア開発者向けの ROS 2 開発スキルです。パッケージ、ノード、通信インターフェース、時間管理、座標フレーム、ビルドとテストを扱い、QoS 設定や実行時の問題にも触れます。
主な機能
- 01ROS 2 パッケージとノードの構成
- 02トピック・サービス・アクションの選択
- 03QoS・時間管理・座標変換の設定
- 04colcon によるビルドとテスト
- 05実行状態の確認と問題の調査
活用シーン
- 01合成可能なロボット機能ノードの構築
- 02センサー・制御用通信インターフェースの設計
- 03複数ノード動作やセンサーシナリオのテスト
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ mindrally/ skills --skill ros2-roboticsインストール後、Claude Code で/ros2-roboticsを入力して読み込まれたか確認します。
詳細
ROS 2 ロボティクス開発
このスキルでは、パッケージ構成、通信パターン(トピック、サービス、アクション)、タイミングとフレーム、colcon を使ったビルド/テストのワークフロー、ロボティクスソフトウェアでよくある落とし穴など、ROS 2 パッケージとノードの構築を扱います。
ROS 2 パッケージを構築するワークフロー
- パッケージのひな型を作成する — colcon ワークスペースの
src/ディレクトリ内で、ros2 pkg create --build-type ament_python <name>(Python)または--build-type ament_cmake <name>(C++)を実行します。 - インターフェースを定義する — 標準インターフェース(
std_msgs、geometry_msgs、sensor_msgs、nav_msgs)では対応できない場合に限り、カスタムの.msg、.srv、または.actionファイルをmsg/、srv/、action/の下に追加します。 - ノードを実装する — 責務を絞り、組み合わせ可能なノードを作成します。パラメーターを明示的に宣言し、ストリームにはトピック、迅速なリクエスト/レスポンスにはサービス、フィードバックとキャンセルに対応する長時間実行の目標にはアクションを選びます。
- launch ファイルを作成する —
launch_ros.actions.Nodeを使って、launch/*.launch.pyファイル内でノード、パラメーター、リマッピングを構成します。 - QoS プロファイルを意図的に設定する — センサーデータとコマンド/制御用の通信経路に合わせて、パブリッシャーとサブスクライバーの QoS(信頼性、永続性、履歴の深さ)を一致させます。
- ワークスペースをビルドする — ワークスペースのルートから
colcon build --symlink-installを実行し、その後source install/setup.bashを実行します。 - テストする — ユニットテスト(Python では
pytest、C++/統合テストではgtest/launch_testing)を追加し、colcon testを実行します。 - 実行して調べる —
ros2 run、ros2 launch、ros2 topic echo、ros2 node info、ros2 doctorを使って、実行時の動作を確認します。
パッケージ構成
- モノリシックなパッケージではなく、各パッケージの責務をロボットの機能または統合境界(例:
lidar_driver、path_planner、arm_controller)のいずれか一つに絞ります。 package.xmlには宣言したビルドタイプを一貫して使用し、ビルドタイプに応じてCMakeLists.txt(ament_cmake、C++)またはsetup.py/setup.cfg(ament_python)を使用します。- launch スクリプトには
launch/、YAML パラメーターファイルにはconfig/、メッセージ定義にはmsg/、サービスにはsrv/、アクションにはaction/、ロボットの記述にはurdf//xacro/を使ってファイルを整理します。 - 複数回起動する可能性があるノード(例:マルチロボット構成)や、複数のプロジェクトで再利用するノードでは、トピック名をハードコードせず、名前空間とトピックのリマッピングを使用します。
- ワークスペースを再現性のある形でビルドできるよう、すべての依存関係を
package.xmlの (<depend>、<exec_depend>、<build_depend>) に明示的に宣言します。
ノードとインターフェース
- ノードは小さく、組み合わせ可能なものにします。すべてを処理する巨大なノードを一つ作るのではなく、論理上の責務ごとにノードを一つ作り、トピック/サービス/アクションで連携させます。
- ROS 2 のパラメーターは
self.declare_parameter('rate_hz', 10.0)で明示的に宣言し、self.get_parameter('rate_hz').valueで読み取ります。未宣言のパラメーターには決して依存しないでください。 - 継続的な状態のストリームにはメッセージ(トピック)、迅速でブロッキングなリクエスト/レスポンス操作にはサービス、フィードバックを報告し、キャンセル/プリエンプションに対応する長時間実行の目標にはアクションを優先します。
- カスタムインターフェースを作成する前に、標準のメッセージ型(
geometry_msgs/Twist、sensor_msgs/LaserScan、nav_msgs/Odometry)を使用します。カスタム型はエコシステムを分断し、既存のツールとの互換性を損ないます。 - トピック、サービス、アクション、フレーム、パラメーターの仕様(名前、型、単位、frame_id、更新頻度)を、パッケージの README またはノードの docstring に記載します。
例:最小限の rclpy パブリッシャーノード
import rclpy
from rclpy.node import Node
from rclpy.qos import QoSProfile, ReliabilityPolicy, HistoryPolicy
from geometry_msgs.msg import Twist
class SafeVelocityPublisher(Node):
"""Publishes bounded velocity commands at a fixed rate."""
def __init__(self) -> None:
super().__init__("safe_velocity_publisher")
self.declare_parameter("rate_hz", 10.0)
self.declare_parameter("max_linear_speed", 0.5)
rate_hz = self.get_parameter("rate_hz").value
self._max_linear = self.get_parameter("max_linear_speed").value
# Reliable QoS for a low-rate command topic; sensor streams would
# typically use BEST_EFFORT with a shallow history instead.
qos = QoSProfile(
reliability=ReliabilityPolicy.RELIABLE,
history=HistoryPolicy.KEEP_LAST,
depth=10,
)
self._publisher = self.create_publisher(Twist, "cmd_vel", qos)
self._timer = self.create_timer(1.0 / rate_hz, self._on_timer)
self._target_linear = 0.0
def _on_timer(self) -> None:
msg = Twist()
msg.linear.x = max(-self._max_linear, min(self._max_linear, self._target_linear))
self._publisher.publish(msg)
def main(args: list | None = None) -> None:
rclpy.init(args=args)
node = SafeVelocityPublisher()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
node.destroy_node()
rclpy.shutdown()
if __name__ == "__main__":
main()
時刻とフレーム
- シミュレーションやバッグの再生が関係する場合は、常に実時間ではなく ROS 時刻(
self.get_clock().now()、シミュレーション時計が使用されている場合はuse_sim_time)を使用します。 - すべてのフレーム変換には
tf2(tf2_ros.BufferとTransformListener)を使用します。名前付きフレーム間の座標変換を独自に実装しないでください。 - フレーム名(
base_link、odom、map、センサーフレーム)とその規約(軸の向きには REP-103、map→odom→base_linkのツリーには REP-105)を文書化します。 - ノードのエグゼキュータースレッド内でコールバックをブロックしないでください。長時間かかる処理は、タイマー、
MultiThreadedExecutor、ワーカースレッド、またはアクションに移し、ノードがほかのコールバックも処理できるようにします。 - QoS プロファイルは意図を持って設定します。サンプルの欠落を許容できる高頻度のセンサーデータには
BEST_EFFORT/volatile、ラッチ型に近い構成トピックにはRELIABLE/TRANSIENT_LOCAL、コマンド経路にはRELIABLE/volatile を使用します。
ビルドとテスト
colcon build(通常、開発中は--symlink-installを使用)を使い、パッケージ間の依存関係をpackage.xmlに明示します。- ワークスペースで使用しているリンターとフォーマッターを実行します。Python では
ament_flake8とament_pep257、C++ ではament_cpplintとament_uncrustifyをcolcon test経由で実行します。 - 複数ノードの動作を対象に、
launch_testingベースの統合テストを追加します(例:「ノード A は、ノード B がパブリッシュした内容を N 秒以内に受信できるか」)。 - 毎回のテスト実行で実機に依存するのではなく、再現可能なセンサーシナリオにはシミュレーション(Gazebo/Ignition)、記録済みの rosbags、またはフィクスチャーデータを使用します。
- 失敗ケースを明示的にテストします。欠落または遅延した変換(
tf2.LookupException)、古いセンサーデータ、呼び出し時に利用できないサービスやアクションを対象にします。
よくある間違い
ament_index_python.packages.get_package_share_directoryを使って解決せず、ファイルシステムの絶対パスをハードコードする。frame_id、単位、タイムスタンプの鮮度を検証せずに速度やアクチュエーターのコマンドをパブリッシュする。古いコマンドや誤ったフレームのコマンドは、ロボットを危険な状態で動かす可能性があります。- 既存の標準インターフェースでデータをモデル化できるのに、カスタムのメッセージ/サービス/アクション型を作成する。
- パブリッシャーとサブスクライバー間の QoS の不整合に関する警告(例:
BEST_EFFORTパブリッシャーとRELIABLEサブスクライバー)を無視する。接続は、データをまったく配信しないままになります。 - オフロードせずにサブスクリプションのコールバック内で大規模な処理を行い、エグゼキューターを占有してほかのコールバック(安全性が重要なものを含む)の処理を遅らせる。
- シミュレーターに接続して実行する際に
use_sim_time:=trueを指定し忘れ、タイムスタンプとtf2のルックアップがシミュレーション時計と一致しなくなる。
コメント
Markdown 対応