こんにちは!この記事では、 株式会社Octa Roboticsが開発・提供している ロボット・設備間連携に特化したマルチベンダー型のインターフェースサービス「LCI」 について、ロボットからの利用方法を連載形式で紹介していきます。
前回の記事では、通信プロトコルの「乗り込み、乗り込み完了(RobotStatus)」の実装を行いました。
前回 : #9 乗り込み・乗り込み完了(RobotStatus) / 次回 : #11 利用解除(Release)
今回は、「降車、降車完了(RobotStatus)」について実装を行っていきます。
おさらい
降車・降車完了(RobotStatus)のシーケンスについて、再確認していきましょう。
降車・降車完了では、それぞれ以下の手順でロボットとエレベーター(LCI)間でMQTT通信を行います。
降車・降車完了は乗り込み、乗り込み完了とほぼ同一のシーケンスです。
送信するstateの値のみ異なります。
降車
- ロボットからエレベーターにRobotStatus(State:5)を送信
- エレベーターからロボットにRobotStatusResultを送信
- 降車完了を送るまで、5秒間隔で実施
降車完了
- ロボットからエレベーターにRobotStatus(State:2)を送信
- エレベーターからロボットにRobotStatusResultを送信
プロトコルの仕様
前回の乗り込み・乗り込み完了で説明済みのため割愛します。
サンプルコードの確認
前回の乗り込み・乗り込み完了で説明済みのため割愛します。
サンプルコードの改良
サンプルコード(lci_client.py)では、シーケンスの降車・降車完了について以下の箇所が未実装です。
- ElevatorStatus内の
floor(エレベーターの現在階)とdoor(ドアの開閉情報)を確認し、降車を行ってよいか判断する - 降車完了および降車中止まで5秒間隔でRobotStatus(state:5)をループする
- 一定時間内に乗り込みができない場合は、降車中止(state: 4)を送信する
- RobotStatusResult内の
resultが2、3、99だった場合のエラー処理
これらの処理を行えるようにサンプルコードを改良します。
実装したコード
前回の乗り込み、乗り込み完了で作成したコードを元に関数の追加・追記を行います。
clear_robot_status_stop_event
self.stop_event_robot_statusをclearする関数です。
def clear_robot_status_stop_event(self):
self.stop_event_robot_status.clear()
do_robot_status_success_exit
do_robot_status_success_enterの一部を変更し、降車成功を送信する関数を作成します。
def do_robot_status_success_exit(self, time_out: int=10):
res = self.robot_status(RobotStatus.HAS_GOT_OFF, time_out)
if res is not None:
if res.result != 1:
self.registered = False
self.logger.error(f"Robot Status(state:2) is failed code : {res.result}")
else:
self.logger.info(f"Robot succeeded in exiting elevator")
else:
self.registered = False
self.logger.error(f"Robot Status(state:2) code : None")
return res
do_robot_status_cancel_exit
do_robot_status_cancel_enterの一部を変更し、self.robot_status_repeat_commandを使用して降車中止を送信する関数を作成します。
def do_robot_status_cancel_exit(self):
res = self.robot_status_repeat_command(RobotStatus.CANCEL_TO_GET_OFF, 5, 5, (1,2,3,99))
if res is not None:
self.logger.info(f"Robot canceled to exit elevator")
else:
self.logger.info(f"Robot canceled to exit elevator : failed")
self.registered = False
return res
メイン処理(if name=='__main__':)
- 乗り込み完了/中止送信後に、
clear_robot_status_stop_eventを実行 - 行き先階への登録(CallElevator)の実施
-
wait_for_arrivalにて行き先階に到着したか、ドアが開状態であるか確認 -
start_robot_status_open_holdを実行し、5秒間隔でドア開継続要求を実施 - ロボット降車(今回は20秒経過)後に
stop_request_elevator_statusを実行し、エレベーター状態取得を停止 -
end_alightingの値に応じて、降車完了か降車中止を送信 - 利用解除の実施
降車開始から、降車終了まで20秒かかるものとします。
# Main routine
if __name__ == '__main__':
...
#ロボットの乗り込みが終了した場合→True
#ロボットの乗り込みを中止したい場合→False
end_boarding = True
lci_client.logger.info(f"Boarding Elevator : {end_boarding}")
with lci_client.lock_robot_status:
lci_client.stop_robot_status_open_hold()
#乗り込み完了
if end_boarding:
res = lci_client.do_robot_status_success_enter()
lci_client.logger.debug(res)
time.sleep(1)
if not res or not lci_client.is_registered:
res = lci_client.do_release()
lci_client.logger.debug(res)
sys.exit(1)
#乗り込み中止
else:
res = lci_client.do_robot_status_cancel_enter()
lci_client.logger.debug(res)
sys.exit(1)
+ time.sleep(1)
#RobotStatusに関するイベントのリセット
+ lci_client.clear_robot_status_stop_event()
+ time.sleep(1)
#行き先階への登録
res = lci_client.do_call_elevator('B1', '1F')
lci_client.logger.debug(res)
time.sleep(1)
#エレベーターの目的階到着・ドアの開閉状態確認
res = lci_client.wait_for_arrival('1F', 1)
+ if res:
#降車
+ lci_client.start_robot_status_open_hold()
"""
~~~ロボットのエレベーター降車~~~
ここでロボットによるエレベーターの降車を実施します.
今回は20秒で、ロボットが降車を行ったとみなします。
"""
+ roop_time = 20 + time.time()
+ while time.time() < roop_time:
+ if not lci_client.is_registered:
+ res = lci_client.do_release()
+ lci_client.logger.debug(res)
+ sys.exit(1)
+ time.sleep(1)
+ else:
+ res = lci_client.do_release()
+ lci_client.logger.debug(res)
+ sys.exit(1)
#エレベーター状態取得終了
lci_client.stop_request_elevator_status()
time.sleep(1)
#ロボットの降車が終了した場合→True
#ロボットの降車を中止したい場合→False
+ end_alighting = True
+ lci_client.logger.info(f"Alighting Elevator : {end_alighting}")
+ with lci_client.lock_robot_status:
+ lci_client.stop_robot_status_open_hold()
#降車完了
+ if end_alighting:
+ res = lci_client.do_robot_status_success_exit()
+ lci_client.logger.debug(res)
+ time.sleep(1)
+ if not res or not lci_client.is_registered:
+ res = lci_client.do_release()
+ lci_client.logger.debug(res)
+ sys.exit(1)
#降車失敗
+ else:
+ res = lci_client.do_robot_status_cancel_exit()
+ lci_client.logger.debug(res)
+ sys.exit(1)
+ time.sleep(1)
#RobotStatusに関するイベントのリセット
+ lci_client.clear_robot_status_stop_event()
+ time.sleep(1)
#利用解除
res = lci_client.do_release()
lci_client.logger.debug(res)
time.sleep(1)
動作確認
メイン処理のコードを変更し、以下の2ケースに分けて動作を確認します。
- 20秒経過後に、
do_robot_status_success_exit()を実行- 降車完了送信後、次のシーケンスに遷移
- 20秒経過後に、
do_robot_status_cancel_exit()を実行- 降車中止送信後、異常シーケンスに遷移
降車完了した場合
コード変更箇所
メイン処理のend_alightingをTrueにします。
# Main routine
if __name__ == '__main__':
...
#ロボットの降車が終了した場合→True
#ロボットの降車を中止したい場合→False
+ end_alighting = True
lci_client.logger.info(f"Alighting Elevator : {end_alighting}")
with lci_client.lock_robot_status:
lci_client.stop_robot_status_open_hold()
#降車完了
if end_alighting:
res = lci_client.do_robot_status_success_exit()
lci_client.logger.debug(res)
time.sleep(1)
if not res or not lci_client.is_registered:
res = lci_client.do_release()
lci_client.logger.debug(res)
sys.exit(1)
#降車失敗
else:
res = lci_client.do_robot_status_cancel_exit()
lci_client.logger.debug(res)
sys.exit(1)
time.sleep(1)
#RobotStatusに関するイベントのリセット
lci_client.clear_robot_status_stop_event()
time.sleep(1)
#利用解除
res = lci_client.do_release()
lci_client.logger.debug(res)
time.sleep(1)
実行結果
ログから読み取れる動作として、降車完了を送信した後、次のシーケンスである利用解除を行っています。
- 16:44:06,050 ~ 16:44:26,885
- 5秒間隔でドア開継続要求の実施
- 16:44:27,137 ~ 16:44:27,309
- 降車完了を送信
- 16:44:30,365 ~ 16:44:30,554
- 利用解除を送信
2026-05-27 16:44:06,049 INFO Elevator arrived
2026-05-27 16:44:06,049 INFO Door opened
2026-05-27 16:44:06,050 DEBUG Sending PUBLISH (d0, q1, r0, m30), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (64 bytes)
2026-05-27 16:44:06,217 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (114 bytes)
2026-05-27 16:44:11,266 DEBUG Sending PUBLISH (d0, q1, r0, m33), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (65 bytes)
2026-05-27 16:44:11,426 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (115 bytes)
2026-05-27 16:44:16,435 DEBUG Sending PUBLISH (d0, q1, r0, m36), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (65 bytes)
2026-05-27 16:44:16,577 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (115 bytes)
2026-05-27 16:44:21,603 DEBUG Sending PUBLISH (d0, q1, r0, m40), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (65 bytes)
2026-05-27 16:44:21,724 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (115 bytes)
2026-05-27 16:44:26,770 DEBUG Sending PUBLISH (d0, q1, r0, m43), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (64 bytes)
2026-05-27 16:44:26,885 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (114 bytes)
2026-05-27 16:44:27,136 INFO Alighting Elevator : True
2026-05-27 16:44:27,137 DEBUG Sending PUBLISH (d0, q1, r0, m44), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (65 bytes)
2026-05-27 16:44:27,309 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (115 bytes)
2026-05-27 16:44:27,352 INFO Robot succeeded in exiting elevator
2026-05-27 16:44:30,365 DEBUG Sending PUBLISH (d0, q1, r0, m45), 'b'/lci/simulator/1/1/Release/_uClosc2'', ... (53 bytes)
2026-05-27 16:44:30,554 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/ReleaseResult/_uClosc2', ... (115 bytes)
降車中止した場合
コード変更箇所
メイン処理のend_alightingをFalseにします。
# Main routine
if __name__ == '__main__':
...
#ロボットの降車が終了した場合→True
#ロボットの降車を中止したい場合→False
+ end_alighting = False
lci_client.logger.info(f"Alighting Elevator : {end_alighting}")
with lci_client.lock_robot_status:
lci_client.stop_robot_status_open_hold()
#降車完了
if end_alighting:
res = lci_client.do_robot_status_success_exit()
lci_client.logger.debug(res)
time.sleep(1)
if not res or not lci_client.is_registered:
res = lci_client.do_release()
lci_client.logger.debug(res)
sys.exit(1)
#降車中止
else:
res = lci_client.do_robot_status_cancel_exit()
lci_client.logger.debug(res)
sys.exit(1)
time.sleep(1)
#RobotStatusに関するイベントのリセット
lci_client.clear_robot_status_stop_event()
time.sleep(1)
#利用解除
res = lci_client.do_release()
lci_client.logger.debug(res)
time.sleep(1)
実行結果
ログから読み取れる動作として、降車中止を送信した後、それ以降のシーケンスを実行していません。
- 16:20:44,082 ~ 16:21:04,674
- 5秒間隔でドア開継続要求
- 16:21:05,169 ~ 16:21:05,346
- 降車中止を送信
2026-05-27 16:20:44,082 INFO Elevator arrived
2026-05-27 16:20:44,082 INFO Door opened
2026-05-27 16:20:44,082 DEBUG Sending PUBLISH (d0, q1, r0, m31), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (65 bytes)
2026-05-27 16:20:44,181 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (115 bytes)
2026-05-27 16:20:49,198 DEBUG Sending PUBLISH (d0, q1, r0, m34), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (65 bytes)
2026-05-27 16:20:49,302 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (115 bytes)
2026-05-27 16:20:54,315 DEBUG Sending PUBLISH (d0, q1, r0, m37), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (65 bytes)
2026-05-27 16:20:54,406 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (115 bytes)
2026-05-27 16:20:59,427 DEBUG Sending PUBLISH (d0, q1, r0, m41), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (65 bytes)
2026-05-27 16:20:59,529 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (114 bytes)
2026-05-27 16:21:04,537 DEBUG Sending PUBLISH (d0, q1, r0, m44), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (65 bytes)
2026-05-27 16:21:04,674 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (115 bytes)
2026-05-27 16:21:05,168 INFO Alighting Elevator : False
2026-05-27 16:21:05,169 DEBUG Sending PUBLISH (d0, q1, r0, m45), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (65 bytes)
2026-05-27 16:21:05,346 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (115 bytes)
2026-05-27 16:21:05,387 INFO Robot aborted exiting the elevator
その他
- 本記事は、LCIプロトコル仕様書(オンライン)のv2025-10-04を参考に作成・加筆しています
- LCI関連の開発に必要な情報が記載されている開発者用ポータルは以下からアクセスできます
- 各種資料は以下から閲覧・ダウンロードできます
サンプルコードは、以下の二つがアップロードされています。
- lci_client.py : オリジナル
- lci_client_tech_blog.py : 本ブログを通して改良したもの
- 開発用アカウントの発行は、以下からお問い合わせください
連載記事リスト
- (1)はじめに・自己紹介・システム概要
- (2)開発用アカウント発行・サンプルコード
- (3)MQTTのブローカー接続・MQTTについて
- (4)エレベーター連携の全体シーケンス
- (5)エレベーター利用登録(Registration)
- (6)エレベーター呼出階・行き先階指定(CallElevator)
- (7)エレベーターの状態取得(RequestElevatorStatus)
- (8)エレベーターの状態取得2(RequestElevatorStatus)
- (9)乗り込み・乗り込み完了(RobotStatus)
- (10)降車・降車完了(RobotStatus)
- (11)利用解除(Release)
他の記事もチェックしてみてください!
次回の記事では、通信プロトコルの「利用解除」についてサンプルコードを改良する予定です!
ご興味があれば「いいね」やフォローをいただけると励みになります!

