ROSのnodeをRustで書いてcatkinで管理する

# このドキュメントの内容

ROSを触り始めたが、pythonもC++もあまり得意ではないので、RustでNodeを書きたくやり方を調べた。
[rosrust](https://github.com/adnanademovic/rosrust)を利用すればできることはすぐわかったし、[わかりやすい記事](https://qiita.com/OTL/items/46451bd137924c043a76)も紹介されていたが、これらのページだけではcatkinで管理する方法がわからなかったので調べた結果をメモする。

以下の内容は基本的に[公式サイトのチュートリアル](http://wiki.ros.org/ja/ROS/Tutorials/CreatingPackage)とrosrustのリポジトリに立っていた[issue](https://github.com/adnanademovic/rosrust/issues/113)の内容である。

# 手順

まずRustのプロジェクトを作る。プロジェクト名は適宜変更する。

```bash
$cd ~/catkin_ws/src
$cargo new --bin rust_test
```

作られたRustのプロジェクトをROSパッケージとして認識させるためには、package.xmlとCMakeLists.txtを含まなければならない([公式サイトのチュートリアル](http://wiki.ros.org/ja/ROS/Tutorials/CreatingPackage)参照)ので、この2つを作る。

CMakeファイルは[issue](https://github.com/adnanademovic/rosrust/issues/113)に neachdainnさんが記載されていた内容ほぼそのままであるが、オリジナルではcargoのpオプションでmy-projectとしているのに、copyの行ではmy-project-binaryと書かれており、コピーに失敗するので注意が必要である。
project名はRustのプロジェクト名と合わせて変更する。

(これでも動くけど変更箇所が多いので、[修正](https://qiita.com/nakakura/items/8b2f08e3b0bf782d4536#%E4%BF%AE%E6%AD%A32020105)参照)

```cmake
cmake_minimum_required(VERSION 3.0)
project(rust_test)

find_package(catkin REQUIRED)
catkin_package()

add_custom_target(rust_test
	ALL
	COMMAND cargo build --release -p rust_test
	COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/cargo/release/rust_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/rust_test
	COMMENT "Building my Rust library"
)
```

package.xmlはC++のときと同じ容量で書き換える。これもプロジェクト名を合わせる

```xml
<?xml version="1.0"?>
<package format="2">
  <name>rust_test</name>
  <version>0.0.0</version>
  <description>my 1st rosrust package</description>
//以下略
```

これでROSのパッケージとして認識され、catkin_makeのビルド対象として扱われる。
但しこのままだとまだビルドがうまく行かないので、Rust側で設定をいくつか行う。


まず~/catkin_ws/Cargo.tomlに、ビルド対象となるRustリポジトリの場所を記載する。

```toml
[workspace]
members = [ "src/rust_test" ]
```

次に~/catkin_ws/.cargo/configに以下の設定を入れる。

```toml
[build]
target-dir = "build/cargo"
```

こうしておくと、cargoでビルドされたファイルが~/catkin_ws/build/cargo内に収まるので、C++で書かれたパッケージと混じらない。

これでビルド環境自体はできたので、実際のコードを記載する。これは元記事や[rosrust](https://github.com/adnanademovic/rosrust)にある通りで、Rustがかける人には問題にならないので割愛。
(但し、rosrustのトップページに有るpub/subの例は、talkerがStringで送っているのにlistenerがUInt64で待ち受けているので通信に失敗する。何かしら間違っているのかと思って三度見したので注意が必要。)

最終的にディレクトリ構成はこうなる

```
catkin_ws
|--- Cargo.toml
|--- .cargo
|    |--- config
|--- src
     |--- rust_test
     |     |--- Cargo.toml
     |     |--- CMakeLists.txt
     |     |--- package.xml
     |     |--- src
     |           |--- main.rs
```

この状態で

```bash
$cd ~/catkin_ws
$catkin_make
$rosrun rust_test rust_test 
```

するとRustで書いたROSパッケージが起動する。roslaunchも大丈夫だった。C++を書く必要はなくなりそうで一安心。

# 修正(2020/10/5)

CMakefileで何箇所もプロジェクト名を書かないといけないのは面倒なので、変数化した。

```cmake

cmake_minimum_required(VERSION 3.0)
# add_custom_targetでコマンドを叩くので環境変数として定義しておく
set (ENV{PROJECT_NAME} rust_test)
project($ENV{PROJECT_NAME})


find_package(catkin REQUIRED COMPONENTS
                std_msgs
                message_generation
)

add_message_files(
                FILES
                Orientation.msg
)

catkin_package(
                CATKIN_DEPENDS std_msgs message_runtime
)

add_custom_target($ENV{PROJECT_NAME}
        ALL
        COMMAND cargo build --release -p $ENV{PROJECT_NAME}
        COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/cargo/release/$ENV{PROJECT_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$ENV{PROJECT_NAME}
        COMMENT "Building my Rust library"
)

# セットした環境変数をクリアしておく
unset (ENV{PROJECT_NAME})                          
```


あと、当然だがCMakefileやpackage.xmlで記載しているプロジェクト名と、Cargo.toml内のプロジェクト名が一致していないと動かないので注意。
(今日別のリポジトリをコピーしてハマった)