RUSTでROSパッケージを作る
はじめに
株式会社Ristのロボットチームのプラダンです。ネパール出身ですが、2年前に来日しました。
タイのアジア工科大学大学院でメカトロニクスの修士号を取得。
Ristに入社する前は研究者、機械エンジニアとして働いていました。
概要
これは、Ristの同僚によるA Gentle Introduction to rosrust, and its actionlib SupportとTurtlebot3(Burger)をROS BridgeしてRustで動かす準備のフォローアップ記事で、ROSで'.rs'のrustファイルを読み込むROSパッケージを作成し、RUSTを使ってパラメータを作成する方法について書かれています。
Catkin_wsでCargoを使ってパッケージを作成する
パッケージを作るのは簡単な作業ですが、'.rs' ファイルを読み込むパッケージを作るのは、ROS のデフォルトのプログラミング言語が c++ と python であるため、少し面倒です。空のパッケージを作成するには:
$ roscd
$ cd ../ src
$ catkin_create_pkg rust_test
パッケージが作成されたら、catkin_wsのsrcフォルダの中に入って、パッケージを見てください。ROSパッケージには以下のものが含まれているはずです。
catkin_ws
├── build
├── devel
└── src
└── rust_test
├── CMakeLists.txt
└── package.xml
※ パッケージを作成する前に、catkin_wsのsrcフォルダにあることを確認してください。
次はcargoを使ってcatkin_wsのsrcフォルダ内にRUSTパッケージを作成します。
$ cargo new rust_ws
rust_wsパッケージの中には、以下のように表示されているはずです。
rust_ws
├── Cargo.toml
└── src
└── main.rs
catkin_wsの中には、ROSパッケージrust_testとカーゴパッケージrust_wsがあります。
##ROSでRUSTをコンパイルす
ROSはまだRUSTをサポートしていないので、 rust_ws カーゴパッケージにいくつかの変更を加えなければなりません。
ラストテスト**フォルダから CMakeLists.txt と package.xml をコピーして、rust_wsフォルダに貼り付けてください。新しいパッケージは以下のようになります。
rust_ws
├── Cargo.toml
├── CMakeLists.txt
├── package.xml
└── src
└── main.rs
CMakeLists.txtとpackage.xml**は、現在のパッケージにコピーした別のパッケージのものなので、ROSとRUSTが機能するようにコードを変更する必要があります。
####CMakeLists.txtファイルを変更
このファイルには元のパッケージ名、すなわち rust_test が含まれています。
Original CMakeLists.txt
cmake_minimum_required(VERSION 2.8.3)
project(rust_test)
find_package(catkin REQUIRED)
include_directories(
# include
# ${catkin_INCLUDE_DIRS}
)
Modified CMakeLists.txt
rust_testを現在のパッケージ名rust_wsに変更し、以下のコードを追加してください。
cmake_minimum_required(VERSION 2.8.3)
project(rust_ws)
find_package(catkin REQUIRED)
include_directories(
# include
# ${catkin_INCLUDE_DIRS}
)
add_custom_target(rust_ws
ALL
COMMAND cargo build --release -p rust_ws
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/cargo/release/rust_ws ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/rust_ws
COMMENT "Building my Rust library"
)
####package.xmlファイルを変更
また、package.xmlも修正する必要があります。CMakeLists.txtファイルの修正と同様に、元の名前を現在のパッケージ名に変更します。
Original package.xml file:
<?xml version="1.0"?>
<package format="2">
<name>rust_test</name>
<version>0.0.0</version>
<description>The rust_test package</description>
Modified package.xml file:
<?xml version="1.0"?>
<package format="2">
<name>rust_ws</name>
<version>0.0.0</version>
<description>The rust_ws package</description>
##catkin_wsをcargoで作成した新しいパッケージでコンプする
CMakeList.txtファイルとpackage.xmlファイルを修正したら、catkin_wsをコンパイルしてソースを作成する必要があります。しかし、catkin_wsをコンパイルする前に、ROSがRUSTの'.rs'ファイルを読み込めるようにするために、catkin_wsにもう一つ重要な追加をする必要があります。
- このステップまでは、catkin_wsはこのようになっているはずです。
catkin_ws
├── build
├── devel
└── src
├── rust_test
└── rust_ws
├── Cargo.toml
├── CMakeLists.txt
├── package.xml
└── src
└── main.rs
- 次のステップでは、設定ファイルを格納する .cargo フォルダを隠しフォルダとして作成します。
- 最も簡単な方法は、cilckを右マウスでクリックして、New Folderを選択することです。
- ※ .cargoというフォルダ名を付ける前に、フォルダ内にconfigファイルを作成しておくことをお勧めします!config.png
- 無題のフォルダ名 .cargo を非表示にします。
- 設定ファイルに以下を追加します。
[build]
target-dir = "build/cargo"
- カーゴ環境用のCargo.tomlファイルを作成します。
- Cargo.tomlファイルに、以下を追加します。
[workspace]
members = [ "src/rust_ws" ]
上記の手順を完了すると、catkin_wsは以下のようになるはずです。
catkin_ws
├── build
├── devel
├── src
├── rust_test
└── rust_ws
├── Cargo.toml
├── CMakeLists.txt
├── package.xml
└── src
└── main.rs
└── Cargo.toml
最後にcatkin_wsをコンパイルします。
※: srcではなくcatkin_wsフォルダにあることを確認してください。
$ catkin_make
エラーが出ないようにコンパイルした後、ソースを出しています。
$ source devel/setup.bash
ソースが作成されると、Cargo.lockファイルがcatkin_wsフォルダに表示されます。これでROSはRUSTの'.rs'スクリプトを読むことができるようになります。
catkin_ws
├── build
├── devel
├── src
├── rust_test
└── rust_ws
├── Cargo.toml
├── CMakeLists.txt
├── package.xml
└── src
└── main.rs
├── Cargo.lock
└── Cargo.toml
##シンプルなパブリッシャーノードのテスト
Source後、ROSはRUSTと通信できるようになります。RUSTがROSで動作しているかどうかをテストするには、'main.rs'に書かれた簡単なパブリッシャーコードを使用します。
use env_logger;
use rosrust;
fn main() {
env_logger::init();
rosrust::init("topic_publisher");
//create publisher
let pubs = rosrust::publish("cmd_vel", 10).unwrap();
let rate = rosrust::rate(10.0);
while rosrust::is_ok(){
let mut cmd_vel_data = rosrust_msg::geometry_msgs::Twist::default();
cmd_vel_data.linear.x = 0.5;
cmd_vel_data.linear.y = 0.0;
cmd_vel_data.linear.z = 0.0;
cmd_vel_data.angular.x = 0.0;
cmd_vel_data.angular.y = 0.0;
cmd_vel_data.angular.z = 0.5;
//publish cmd
pubs.send(cmd_vel_data).unwrap();
}
rate.sleep();
rosrust::spin();
}
次に、簡単なlaunchフォルダとlaunchファイルtest.launchを作成します。
※ rust_wsフォルダ内で作成するようご注意ください。**
<launch>
<node name ="test" pkg="rust_ws" type="rust_ws"/>
</launch>
新しいターミナルで rosrcore を起動します。
$ roscore
別の新しいターミナルで起動ファイルを実行してください。
$ roslaunch rust_ws test.launch
##rosrust Dependencies
ソーシング後、ROSはRUSTと通信できるようになります。しかし、RUSTはまだROSと通信できず、常にエラーを出します。
これは、RUSTがROSのデフォルト言語ではないため、'.rs'ファイルを実行できるようにするためには、いくつかの小さな、しかし重要な依存関係が必要だからです。
rust_wsフォルダに戻って、以下の依存関係をrust_wsのCargo.toml**ファイルに追加する必要があります。
依存関係を追加する前に:
[package]
name = "rust_ws"
version = "0.1.0"
authors = ["Praveshkp <pravesh.k.pradhan@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
依存関係を追加した後:
[package]
name = "rust_ws"
version = "0.1.0"
authors = ["Praveshkp <pravesh.k.pradhan@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
env_logger = "0.7.1"
rosrust = "0.9"
rosrust_msg = "0.1"
要件に応じて、依存関係を追加することができます。
依存関係を追加したら、カーゴビルドで依存関係をダウンロードします。
$ cargo build
※ cargo buildを rust_ws パッケージの src フォルダで行っていることを確認してください。
cargoが必要な[dependencies]のダウンロードを終えた後、新しいターミナルで rostopic echo を実行してください。
$ rostopic echo /cmd_vel
そして、launchファイルを実行します。
$ roslaunch rust_ws test.launch
これは、/cmd_velというトピックと値をpublishするだけのプログラムなので、rostopic echoが値をpublishしてくれます。
##Conclusion
上記の手順を踏むことで、RUST付きのROSパッケージを作成することができます。欠点は、新しい ROS with RUST パッケージを作成しようとすると、毎回同じ処理をしなければならないことです。私と 株式会社Rist の同僚は現在、このプロセスを自律的にするための作業を行っています。