名称 MIRS2603 ソフトウェア詳細設計書
番号 MIRS2603-SOFT-0001

版数 最終更新日 作成 承認 改訂記事
A01 2026.10.16 水井 悠人 初版(2026.10.16時点)



1. ドキュメント概要

本ドキュメントはMIRS2603 のこさへんに関するソフトウェア詳細設計についてまとめたものである。2026年10月16日時点の作成途中の版であり、記入中の項目と、実機での確認が済んでいない機能は、その旨を各項に記載している。

2. 機能概要

実装する機能とその概要を以下の表1に示す。

表1 機能と概要

機能 機能概要 記述言語
足回り制御 Jetsonからの速度指令(/cmd_vel)を受け取り、左右の走行モーターの速度制御、エンコーダの計測、緊急停止・通信断時の停止を行う。 C++(Arduino, PlatformIO)
自己位置推定・地図作成 LiDARとオドメトリから、地図の作成(SLAM)と自己位置の推定を行う。 Python(ROS 2)、YAML(slam_toolbox)
自動走行 Nav2で経路を計画し、障害物を避けて走行する。50cmの安全距離と、後退による回復動作を持つ(実機未確認)。自立探索と、ピンへの移動も行う。 YAML・XML(Nav2)、Python
混雑判定・人物検出 LiDARの入口付近の点群密度から混雑/閑散を判定し、人物の候補を確定する。 Python
行動の判断 混雑・人物・残数・各種の停止条件から、接近・見回し・待機・発話を決める。時間帯・状況ルールとbehavior treeで、方針を切り替える。 Python
残数管理 決済横カメラの人物通過、またはタブレットOCRの読み取りから購入数を求め、メニューごとの残数・消費の偏り・宣伝対象を計算する。 Python
音声発話・BGM 発話の文章をOllamaで生成し、VOICEVOXで合成して再生する。状況アナウンスの繰り返し再生、音量・全体ON/OFFの設定を持つ。 Python
腹部ディスプレイ お客さん向けの表示、アンケート、OCR試験用の模擬POSを、1つの画面で切り替えて表示する。アンケートの保存が完了するまで、ロボットは動かない。 HTML・JavaScript、Python、bash
タブレットOCR 決済端末(タブレット)の画面をWebカメラで撮影し、Coral(Edge TPU)による数字認識で購入数を読み取る。 Python
管理画面 PC・スマホから、ロボットの状態の確認と操作を行う。権限は、管理者・弱いアカウント(operator)・guestの3段階。 Python、HTML・JavaScript
起動・停止 1つのコマンドで、状態(manual / full / nav_test)を指定して起動する。停止は、全停止スクリプトと、管理画面のボタンからの終了がある。 bash

管理画面(webアプリ)の機能とその概要を以下の表2に示す。

表2 webアプリ機能概要

機能 機能概要 詳細
地図・走行 地図の表示、目的地の指定、ピンの登録、自立探索の開始・停止。 地図上のクリックで目的地を送り、Nav2が走行する。ピンは行動の順番の指定にも使う。
緊急停止 ソフト緊急停止を、かける・解除する。 すべてのロールが「かける」ことができる。解除は管理者のみ。
速度設定 走行速度・手動運転の最高速度・自動走行の速度を変える。 管理者のみ。通信が切れた場合は、ウォッチドッグで速度0に戻る。
手動運転 スマホ専用ページ(8095)から、D-padで操作する。 手動運転中は、自律的な目的地の送信を止める。「自律に戻す」で復帰する。
音声設定 発話・BGMの音量、音声の全体ON/OFF、状況アナウンスの内容・間隔を設定する。 音量は発話・BGMそれぞれ0〜5倍。operatorには、一部だけを許可できる。
行動設定 時間帯・状況ルールと、behavior treeを編集する。 管理者のみ。安全に関わる停止の判断は、設定の対象外で固定している。
残数・OCR メニューごとの残数の確認と、OCR(模擬POS)の数字の変更。 OCRのカメラ画質は、デモ用と本番用のプロファイルを切り替える。
アカウント・権限 operatorに許可する操作を、1つずつ足す。 operatorの変更は、プログラムの再起動で元に戻る。同じアカウントで操作できる端末は1台まで。
プログラム終了 モーターを止めたうえで、ロボット関連のプログラムを順番に止める。 OSの電源は切らない。確認文字列の入力が必要で、未保存の地図があるときは拒否する(実機未確認)。

