VOOZH about

URL: https://qiita.com/kanetugu2018/items/c292ea92ef087bc5e68a

⇱ Python使ってUnity上の箱庭ロボットのカメラデータを取得してみよう #Python - Qiita


👁 Image
8

Go to list of users who liked

10

Share on X(Twitter)

Share on Facebook

Add to Hatena Bookmark

More than 3 years have passed since last update.

@kanetugu2018(Mori Takashi)in👁 Image
TOPPERSプロジェクト

Python使ってUnity上の箱庭ロボットのカメラデータを取得してみよう

8
Last updated at Posted at 2023-03-18

はじめに

これ、Turtlebot3 の 3D モデルを Unity 上に取り込み、モーター、センサ系を再現したものです。

👁 image.png

この Unity 上のロボットを Python 使って制御する方法をご紹介します。

仕組み

このロボットをPythonでコントロールするためのプラットフォームとして、TOPPERS/箱庭を利用します。
最近ですと、以下の記事で EV3 というロボットをPython 使って強化学習した実績があるものです。

ロボットの部品群

モーター

差動モーターで駆動します。両輪それぞれにモーターが割り当てられており、モーターの回転速度差で直進、右曲がり、左曲がりができます。

👁 image.png

レーザスキャナ

2D のレーザスキャナです。360度(1度単位)の障害物検出ができます。

👁 image.png

カメラセンサ

前方にカメラセンサを付けています。
640×480 のカメラデータが取れます。

👁 image.png

ロボットの通信データ

ロボットの通信データは、ROS2のトピックデータ型で定義しています。
(cmd_vel 以外はすべてセンサデータです)

ROSトピックデータ型 名前 サイズ[単位:バイト] channel_id
geometry_msgs/Twist cmd_vel 48 0
sensor_msgs/JointState joint_states 440 1
sensor_msgs/Imu imu 432 2
nav_msgs/Odometry odom 944 3
tf2_msgs/TFMessage tf 320 4
sensor_msgs/Image image 1,024,280 5
sensor_msgs/CompressedImage image/compressed 102,664 6
sensor_msgs/CameraInfo camera_info 580 7
sensor_msgs/LaserScan scan 3,044 8

Python側のプログラム

通信データ

Python側のプログラムでは、これらの通信データは、dictionary形式で読めます。

モーターコントロール(cmd_vel)

linearのxが速度で、angularのzが回転方向です。
それ以外は無視されます。

linear:
 x: 0
 y: 0
 z: 0
angular:
 x: 0
 y: 0
 z: 0

カメラデータ(image/compressed)

data の中にjpeg形式のデータが格納されています。

header:
 stamp:
 sec: 1678519485
 nanosec: 759772000
 frame_id: camera_link
format: jpeg
data: <生のバイナリデータ>

レーザスキャナ(scan)

ranges の中にスキャンした結果が配列として360個格納されています。

header:
 stamp:
 sec: 1678519496
 nanosec: 958531000
 frame_id: base_scan
angle_min: 0
angle_max: 6.2657318115234375
angle_increment: 0.01745329238474369
time_increment: 2.9880000511184335e-05
scan_time: 0
range_min: 0.11999999731779099
range_max: 3.5
ranges:
 - 3.5
 :(全部で360個あります)

通信ライブラリ

Unity上のTurtlebot3を制御するためのプログラムは以下の通りです。

class HakoRoboModelTb3:
 def __init__(self, hako):
 self.hako = hako
 self.hako.create_pdu_channel(0, 48, 'Twist')
 self.hako.subscribe_pdu_channel(1, 440, 'JointState')
 self.hako.subscribe_pdu_channel(2, 432, 'Imu')
 self.hako.subscribe_pdu_channel(3, 944, 'Odometry')
 self.hako.subscribe_pdu_channel(4, 320, 'TFMessage')
 self.hako.subscribe_pdu_channel(5, 1024280, 'Image')
 self.hako.subscribe_pdu_channel(6, 102664, 'CompressedImage')
 self.hako.subscribe_pdu_channel(7, 580, 'CameraInfo')
 self.hako.subscribe_pdu_channel(8, 3044, 'LaserScan')
 self.binary_data = bytearray(48)
 self.actions = { 0: binary_reader.binary_read(self.hako.offmap, 'Twist', self.binary_data) }

 def delta_usec(self):
 #20msec
 return 20000

 def camera_data(self, sensors):
 return (sensors[6]['data'])

 def laser_scan(self, sensors):
 return (sensors[8]['ranges'])

 def get_forward_distance(self, scan_datas):
 min1 = min(scan_datas[0:15])
 min2 = min(scan_datas[345:359])
 return min(min1, min2)
 
 def get_right_distance(self, scan_datas):
 return min(scan_datas[60:120])
 
 def foward(self, speed):
 self.actions[0]['linear']['x'] = speed
 
 def turn(self, speed):
 self.actions[0]['angular']['z'] = speed
 
 def stop(self):
 self.actions[0]['linear']['x'] = 0.0
 self.actions[0]['angular']['z'] = 0.0

 def step(self):
 for channel_id in self.actions:
 self.hako.write_pdu(channel_id, self.actions[channel_id])

