コードの自動フォーマット(ROS2 Foxy)

ROS2ではcolcon testでテストが動いてくれますが、このとき、コードが決められたルール通りにコーディングされているかチェックが入ります。 テストが通らないと気持ち悪いので直すのですが、いちいち手で直していると面倒です。そこでamentのCLIツールを使ってコードを自動で整形します。

環境

  • OS:Ubuntu 20.04
  • ROS version:foxy

ament_uncrustify

インストールは以下の通り。

$ sudo apt install -y ros-foxy-ament-cmake-uncrustify ros-foxy-ament-uncrustify

使い方は次の通り。

$ ~/ros2_ws # ワークスペースへ移動
$ ament_uncrustify

次のような感じでスタイルを満たしていないコードを出力してくれる。

Code style divergence in file 'src/ros2_tutorial_collection/tutorial_publisher/src/talker.cpp':

--- src/ros2_tutorial_collection/tutorial_publisher/src/talker.cpp
+++ src/ros2_tutorial_collection/tutorial_publisher/src/talker.cpp.uncrustify
@@ -27,2 +27,3 @@
-class Talker : public rclcpp::Node {
- private:
+class Talker : public rclcpp::Node
+{
+private:
@@ -32,3 +33,4 @@
- public:
-  Talker(const std::string& node_name, const std::string& topic_name)
-      : Node(node_name) {
+public:
+  Talker(const std::string & node_name, const std::string & topic_name)
+  : Node(node_name)
+  {
@@ -41,3 +43,3 @@
-      RCLCPP_INFO(this->get_logger(), "%s", msg_.data.c_str());
-      this->pub_->publish(msg_);
-    };
+        RCLCPP_INFO(this->get_logger(), "%s", msg_.data.c_str());
+        this->pub_->publish(msg_);
+      };
@@ -49 +51,2 @@
-int main(int argc, char* argv[]) {
+int main(int argc, char * argv[])
+{

間違いがたくさんあるので、このままだとcolcon testしたときにエラーが出てしまう。

そこで--reformatオプションを追加して自動フォーマットする。

$ ament_uncrustify --reformat

次のような表示が出てリフォーマットが完了する。

$ Code style divergence in file 'src/ros2_tutorial_collection/tutorial_publisher/src/talker.cpp': reformatted file

これだとcolcon testしてもちゃんとテストが通る。

スタイルは次のURLを使っているはず。

github.com

自分でcfgファイルを編集したい場合は次のリポジトリを参考にすると良さそう。

github.com

ament_clang_format

clang-format形式でコードが記述されているかチェックしてくれる。

インストールは次の通り。

$ sudo apt install -y clang-format
$ sudo apt install -y ros-foxy-ament-cmake-clang-format ros-foxy-ament-clang-format

使い方は次の通り。

$ cd ~/ros2_ws # ワークスペースへ移動
$ ament_clang_format

このままだとbuildフォルダやinstallフォルダまで見に行ってしまうので、ソースコードのあるパスだけ指定する場合は以下を実行する。

$ ament_clang_format ./src

間違いを自動で修正するには--reformatオプションをつける。

$ ament_clang_format --reformat ./src

すると自動的にソースコードを.clang-formatのスタイルに合わせてフォーマットしてくれる。

どんなスタイルでフォーマットするかは.clang-formatに記述する。デフォルトの.clang-formatは多分これを使ってる。

github.com

自分で.clang-formatを作りたい場合は以下のコマンドを実行する。以下はGoogleスタイルを使った場合だが、.clang-formatファイルを直接編集しても良い。

$ clang-format -dump-config -style=Google > .clang-format

ROS2のスタイルは以下に記述がある。

docs.ros.org

独自スタイルでフォーマットする場合は以下の通り。

$ ament_clang_format ./src --reformat --config .clang-format

package.xmlとCMakeLists.txtを次の行を追加するとcolcon testでclang-formatのチェックが入ってくれる。(だが同時にuncrustifyのチェックも走る。残念ながらuncrustifyの外し方がわからなかった。)

<buildtool_depend>ament_cmake</buildtool_depend>
<test_depend>ament_cmake_clang_format</test_depend>
  • CMakeLists.txt
find_package(ament_cmake REQUIRED)
if(BUILD_TESTING)
  find_package(ament_cmake_clang_format REQUIRED)
  ament_clang_format()
endif()

どっちがいいの?

clang-formatのほうが新しいし、ユーザー数も多い。uncrustifyはそうでもない様子。ただROS2のデフォルトはuncrustifyを採用している。clang-formatのほうが将来性はあるという認識はあるようだが、これまでuncrustifyでやってきて今からすべてのリポジトリをリフォーマットするのはコストの割にメリットが少ないという考えらしい。

github.com

コマンドラインからバイト型をパブリッシュする

忘れそうなので。

$ ros2 topic pub /topic std_msgs/msg/Byte "{data: {5}}"
publisher: beginning loop
publishing #1: std_msgs.msg.Byte(data=b'\x05')

publishing #2: std_msgs.msg.Byte(data=b'\x05')

publishing #3: std_msgs.msg.Byte(data=b'\x05')

ros2 topic pub /topic std_msgs/msg/Byte "{data: {255}}"
publisher: beginning loop
publishing #1: std_msgs.msg.Byte(data=b'\xff')

publishing #2: std_msgs.msg.Byte(data=b'\xff')

publishing #3: std_msgs.msg.Byte(data=b'\xff')

256をパブリッシュするとFailed to populate field: bytes must be in range(0, 256)と出るので多分あってる。

97,98,99...とパブリッシュすると表示上はa,b,c...に変換される。

ROS2のコピーライトのあれこれ

概要

ament_copyrightを改良することで、独自のコピーライトを作ってテストを通すことができます。
コマンドラインツールを使用して、コピーライトをあとからまとめて挿入できます。

動機

ROS2のパッケージを作るとき、コピーライトを書かなければなりませんが、いちいちコピペするのが面倒で書き忘れてエラーが出たりしてました。
また仕事でROS2のパッケージを作るときは企業独自のコピーライトを書きたいってときがあるのですが、独自のコピーライトでは、デフォルトのament_copyrightを使うとテストで引っかかってしまいます。
どうにかならないかと思い、いろいろ調べていると、ament_copyrightをを改良することで独自のコピーライトを作成できるということがわかりました。
以下のリポジトリをクローン→編集でできます。

github.com

やり方

  1. 上のリポジトリをクローン
  2. 次のファイルを書き換える。
    • mycompany_ament_copyright/template/mycompany_contributing.txt
      • コントリビューターへ伝えたいことを書く。
    • mycompany_ament_copyright/template/mycompany_header.txt
      • 各ファイルのヘッダー部分に必要なコピーライトを書く。
    • mycompany_ament_copyright/template/mycompany_license.txt
      • ライセンスファイルの記述を書く。
    • setup.py
      • 4行目と28~30行目を編集する。
    • \mycompany_ament_copyright/__init__.py
      • 18, 19行目を編集する。
    • mycompany_ament_copyright/copyright_names.py
      • 18行目を編集する。
    • mycompany_ament_copyright/licenses.py
      • 40行目を編集する。
    • test/cases/mycompany_license/case.py
  3. colcon build & source install/setup.bashを実行する。

使い方

package.xmlに以下を追加する。

<test_depend>mycompany_ament_copyright</test_depend>

C++の場合はCMakeLists.txtに以下を追加する。

find_package(mycompany_ament_copyright REQUIRED)

colcon testでテストを実行して、コピーライトが通っていることを確かめる。

コマンドラインツール

作成したmycompany_ament_copyrightはコマンドライトして使用できます。ヘルプは以下のような感じ。

$ mycompany_ament_copyright --help
usage: mycompany_ament_copyright [-h] [--exclude [filename [filename ...]]] [--add-missing COPYRIGHT_NAME LICENSE] [--add-copyright-year [ADD_COPYRIGHT_YEAR [ADD_COPYRIGHT_YEAR ...]]]
                                 [--list-copyright-names] [--list-licenses] [--verbose] [--xunit-file XUNIT_FILE]
                                 [paths [paths ...]]

Check code files for copyright and license information.

positional arguments:
  paths                 The files or directories to check. For directories files ending in '.c', '.cc', '.cpp', '.cxx', '.h', '.hh', '.hpp', '.hxx', '.cmake', '.py' will be considered
                        (except directories starting with '.' or '_' and 'setup.py' files beside 'package.xml' files). (default: ['.'])

optional arguments:
  -h, --help            show this help message and exit
  --exclude [filename [filename ...]]
                        The filenames to exclude. (default: None)
  --add-missing COPYRIGHT_NAME LICENSE
                        Add missing copyright notice and license information using the passed copyright holder and license (default: None)
  --add-copyright-year [ADD_COPYRIGHT_YEAR [ADD_COPYRIGHT_YEAR ...]]
                        Add the current year to existing copyright notices (default: None)
  --list-copyright-names
                        List names of known copyright holders (default: False)
  --list-licenses       List names of known licenses (default: False)
  --verbose             Show all files instead of only the ones with errors / modifications (default: False)
  --xunit-file XUNIT_FILE
                        Generate a xunit compliant XML file (default: None)

この中で便利なのが--add-missingオプションです。コピーライトがないすべてのファイルにコピーライトを追加してくれます。
ワークスペースで以下を実行するとワークスペース内のパッケージにヘッダーを追記します。

$ mycompany_ament_copyright --add-missing mycompany mycompany

開発中はコピーライトを書かず、リリースする際に一括でコピーライトを追記する、といったことが可能です。

ちなみにcolcon testでコピーライトのテストを回避するには、
C++の場合、CMakeLists.txtのテストの項目に以下を追記します。

set(ament_cmake_copyright_FOUND TRUE)
set(ament_cmake_cpplint_FOUND TRUE)

pythonの場合はros2 pkg create ...で自動生成されるtestフォルダのtest_copyright.pyを削除すればいいです。