3. 各デバイスのモジュール構成

のこさへんは、ESP32(足回り)、Jetson 1台目(頭脳)、Jetson 2台目(音声)、Raspberry Pi(腹部ディスプレイ)、タブレットOCR(Jetson 1台目上)で構成する。各デバイスのモジュール構成を、以下の表に示す。デバイス構成図とネットワーク構成図は作成中である。

3.1. ESP32(足回り)

表3 ESP32 足回りモジュール一覧

ファイル名 説明
main.cpp メインプログラム。setup(), loop() を含む。micro-ROSの通信設定、20ms周期の制御コールバック(速度指令の整形・PID制御・モーター出力・エンコーダ値の送信)、緊急停止入力の監視、通信断からの自己復旧を行う。
config.h 設定定義ファイル。ピン番号の割り当て、PIDゲインの既定値、加減速の設定、車輪半径・車輪間隔・エンコーダ分解能などの定数を集約している。
platformio.ini ビルド設定。PlatformIOによるESP32(Arduinoフレームワーク)のビルド設定と、micro-ROSライブラリ(Humble)の指定。

足回りプログラムは「走行モーターの速度制御」と「通信・緊急停止時の安全な停止」を担う下位ユニットである。上位機(Jetson)から受け取った速度指令を、20ms周期の制御ループ内で左右の車輪の目標速度に変換し、PID制御で追従させる。経路の計画や行動の判断は行わない。

3.1.1. 足回りシステムアーキテクチャ

プログラムは階層構造を採用しており、上位の指令を整形したあとで、下位の駆動を行う設計となっている。

通信層 (micro-ROS)
/cmd_vel(速度指令)と /nokosahen/pid_gains(ゲイン変更)を購読し、エンコーダ値(/wheel_ticks)・緊急停止状態(/estop_state)・ゲインの現在値などを送信する。
速度指令整形層 (controlCallback)
速度指令に台形の加減速制限と臨界減衰フィルタをかけ、左右の車輪の目標速度へ変換する。
速度制御層 (PID)
左右の車輪の回転速度をPID制御により目標へ追従させる。前進と後退で別のゲインを持つ。
ハードウェア抽象化層 (setMotor, エンコーダ割り込み, updateEstop)
PWM・回転方向信号の出力、エンコーダのパルス計測、緊急停止入力の読み取りを行う。

3.1.2. 足回り詳細機能

速度制御 (PID)
足回りの制御における最下層かつ最も重要な部分である。
加減速の整形
急な速度変化による転倒・スリップを防ぐための処理である。
停止の仕組み
センサ処理
通信インターフェース

3.2. Jetson 1台目(頭脳、ROS 2)

表4 Jetson 頭脳プログラムの主なモジュール一覧

