hotch-potch, Note to self

いろいろ作業記録

Elixirでロボット「カチャカ」とgRPC通信~続編

1.はじめに

前回の記事では、Elixirからカチャカへの通信を確立させて、カチャカのステータスを取得するまでを試行しました。

次のステップとして、カチャカに対して指示を送って、動かすまでを試行しました。

結論

結論としては、「未解決」です。

  1. Elixir→カチャカへの運転指令は出せた
  2. カチャカは受理するも、コマンドを解釈できない

ここからは現時点の考察です。

  1. kachaka-api.protoから生成する、Elixir側のrpcクライアントのコードに不具合がありそう
  2. 具体的には、 protoファイルoneof構文の解釈がうまくできていない
  3. Elixir側でマップCommandにkeyとなるatomを渡しても、oneofで定義されているもののうち、意図する型のメンバーを引いてこられない
  4. protoファイルを直接いじってElixir側で上記を解決(2パターン試行)するも、protoの構造が変わってるので、カチャカでコマンドを受け取れない

といったところで、以下に今回の顛末を整理します。

2.試行おぼえ

(1)環境構築

Elixirのバージョン

$ elixir -v
Erlang/OTP 26 [erts-14.1.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit:ns]

Elixir 1.15.7 (compiled with Erlang/OTP 24)

protobuf関連のツールをインストール

# protocコンパイラ他
sudo apt install protobuf-compiler -y

# protocのElixirプラグイン
mix escript.install hex protobuf

プロジェクトを作る

# 作業ディレクトリ
$ mkdir -p ~/gitwork/kachaka/

# 新規プロジェクト
$ cd !$
$ mix new kachakex
$ cd !$

(2)カチャカのprotoファイルからrpcクライアントを生成

# カチャカのprotoファイルを入手
$ wget https://raw.githubusercontent.com/pf-robotics/kachaka-api/main/protos/kachaka-api.proto

# protoファイル生成のElixirプラグインのパスを通す(Elixirのバージョンによって変わるのでパス名に注意)
PATH=${HOME}/.asdf/installs/elixir/1.15.7/.mix/escripts/:$PATH

# protoファイルから生成
protoc --elixir_out=plugins=grpc:./lib/ kachaka-api.proto 

(3)まずは基本の形から

結論:NG

(4)試行1:生のprotoファイルで生成したkachaka-api.pb.exのうち、oneofが効かないところを手直し

結論:通信は届くけど、カチャカがコマンドの解釈ができないエラーを返してきてNG

修正前

kachakex/lib/kachaka-api.pb.exファイル、375行目付近

protobufの、いわゆるunion型に相当する記述を展開した場所

defmodule KachakaApi.Command do
  @moduledoc false

  use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0"

  oneof(:command, 0)

  field(:move_shelf_command, 1,
    type: KachakaApi.MoveShelfCommand,
    json_name: "moveShelfCommand",
    oneof: 0
  )

  field(:return_shelf_command, 2,
    type: KachakaApi.ReturnShelfCommand,
    json_name: "returnShelfCommand",
    oneof: 0
  )
…
  field(:lock_command, 9, type: KachakaApi.LockCommand, json_name: "lockCommand", oneof: 0)
end

修正後

上記の関数KachakaApi.Commandをまるっと書き換え。

とりあえず今回の試行で使うmove_to_location_commandフィールドだけを書いた関数とした。

defmodule KachakaApi.Command do
  @moduledoc false

  use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0"

  field(:move_to_location_command, 1,
    type: KachakaApi.MoveToLocationCommand,
    json_name: "moveToLocationCommand"
  )
end

(5)試行2:他のprotoファイルの書き方をまねる

結論:NG

3.まとめ

protoファイルのoneof構文の書き方を気を付ければできそう。。。 なのですが、カチャカ本体にまでは修正の手が出せないので、今回はここでいったん終了です。

おそらくコレに関するissueは出ていて、解消の可能性も・・・?

Inconsistent behaviour when encoding oneof · Issue #362 · elixir-protobuf/protobuf · GitHub

おとなしく、Pythonほかを使った実装で作ってみようと思います。