はじめに

 

すいません,私もこのネタ(includeパス問題)です.

Go言語(以下,golang)はクラウドネイティブな各モジュールと相性が良い.Webサーバ機能がPy○○onなどと違ってテスト用ではなく商用にも耐えられるモノが標準で採用されてる点が大きい.その他諸々からもREST APIファーストな用途には欠かすことが出来ない言語と言える.

そんなgolangをROS2でも利用したい!と考えるのは最早,必然である(?)

2022年現在,目についたrclgo実装は次の通り.

    • https://github.com/tiiuae/rclgo

 

    • https://github.com/juaruipav/rclgo

 

    https://github.com/PiusNyakoojo/rclgo

いずれの実装もhumbleには未対応である点は共通している.ただし,更新が積極的に行われており比較的利用者が多いことが想定できる tiiuae/rclgo のhumble対応に挑戦してみようと思った次第である.

tiiuae/rclgoについて

このrclgoは,ROS2コアライブラリ(ros-galactic-ros-coreで入るような,rclcppや各種Pub/Subのメッセージ定義,rmw等)に依存している.golangのスタンダード・ライブラリの一つであるcgoを利用することによって,C/C++言語で書かれたコード(rclcpp)を呼び出すgolangラッパーの役割を果たす.

cgoについて

以下は,https://pkg.go.dev/cmd/cgo にあるベーシックな例である.

package main

// #include <stdio.h>
// #include <stdlib.h>
//
// static void myprint(char* s) {
//   printf("%s\n", s);
// }
import "C"
import "unsafe"

func main() {
	cs := C.CString("Hello from stdio")
	C.myprint(cs)
	C.free(unsafe.Pointer(cs))
}

こんな感じで,golangソースコードにコメントでC実装を書き込み, import C を宣言する(プリアンブル).Go ツールは,1 つ以上の Go ファイルが特別な import C を使用していることを確認すると,非 Go ファイルを探し,それらを Go パッケージの一部としてコンパイルする.

また,Cのコンパイラに伝えるオプションCFLAGS,CPPFLAGS,CXXFLAGS,FFLAGS,および LDFLAGS は,コメント内で疑似 #cgo ディレクティブを使用して定義できる.

// #cgo LDFLAGS: -L${SRCDIR}/libs -lfoo

その他,環境変数としてもC用のコンパイラオプションの設定が可能.

tiiuae/rclgoでのcgo利用と直面する諸問題

表題のgolangパッケージでは2つのパッケージエントリがある.

    1. gogen

メッセージ定義毎の相互変換用パッケージを自動生成するためのツール.(rclcppからrclgoへ)

rclgo

今回目的のrcl

rclgoを使うためには,gogenであらかじめパッケージを生成しておく必要がある.これで生成されるメッセージ定義の一例としてstd_msgs/msg/stringのcgo利用箇所を抜粋する.

 

/*
#include <rosidl_runtime_c/message_type_support_struct.h>
#include <std_msgs/msg/string.h>
*/
import "C"

 

/*
#cgo LDFLAGS: "-L/opt/ros/galactic/lib" "-Wl,-rpath=/opt/ros/galactic/lib"
#cgo LDFLAGS: -lrcl -lrosidl_runtime_c -lrosidl_typesupport_c -lrcutils -lrmw_implementation
#cgo LDFLAGS: -lstd_msgs__rosidl_typesupport_c -lstd_msgs__rosidl_generator_c
#cgo LDFLAGS: -lbuiltin_interfaces__rosidl_typesupport_c -lbuiltin_interfaces__rosidl_generator_c
#cgo CFLAGS: "-I/opt/ros/galactic/include"
*/
import "C"

もう,お分かりですね.

そう,数々のROS2戦士達が一度は「??????」となったであろう,includeパス変更問題に直面するのである.

std_msgs/msg/stringの場合は,メッセージ定義上位パッケージでLDFLAGSとCFLAGS: -I/opt/ros/galactic/includeを使用して,依存関係を無事解決!!となっていたわけであるが,,,

私はどうしたか?

とりあえず,一刻でも早くhumbleで動くことを確認をしたかったので,環境変数を使った力技で押し切るためのスペシャルな(??)ラッピングBashスクリプトcommander.bash を作った.
(多分,パッケージジェネレーターのテンプレートエンジンをいじるのが最も根本的な解決なのであろうが,人のコードは読むのが辛い....時間を優先した結果として許して欲しい.)

#!/bin/bash

BASE_DIR=/opt/ros/humble
CGO_CFLAGS="-L${BASE_DIR}/lib -Wl,-rpath=$BASE_DIR/lib -lrcl -lrmw -lrosidl_runtime_c -lrosidl_typesupport_c -lrcutils -lrcl_action -lrmw_implementation"
include_list=
for dir in $( ls -d $BASE_DIR/include/* ); do
    if [ -d $dir ]; then
        include_list="$include_list -I$dir"
    fi
done

CGO_CFLAGS="$CGO_CFLAGS $include_list"
echo $CGO_CFLAGS
# Exec
CGO_ENABLED=1 CC=gcc CGO_CFLAGS=$CGO_CFLAGS make $1

exit $?

使うときは,Makefileのオプションを指定すればよい.

./commander.bash build
./commander.bash test

他の問題

この他,humble移行に伴い,いくつかの変更があったことから,rclgoに影響のある範囲に対しての修正が必要である.

    1. 各パスでgalacticになっているの部分をhumbleに置換が必要

 

    1. 構造体のサフィックスが_tから_sへ(struct type name suffix changed from _t to _s)

sizeof_struct_rcl_service_t から sizeof_struct_rcl_service_s

struct_rmw_service_info_t から struct_rmw_service_info_s

struct_rcl_client_t から struct_rcl_client_s

rcl_clock_initのコンストラクタに渡す型が変わった.

uint32 から rcl_clock_type_t

動作確認結果

Pub/Sub共に動いた模様.

image.png

おわりに

この辺までやったところで,本業やらなんやらが忙しくなったのでテンプレートエンジンをイジるところまで着手できていない.

テンプレートエンジンをいじったら,本家にPRを送ってみようかなと思う(その前に,対応をしてこられそうですが.)

广告
将在 10 秒后关闭
bannerAds