ファイル名 説明
behavior_director.py 行動の判断(メイン)。混雑状態・人物・残数・各種停止条件から、いまの行動(モード)を決め、接近・見回し・発話・待機の指令を出す。安全に関わる停止の分岐は、他の判断より常に先に評価する。
behavior_rules.py / behavior_rules_store.py 時間帯・状況ルール。時間帯・曜日・混雑・残数などの条件に応じて、待機・接近の禁止・速度の倍率・発話の抑制などの方針を与える。
behavior_tree.py / behavior_tree_store.py behavior tree。ルール表を包む形の判断ロジック。安全層は木の外に固定し、木が壊れてもルール表へ戻る。
crowd_monitor.py 混雑判定。LiDARの入口付近の点群密度から、混雑/閑散を判定する。
person_target_detector.py 人物の検出。LiDARで人物の候補を確定し、接近の目標にする。
wheel_odom_node.py オドメトリ。ESP32のエンコーダ値(/wheel_ticks)から、走行距離・向き(/odom)を計算する。
nav2_goal_router.py 目的地の中継。ダッシュボードや行動の判断が出した目的地を、Nav2へ送る。走行可能範囲の外や、立入禁止エリアへの目的地は止める。
frontier_explorer.py 自立探索。未探索の領域へ向かって、自動で地図を広げる。
map_pins.py 地図のピン。地図上に登録した場所(ピン)を管理し、行先に指定できるようにする。
nav_speed.py 走行速度の管理。Nav2の最高速度や自律走行の速度を、ダッシュボードの設定に合わせて切り替える。
survey_monitor.py / survey_admin_proxy.py アンケート回答中の停止。腹部ディスプレイでアンケートに回答している間と、保存が完了するまで、ロボットを動かさない(探索中は無効)。ラズパイの管理APIへの中継も行う。
inventory_manager.py 残数管理。メニューごとの残数・消費の偏りを計算し、宣伝対象のメニューを決める。
announce_events.py / announce_node.py 状況アナウンス(ROS側)。探索中などの状況を判定し、アナウンスの要求を音声側へ送る。
dashboard_common.py / full_dashboard_node.py 管理画面(ダッシュボード)。PC用(8090)・スマホ用(8095)・Web UI(8080)の画面とAPIを提供する。緊急停止・速度・地図・行動の設定を持つ。
roles.py / accounts.py / ephemeral_overrides.py アカウントと権限。管理者(TL)・弱いアカウント(operator)・guestの権限を管理する。許可リストにない操作は、既定で拒否する。operatorの変更は、再起動で元に戻す。
system_shutdown.py プログラム終了。管理画面のボタンから、モーターを止めたうえで、ロボット関連のプログラムを順番に止める(OSの電源は切らない)。
nokosahen.yaml / nav2_params_jetson.yaml / slam_toolbox_online_async.yaml 設定ファイル。システム全体のパラメータ、Nav2(走行・障害物回避)のパラメータ、SLAMのパラメータ。
persistent_base.launch.py ほか(launch/) 起動ファイル。常駐させるノード群(LiDAR、足回り通信、オドメトリ、管理画面など)と、地図作成・自己位置推定の起動を定義する。
start_all.sh / stop_everything.sh / shutdown_all.sh(scripts/) 起動・停止スクリプト。1つのコマンドで、状態(manual・full・nav_test)を指定して起動する。停止は、全停止と、管理画面からの終了に分かれる。

頭脳プログラムは「状況の認識」「行動の判断」「移動の計画」「操作画面の提供」を担う上位ユニットである。LiDARとカメラの情報から、食堂の混雑や人物を認識し、Nav2に目的地を与えて走行する。足回りは、ESP32へ速度指令を送るだけで、モーターを直接制御しない。

3.2.1. 頭脳システムアーキテクチャ

プログラムは階層構造を採用しており、安全に関わる判断が、他の判断より常に優先される設計となっている。

安全層 (behavior_director の固定の分岐)
緊急停止・手動運転・アンケート回答中・人への近接・走行可能範囲の外・立入禁止エリア・カメラ障害物・地図作成中の各状況で、動きを止める。この層は、behavior treeやルール表からは変更できない。
判断層 (ルール表・behavior tree)
時間帯や混雑に応じて、待機・接近・見回し・発話の方針を決める。
移動層 (Nav2, SLAM, nav2_goal_router)
経路を計画して、障害物を避けながら走行する。地図の作成と自己位置の推定を行う。
認識層 (crowd_monitor, person_target_detector, 決済横カメラ, タブレットOCR)
混雑・人物・購入数を、センサの値から求める。
提示層 (管理画面, voice_bridge, 腹部ディスプレイ)
人への発話・表示と、操作者への画面を提供する。