上記ライブラリを使ったサンプルプログラムは以下の通りです。

#!/usr/bin/python
# -*- coding: utf-8 -*-
import json
import sys
from hako_binary import offset_map
from hako_binary import binary_writer
from hako_binary import binary_reader
import hako_env
import hako
import time
import signal
import hako_robomodel_tb3 as tb3

def handler(signum, frame):
 print(f'SIGNAL(signum={signum})')
 sys.exit(0)
 
print("START TB3 TEST")

# signal.SIGALRMのシグナルハンドラを登録
signal.signal(signal.SIGINT, handler)

#create hakoniwa env
env = hako_env.make("base_practice_1", "tb3")
print("WAIT START:")
env.hako.wait_event(hako.HakoEvent['START'])
print("WAIT RUNNING:")
env.hako.wait_state(hako.HakoState['RUNNING'])
print("GO:")

#do simulation
robo = env.robo()
for episode in range(1):
 total_time = 0
 done = False
 state = 0
 total_reward = 0
 #100secs
 while not done and total_time < 4000:
 sensors = env.hako.execute()
 
 img = env.robo().camera_data(sensors)
 with open("camera.jpg" , 'bw') as f:
 f.write(img)
 
 scan_datas = env.robo().laser_scan(sensors)
 if env.robo().get_forward_distance(scan_datas) >= 0.2:
 env.robo().foward(0.5)
 env.robo().turn(0.0)
 else:
 env.robo().foward(0.0)
 env.robo().turn(-0.5)
 env.robo().step() 
 total_time = total_time + 1
 env.reset()
print("END")
env.reset()
sys.exit(0)

カメラデータは、上記プログラムのここで取得してファイルに保存しています。

 img = env.robo().camera_data(sensors)
 with open("camera.jpg" , 'bw') as f:
 f.write(img)

実際に保存したカメラデータはこんな感じです。

👁 camera.jpg

Unityのセットアップ手順

基本的なインストール手順は前回の記事の通りですが、Unity環境のセットアップのクローン対象リポジトリが異なります。

git clone -b unity-asset-for-tb3 --recursive https://github.com/toppers/hakoniwa-ros2sim.git

Unityエディタを起動後、プロジェクトビューから「Configurator」というシーンをダブルクリックします。

👁 image.png

起動すると、下図のようになります。

👁 image.png

ヒエラルキービューを開き、「Robot」内にあるオブジェクトを「delete」キーで削除し、以下のTurtlebot3モデル(MiconTB3RoboModel)を配置します。

👁 image.png

MiconTB3RoboModelは、プロジェクトビューの Assets/Resources/Hakoniwa/Robots 配下にあります。

配置が終わったら、メニューから環境構成を外部出力します。

👁 image.png

出力完了後、以下のコマンドで箱庭環境にインストールします。

bash hako-install.bash opt all

そして、Unityのシミュレーション用のシーンとして、「Toppers_Course」を起動します。

👁 image.png

Python側のセットアップ手順

Python 側のセットアップ手順は、前回の記事の通りです。

ただし、Turtlebot3を動かすには、以下のファイルを変更する必要があります。

  • workspace/runtime/asset_def.txt

変更前:dev/ai/ai_qtable.py
変更後:dev/ai/test_tb3-01.py:mqtt

test_tb3.py は、以下にあります。

シミュレーション実行方法

hakoniwa-base 上で、以下のように docker コンテナを起動します。

$ bash docker/run.bash runtime
ASSET_DEF=asset_def.txt
PYTHON_PROG=dev/ai/test_tb3.py
PDU_COMM=mqtt
INFO: ACTIVATING MOSQUITTO
[13703.343514]~DLT~ 13~INFO ~FIFO /tmp/dlt cannot be opened. Retrying later...
INFO: ACTIVATING HAKO-MASTER
OPEN RECIEVER UDP PORT=172.30.224.33:54001
OPEN SENDER UDP PORT=172.30.224.33:54002
mqtt_url=mqtt://172.30.224.33:1883
PUBLISHER Connecting to the MQTT server...
PUBLISHER CONNECTED to the MQTT server...
delta_msec = 20
max_delay_msec = 100
INFO: shmget() key=255 size=12160
Server Start: 172.30.224.33:50051
INFO: ACTIVATING :dev/ai/test_tb3.py
START TB3 TEST
create_channel: id=0 size=48
WAIT START:

この状態で、Unityのシミュレーションを開始します。

👁 image.png

この状態で、「開始」ボタンをクリックすると動き出します。

デモ

上記の手順で実行したときのデモをお見せします。

カメラデータは、ローカルのファイルシステム上に保存されていますので、そのデータをWebブラウザ上で眺めています。

8

Go to list of users who liked

10
0

Go to list of comments

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8

Go to list of users who liked

10