Slide 1

Slide 1 text

0 Dynamic Vehicle Routing のシミュレーションを Streamlitで作ってみた 2024-03-15 第82回NearMe技術勉強会 Kenji Hosoda

Slide 2

Slide 2 text

1 ● ⾃動運転キャッチアップしたいな ○ 「Autoware :⾃動運転ソフトウェア⼊⾨」を読む ○ 要素技術多すぎて、勉強会ネタとしてはまとめきれない。。 ● 要素技術の⼀つであるROSにフォーカスするか ● ROSで複数⾞両のルーティングのシミュレーションやってるのないかな ○ あった ■ https://github.com/shineyruan/vehicle-routing-ros2?tab=readme-ov-file ○ 元のPython実装もあった ■ https://github.com/lb-robotics/python-vehicle-routing ○ 元の論⽂もあった ■ “Dynamic Vehicle Routing for Robotic Systems”(Bullo et al., 2011) ■ https://stanfordasl.github.io/wp-content/papercite-data/pdf/Bullo.Fraz zoli.ea.IEEEProc11.pdf ● ⾯⽩いのでやっぱりDynamic Vehicle Routingにフォーカス ● こういうシミュレーション基盤も作りたかったな ○ Streamlitでマルチスレッド処理できるかな? ○ https://zenn.dev/ohtaman/articles/streamlit_start_stop ○ いけそうなので作ってみるか (勉強会ネタのチョイスの紆余曲折)

Slide 3

Slide 3 text

2 Dynamic Vehicle Routingについて ● 動的に変わる環境 ○ 確率的に出現する注⽂/タスク ● 複数⾞両/ロボットによるアサイン ○ ⾃律的な最適化 ○ 協調的なコントロール ● ポリシーの違いによってパフォーマンスは⼤きく異なる ● 協調的なコントロールは必須 ● 注⽂の確率分布に応じて⾞両をバランスよく配置するこ とも重要 ● 注⽂数/⾞両数のバランスの違いによってもパフォーマン スは異なる ○ 注⽂数が多い時は、TSPが有効 https://github.com/lb-robotics/python-vehicle-routing

Slide 4

Slide 4 text

3 シミュレータ作ってみた こちらからダウンロードして実⾏ https://gist.github.com/kenji4569/8da401b4d1bbfe2b0b6be41ac6d3d1a2 以下のコマンドを実行 pip install streamlit numpy scipy pandas altair readerwriterlock streamlit run app.py (wandb利用の場合は以下も実行 ) wandb login pip install wandb ブラウザでStreamlitアプリが立ち上がったら “Start”ボタンを押下

Slide 5

Slide 5 text

4 マルチスレッドについて class Vehicle(threading.Thread): def __init__(self, events: Events, location: Location, **kwargs): super().__init__(**kwargs) self.done = threading.Event() ... def run(self): while not self.done.wait(0): time.sleep(TIME_STEP) self._move() class Timer(threading.Thread): def __init__(self, events: Events, **kwargs): super().__init__(**kwargs) self.done = threading.Event() ... def run(self): while not self.done.wait(0): time.sleep(TIME_STEP) self.elapsed_time += TIME_STEP ● Timerのスレッド ● Vehicle x nのスレッド 各スレッドが並列動く (Streamlitではグローバルにキャッシュでスレッドのオブジェクトを保持する必要あり) @st.cache_resource def get_root_manager(): return RootManager()

Slide 6

Slide 6 text

5 マルチスレッドの注意点 ● ロック処理をしないとどうなるか def _move(self): diff = self.target_location - self.location diff_norm = np.linalg.norm(diff) if diff_norm < self.pickup_threshold: self.location = self.target_location self._pickup_demand() else: movement = diff * (self.speed / diff_norm) self.location = self.location + TIME_STEP * movement def _pickup_demand(self): if not self.target_demand: return target_demand = self.target_demand with self.lock.gen_wlock(): if not target_demand.picked_up: target_demand.picked_up = True self.events.append( Event( "pickup_demand", {"demand_uid": target_demand.uid, "vehicle_uid": self.uid}, ) ) ここでロック ロックしないとこの値が 書き変わる可能性がある ピックアップイベントが 複数回記録される可能性がある 距離が近くなったら ピックアップ

Slide 7

Slide 7 text

6 イベントの記録 ● グローバルなイベントを記録 ○ (ROSのrosbagに倣った) ● イベントを集計 ● 時系列のメトリクスを算出 ○ Streamlitで表⽰ ● WandBに連携 ○ strategy毎の⽐較がしやすい ○ 右図が⼀例

Slide 8

Slide 8 text

7 Thank you