3.2.2. 頭脳詳細機能

混雑判定と人物の検出
自動走行 (Nav2)
Nav2で経路を計画し、障害物を避けながら走行する。
自立探索 (frontier_explorer)
未探索の領域へ向かって、自動で地図を広げる。探索中は、お客さんがいない前提で、画面に触れられても止まらない(アンケートによる停止を無効にしている)。走行可能範囲を制限した場合は、範囲内の人物へ向きを変えて、話しかける。
behavior tree と時間帯・状況ルール
管理画面とアカウント
停止・終了の操作
残数管理
決済横カメラの人物通過、またはタブレットOCRによる決済端末の表示から、購入数を求め、メニューごとの残数と消費の偏りを計算する。残数の少ないメニューは、宣伝の対象になる。

3.3. Jetson 2台目(音声)

表5 Jetson 2台目 音声モジュール一覧

ファイル名 説明
voice_bridge.py 音声出力サービス(メイン)。発話の文章をVOICEVOXで音声に合成し、スピーカーとBGMを再生する。文章の生成にはOllamaを用いる。音量・音声の全体ON/OFFの設定を受け付ける。1台目とloopbackからの接続だけを許可する。
announce_engine.py 状況アナウンスの再生。探索中などの繰り返しの発話を、あらかじめ合成して、一定間隔で繰り返し再生する(内容・ON/OFF・音量・間隔を設定できる)。
persona_prompt.txt 発話のキャラクター設定。Ollamaへ渡す指示文。
requirements.txt 依存ライブラリ一覧。
tests/ テスト。繰り返し再生の動作と、計測値のテスト。
jetson2_setup/(scripts/) 2台目のセットアップ。2台目の設定用スクリプト一式。
nokosahen_voice(ROS側ノード) 橋渡し。1台目で動き、/nokosahen/announce_text を、2台目のvoice_bridgeへ送る薄いノード。

音量は、発話とBGMで個別に、0〜5倍の範囲で変えられる。2台目は、1台目から、有線LAN(ハブ経由、10.10.10.3)で接続する。

3.4. Raspberry Pi(腹部ディスプレイ)

表6 Raspberry Pi 腹部ディスプレイモジュール一覧

ファイル名 説明
start_kiosk.sh 画面の起動。ブラウザ(キオスク)を全画面で起動し、表示モードに従って、表示するページを切り替える。受信サーバと管理APIも、常時起動する。
switch_kiosk.sh 表示モードの切替。お客さん向け・アンケート・OCRテストを切り替える。回答の件数も表示する。
mirs_robot_survey.html アンケート画面。お客さんが回答する画面。
receiver.py アンケートの受信サーバ。回答を保存し、回答中・保存完了などの状態を管理する。
kiosk_admin.py 管理API。1台目のダッシュボードから、表示モードの切替・回答件数の取得・模擬POSの数字の変更を受け付ける(呼び出し元は、1台目のみ)。

アンケートに回答している間と、保存が完了するまで、ロボットを動かさない。この停止は、1台目の survey_monitor が、ラズパイの状態を監視して行う(表4)。

3.5. タブレットOCR(Jetson 1台目上)

表7 タブレットOCRモジュール一覧

ファイル名 説明
tablet_ocr_reader.py 読み取り(メイン)。Webカメラの画像から、決済端末の画面の数字を認識し、購入数を求める。
ocr_camera_quality.py カメラ画質の管理。ピントの評価と自動調整、画質の向上処理を行う。デモ用(フレームレート優先)と本番用(最高画質)のプロファイルを切り替える。
train_digit_model.py 数字認識モデルの学習。
digit_model/ 学習済みモデル。Kerasのモデルと、量子化したモデル、Edge TPU向けのモデル。
coral_tpu_retry/ Coral(Edge TPU)のサーバー。Dockerコンテナ内で動かすサーバー(server.py)と、起動・確認のスクリプト。
tablet_ocr_config.example.json 設定の雛形。カメラ・認証・回転角などの設定。

