hotch-potch, Note to self

いろいろ作業記録

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

1.はじめに

 自律移動ロボット「カチャカ」との通信にgRPCが使えるので、Elixirからの通信を試してみました。

kachaka.life

 今のところ、カチャカのステータスを取得するところまでできました。運転命令を送るところができていないので、次回の課題です。

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__: []
}

ひとまず、カチャカのステータスを取得するところまでできました。

4.参考