1. ROS Noetic のインストール手順
1.1 ソフトウェアソースの設定
インストールを円滑に進めるため、システムのソフトウェアソースを国内サーバー(例:Aliyun)に変更します。 システム設定 → 「About」 → 「Software & Updates」 → 「Download from」 で Aliyun を選択し、「Reload」を実行します。
1.2 ROS Noetic のインストール
1.2.1 sources.list の追加
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
1.2.2 キーの設定
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
成功すると以下のメッセージが表示されます。
gpg: 総数処理数: 1
gpg: インポート: 1
1.2.3 パッケージリストの更新
sudo apt update
1.2.4 ROS Noetic フルパッケージのインストール
sudo apt install ros-noetic-desktop-full
ダウンロードに時間がかかる場合があります。パッケージのダウンロードに失敗した場合は、手順1.1に戻りソースを変更するか、ネットワーク接続を確認してください。
1.2.5 環境変数の設定
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
source ~/.bashrc
2. ROS の動作確認と Turtlesim の実行
新しいターミナルで roscore を起動し、ROS マスターとログ出力の準備を確認します。
続いて別のターミナルで rosrun turtlesim turtlesim_node を実行すると、亀のウィンドウが表示されます。
さらに別のターミナルで rosrun turtlesim turtle_teleop_key を起動し、矢印キーで亀を操作します。壁に衝突すると turtlesim_node 側にログが出力されます。
3. ROS の基本操作
# ROS マスター起動
roscore
# トピック一覧表示
rostopic list
# トピックデータの表示
rostopic echo /camera_raw
# トピックヘッダー表示
rostopic echo /camera_raw/header
# compressed 形式を raw 形式に変換
rosrun image_transport republish compressed in:=/Mate/camera/ raw out:=/Mate/camera_raw/
# トピックのパブリッシュレート制限(4Hz)
rosrun topic_tools throttle messages /Mate/camera_raw 4.0 /left
# rosbag の記録
rosbag record -O bagpath.bag /camera_raw /imu
# rosbag の再生(100倍速)
rosbag play -r 100 bagpath.bag
# rviz 起動
rviz
4. ROS の通信メカニズム
ROS の中核は分散通信フレームワークです。主要な通信方式は Topic、Service、そしてパラメータ共有の3つです。
4.1 トピック通信 (Topic)
パブリッシャー(Publisher)がメッセージを発行し、サブスクライバー(Subscriber)が受信する一方向・非同期の通信です。連続的なデータストリームに適しています。
- Talker(パブリッシャー):データを送信
- Listener(サブスクライバー):データを受信
- ROS Master:ノード情報を管理し、同一トピック名のノード同士をマッチング
接続フロー:
- Publisher が Master に自身のトピック名とアドレスを登録
- Subscriber が Master に購読したいトピック名を登録
- Master が Publisher のアドレスを Subscriber に通知
- Subscriber が Publisher に接続要求を送信
- Publisher が応答し、TCP アドレス情報を送信
- TCP 接続確立後、Publisher から Subscriber へデータ送信
補足: 発行側と購読側の起動順序は任意です。トピック名が一致する必要があります。Master が停止しても、確立済みの接続は維持されます。
4.2 サービス通信 (Service)
クライアント(Client)がリクエストを送信し、サーバー(Server)が応答を返す同期型通信です。偶発的な処理や論理演算が必要な場面に適しています。
- Client:リクエスト送信と応答受信
- Server:リクエスト処理と応答生成
- ROS Master:サービス名に基づき Client と Server をマッチング
接続フロー:
- Server が Master にサービス名を登録
- Client が Master にサービス名を登録
- Master が Server のアドレスを Client に通知
- Client が Server にリクエストを送信
- Server が処理し、応答を Client に返送
補足: クライアントはサーバーが起動している状態でリクエスト可能です。Server と Client は複数存在できます。
5. サービス通信のプログラミング実装
5.1 パッケージの作成
cd ~/ROS_ws/src
catkin_create_pkg communication_pkg rospy roscpp std_msgs std_srvs
cd ~/ROS_ws
catkin_make
source devel/setup.bash
5.2 サービスデータ定義
communication_pkg/srv/ ディレクトリを作成し、AddTwoInts.srv ファイルを作成します。
int64 a
int64 b
---
int64 sum
5.3 クライアントノードの実装
communication_pkg/src/client.cpp を作成し、以下のコードを記述します。
#include <cstdlib>
#include "ros/ros.h"
#include "communication_pkg/AddTwoInts.h"
int main(int argc, char **argv)
{
ros::init(argc, argv, "add_two_ints_client");
if(argc != 3)
{
ROS_INFO("usage: add_two_ints_client X Y");
return 1;
}
ros::NodeHandle n;
ros::ServiceClient client = n.serviceClient<communication_pkg::AddTwoInts>("add_two_ints");
communication_pkg::AddTwoInts srv;
srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);
if(client.call(srv))
{
ROS_INFO("Sum: %ld", (long int)srv.response.sum);
}
else
{
ROS_ERROR("Failed to call service add_two_ints");
return 1;
}
return 0;
}
5.4 サーバーノードの実装
communication_pkg/src/server.cpp を作成します。
#include "ros/ros.h"
#include "communication_pkg/AddTwoInts.h"
bool add(communication_pkg::AddTwoInts::Request &req,
communication_pkg::AddTwoInts::Response &res)
{
res.sum = req.a + req.b;
ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
ROS_INFO("sending back response: [%ld]", (long int)res.sum);
return true;
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "add_two_ints_server");
ros::NodeHandle n;
ros::ServiceServer service = n.advertiseService("add_two_ints", add);
ROS_INFO("Ready to add two ints.");
ros::spin();
return 0;
}
5.5 ビルド設定
CMakeLists.txt の該当箇所を編集します。
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs std_srvs message_generation)
add_service_files(FILES AddTwoInts.srv)
generate_messages(DEPENDENCIES std_msgs)
add_executable(server src/server.cpp)
target_link_libraries(server ${catkin_LIBRARIES})
add_dependencies(server ${PROJECT_NAME}_gencpp)
add_executable(client src/client.cpp)
target_link_libraries(client ${catkin_LIBRARIES})
add_dependencies(client ${PROJECT_NAME}_gencpp)
package.xml に依存関係を追加します。
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
5.6 コンパイルと実行
cd ~/ROS_ws
catkin_make
source devel/setup.bash
# ターミナル1
roscore
# ターミナル2
rosrun communication_pkg server
# ターミナル3
rosrun communication_pkg client 3 5
6. トピック通信のプログラミング実装
6.1 パッケージの作成
cd ~/ROS_ws/src
catkin_create_pkg test_pkg rospy roscpp std_msgs std_srvs
cd ~/ROS_ws
catkin_make
source devel/setup.bash
6.2 カスタムメッセージ定義
test_pkg/msg/Person.msg を作成します。
string name
uint8 sex
uint8 age
uint8 unknown = 0
uint8 male = 1
uint8 female = 2
6.3 パブリッシャーの実装
test_pkg/src/publisher.cpp を作成します。
#include "ros/ros.h"
#include "test_pkg/Person.h"
int main(int argc, char **argv)
{
ros::init(argc, argv, "person_publisher");
ros::NodeHandle n;
ros::Publisher pub = n.advertise<test_pkg::Person>("/person_info", 10);
ros::Rate rate(1);
while(ros::ok())
{
test_pkg::Person msg;
msg.name = "Alice";
msg.age = 25;
msg.sex = test_pkg::Person::female;
pub.publish(msg);
ROS_INFO("Published: name=%s, age=%d, sex=%d", msg.name.c_str(), msg.age, msg.sex);
rate.sleep();
}
return 0;
}
6.4 サブスクライバーの実装
test_pkg/src/subscriber.cpp を作成します。
#include "ros/ros.h"
#include "test_pkg/Person.h"
void callback(const test_pkg::Person::ConstPtr& msg)
{
ROS_INFO("Received: name=%s, age=%d, sex=%d", msg->name.c_str(), msg->age, msg->sex);
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "person_subscriber");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("/person_info", 10, callback);
ros::spin();
return 0;
}
6.5 ビルド設定
CMakeLists.txt を編集します。
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation)
add_message_files(FILES Person.msg)
generate_messages(DEPENDENCIES std_msgs)
add_executable(publisher src/publisher.cpp)
target_link_libraries(publisher ${catkin_LIBRARIES})
add_dependencies(publisher ${PROJECT_NAME}_generate_messages_cpp)
add_executable(subscriber src/subscriber.cpp)
target_link_libraries(subscriber ${catkin_LIBRARIES})
add_dependencies(subscriber ${PROJECT_NAME}_generate_messages_cpp)
package.xml に message_generation と message_runtime の依存を追加します。
6.6 コンパイルと実行
cd ~/ROS_ws
catkin_make
source devel/setup.bash
# ターミナル1
roscore
# ターミナル2
rosrun test_pkg publisher
# ターミナル3
rosrun test_pkg subscriber
6.7 トピックの可視化
rqt_graph を実行すると、現在のノードとトピックの関係がグラフィカルに表示されます。
参考資料
- ROS Wiki: http://wiki.ros.org/
- ROS 通信チュートリアル