カメラの向きを実機に合わせた、数字の認識の確認は未実施。

4. フローチャート

フローチャートの図は作成中である。流れを、以下に文章で示す。

4.1. 足回りの流れ

  1. 入力: 20msごとに、エンコーダのパルス数と、最後に受信した速度指令(/cmd_vel)、緊急停止入力を取得する。
  2. 判断: ウォッチドッグと緊急停止を確認し、停止すべきなら目標を0にする。それ以外は、速度指令に加減速の整形をかけて、左右の車輪の目標速度へ変換する。
  3. 計算: 目標速度を実現するためのモーターへの指令値(PWM値)をPID演算で算出する。
  4. 出力: モータードライバへPWM信号を出力し、エンコーダ値・緊急停止状態をJetsonへ送信する。

足回りプログラムは、独立した動作モードを持たず、次の4つの状態だけを持つ。

通常走行
速度指令に従って、PIDで走行する。
ウォッチドッグ停止
速度指令が500ms途絶えると、速度0へ戻る。指令が再開すると、通常走行へ戻る。
緊急停止
GPIO34の入力が作動すると、加減速の整形を通さずに0にする(物理スイッチ未配線のため、現在は無効)。
自己復旧
通信の失敗が続くと、自己リセットして初期化し直す。

4.2. 頭脳の流れ

  1. 入力: LiDAR(/scan)、オドメトリ(/odom)、決済横カメラ、タブレットOCR、ダッシュボードの操作、アンケートの状態を取得する。
  2. 認識: 混雑判定と人物の検出を行い、残数を計算する。
  3. 判断: 安全層で停止条件を確認し、問題がなければ、ルール表・behavior treeに従って、行動(接近・見回し・待機・移動・発話)を決める(behavior_director)。
  4. 計画: 目的地をNav2へ送り、経路を計画する。直接の速度指令が必要な動作(見回し・接近)は、速度指令(/cmd_vel)を直接出す。
  5. 出力: 速度指令をESP32へ送り、発話と表示をvoice_bridge・腹部ディスプレイへ送る。

behavior_directorの主なモードを次に示す。上から順に、優先度が高い。

ESTOP_HOLD (緊急停止)
ソフト緊急停止、または物理の緊急停止が作動している間は、すべての動きを止める。
MANUAL_OVERRIDE (手動運転)
手動運転中は、自律的な目的地の送信を止める。ダッシュボードの「自律に戻す」操作で復帰する。
SURVEY_ACTIVE_HOLD (アンケート回答中)
腹部ディスプレイでアンケートに回答している間と、保存が完了するまで、動かない(探索中は無効)。
NEAR_PERSON_HOLD / OUT_OF_BOUNDS_HOLD / KEEPOUT_ZONE_HOLD / CAMERA_OBSTACLE_HOLD (各種の安全停止)
人に近づきすぎたとき、走行可能範囲の外に出たとき、立入禁止エリアに入ったとき、カメラが障害物を検知したときに、止まる。
MAPPING_ACTIVE_HOLD (地図作成中)
地図を作成している間は、自律的な走行をしない。
CROWD_SCAN / CROWD_APPROACH (見回し・群衆への接近)
人物を確定できないとき、その場で見回し、人の多い方向へ前進する。
APPROACH_PERSON / APPROACH_ARRIVED (人物への接近)
人物を確定したら、その方向へ接近し、到着後は発話が終わる頃合いまで、その場に留まる。
RETURN_HOME / IDLE_WIGGLE (帰還・待機)
接近のあとにホームへ戻る。人がいないときは、待機の揺動(演出)を行う。

5. 別パートへのリンク

MIRS2603の別パートの詳細設計書へのリンクを以下に示す。メカニクス詳細設計書とエレクトロニクス詳細設計書のリンクは、決まり次第追記する(作成中)。




MIRSデータベース