1.はじめに
自律移動ロボット「カチャカ」との通信にgRPCが使えるので、Elixirからの通信を試してみました。
今のところ、カチャカのステータスを取得するところまでできました。運転命令を送るところができていないので、次回の課題です。
2.準備
(1)protobuf-elixirをインストール
参考:GitHub - elixir-protobuf/protobuf: A pure Elixir implementation of Google Protobuf.
$ mix escript.install hex protobuf Resolving Hex dependencies... Resolution completed in 0.035s New: protobuf 0.12.0 * Getting protobuf (Hex package) ・・・ * creating /home/user/.asdf/installs/elixir/1.15.6-otp-25/.mix/escripts/protoc-gen-elixir
最後の行の部分が、実際にインストールされたディレクトリを示しています。
インストールの確認のため、一時的に環境変数PATHに、先ほどのディレクトリを指定して、protoc
を実行します。
PATH=/home/user/.asdf/installs/elixir/1.15.6-otp-25/.mix/escripts:$PATH \ protoc Usage: protoc [OPTION] PROTO_FILES ・・・
2.サンプルコード
プロジェクトを作成
$ pwd /home/user/gitwork/ $ mix new kachakex $ cd kachakex
カチャカのprotoファイルを取得
$ wget https://github.com/pf-robotics/kachaka-api/blob/main/protos/kachaka-api.proto
kachaka-api.proto
から、Elixirのコードを生成します。
引数のオプションには、”スペース”文字は入れず一気に記述してください。
カレントディレクトリの./kachaka-api.proto
から生成したコードは、直接./lib
ディレクトリに出力します。
$ PATH=/home/user/.asdf/installs/elixir/1.15.6-otp-25/.mix/escripts:$PATH \ protoc \ --elixir_out=gen_descriptors=true,plugins=grpc:./lib \ -I./ \ ./kachaka-api.proto
下記のPythonサンプルを参考に、Elixirのコードを作成します。
$ touch ./lib/kachakex.ex
./lib/kachakex.ex
の内容
defmodule Kachakex do @moduledoc """ Documentation for `Kachakex`. """ @ipaddr "192.168.1.14:26400" @doc """ 目的地の情報一覧を取得 ## Parameters - ipaddr: KACHAKAのIPアドレス:ポート番号 ## notes - %KachakaApi.Location - id:後述の関数で目的地を指定する際に使用します - pose:単位はロボットの姿勢同様にmおよびradianです """ def get_locations(ipaddr \\ @ipaddr) do with {:ok, channel} <- GRPC.Stub.connect(ipaddr), {:ok, reply} <- KachakaApi.KachakaApi.Stub.get_locations( channel, KachakaApi.GetLocationsResponse.new() ), do: ( {:ok, _channel} = GRPC.Stub.disconnect(channel) reply ) end @doc """ robot versionを取得 ## Parameters - ipaddr: KACHAKAのIPアドレス:ポート番号 ## notes ref: https://github.com/pf-robotics/kachaka-api/blob/main/python/demos/grpc_samples/sample_getter.py """ def get_robot_version(ipaddr \\ @ipaddr) do with {:ok, channel} <- GRPC.Stub.connect(ipaddr), {:ok, reply} <- KachakaApi.KachakaApi.Stub.get_robot_version( channel, KachakaApi.GetRobotVersionResponse.new() ), do: ( {:ok, _channel} = GRPC.Stub.disconnect(channel) reply ) end @doc """ serial numberを取得 ## Parameters - ipaddr: KACHAKAのIPアドレス:ポート番号 """ def get_robot_serial_number(ipaddr \\ @ipaddr) do with {:ok, channel} <- GRPC.Stub.connect(ipaddr), {:ok, reply} <- KachakaApi.KachakaApi.Stub.get_robot_serial_number( channel, KachakaApi.GetRobotSerialNumberResponse.new() ), do: ( {:ok, _channel} = GRPC.Stub.disconnect(channel) reply ) end end
3.実行例
$ iex -S mix Erlang/OTP 25 [erts-13.2.2.4] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit:ns] # バージョン情報を取得 iex(2)> Kachakex.get_robot_version %KachakaApi.GetRobotVersionResponse{ metadata: %KachakaApi.Metadata{cursor: 130182567330, __unknown_fields__: []}, version: "2.3.8", __unknown_fields__: [] } # 登録済みの目的地の一覧を取得 iex(3)> Kachakex.get_locations %KachakaApi.GetLocationsResponse{ metadata: %KachakaApi.Metadata{cursor: 41679425151905, __unknown_fields__: []}, locations: [ %KachakaApi.Location{ id: "L01", name: "リビング", pose: %KachakaApi.Pose{ x: -0.756585, y: 2.818531, theta: -1.035062, __unknown_fields__: [] }, type: :LOCATION_TYPE_UNSPECIFIED, undock_shelf_aligning_to_wall: false, undock_shelf_avoiding_obstacles: false, ignore_voice_recognition: false, __unknown_fields__: [] }, %KachakaApi.Location{ id: "L02", name: "ダイニング", pose: %KachakaApi.Pose{ x: 1.185822, y: 3.914194, theta: -0.409535, __unknown_fields__: [] }, ・・・(省略)・・・ ], default_location_id: "L02", __unknown_fields__: [] }
ひとまず、カチャカのステータスを取得するところまでできました。