🛸

PyBulletでドローンを飛ばす その4

2022/03/19に公開

前回で終わりと言いつつ追加・・・
キーボード入力でドローンをラジコンのように操作できるようにしてみました。

前回の記事
https://zenn.dev/taront/articles/b2f896ff8dd5cf

今回追加したコード
https://github.com/toritamantaro/pybullet-drone-self-study

1.キーボードの入力判定

入力判定については、ゲームみたいなものを作ったことが無いのでやり方が良くわかりません。以下のようにビット演算的に入力判定してみました。きっともっと良い方法があると思います。

./util/external_input.py

def key_code_list2binary(code_list: List[int]):
    ''' key2binary map
    up          down        ccw         cw          left        right       back        forward
    d           c           z           x           h           k           j           u
    0b1000_0000 0b0100_0000 0b0010_0000 0b0001_0000 0b0000_1000 0b0000_0100 0b0000_0010 0b0000_0001
    128          64          32          16          8           4           2           1    
    '''
    key2binary_map = {
        'd': 0b1000_0000,  # up
        'c': 0b0100_0000,  # down
        'z': 0b0010_0000,  # ccw
        'x': 0b0001_0000,  # cw
        'h': 0b0000_1000,  # left
        'k': 0b0000_0100,  # right
        'j': 0b0000_0010,  # back
        'u': 0b0000_0001,  # forward
    }
    input_keys = [chr(k) for k in code_list]
    input_keys_bin = [key2binary_map.get(k, 0) for k in input_keys]
    return sum(input_keys_bin)

2.キーボード入力によるドローン制御

キー入力は、d,cで上昇・下降。zxで左右回転、hkで左右移動、juが前後移動に対応しています。変なキー割り当てになっているのは、PyBulletの標準のキー操作との競合を避けるためです。ご了承ください。
実装の中身は./util/external_input.pyをご確認ください。具体的には、キーボードの入力から(シミュレーションの)数ステップ先の目標位置を算出し、その目標目掛けてPID制御を行うをいうことを繰り返しています。

./b04_keyin_operation.pyを実行すると、キー入力によるドローン操作が可能です。
動かしてみるとわかりますが、少し無理な操作を行うとバランスを崩して墜落してしまいます。
多分、実際のドローンラジコンなどとは制御方法が違うのだと思います。本物はどうなっているのでしょうか?もっと機敏に動かせるようにしてみたいものです。(←本来はそのための強化学習ですよね...)

動画
https://www.youtube.com/watch?v=-0waWMDrlg8

[補足]
今回、ドローン視点のカメラを追加したのですが、環境によってはそのカメラの負荷によってシミュレーション速度が著しく低下する場合があるようです。その際は、以下の対策を実施してみてください。

  • ./b04_keyin_operation.pyの30行目辺りで指定しているカメラの解像度を下げる
  • それでもだめなら、./b04_keyin_operation.pyの100行目辺りにあるmy_camera.cam_capture()の行をコメントアウトする
./b04_keyin_operation.py
            ...
	    
    # Initialize the camera.
    my_camera = BulletCameraDevice(
        # res_w=640,
        # res_h=480,
	res_w=120,
	res_h=90,
        z_near=0.01,
        z_far=10.0,
        fov_w=50,
    )
            ...
	    
            # Cam capture.
            cam_pos = kis[0].pos + np.array([0, 0, 0.02])
            cam_quat = kis[0].quat
            view_mat = compute_view_matrix_from_cam_location(cam_pos=cam_pos, cam_quat=cam_quat, )
	    # 解像度を下げてもダメなら↓をコメントアウトする
            _, _, _ = my_camera.cam_capture(view_mat)  
	    
	    ...

3.TODO

終わり終わりと言いながら今後の課題を記述

  • OpenAI Gymへの対応
  • Rayの分散並列処理によるマルチエージェントの対応

オリジナルのリポジトリの実装では、PyBulletOpenAI GymStableBaselines3Rayへの対応を「継承」を繰り返すことで実現していました。これは実装する上では楽ですが、プログラムを見通す際に少々複雑で、改修などが難しくなってしまっているように思います。そこで、今回は「継承」ではなく「委譲」をベースとして強化学習環境を構築することを前提にトレースしています。
現時点の問題点として、「委譲」ベースで再構築していく際に、Rayによる並列化において上手くオリジナルのプログラムを再現できない場面が出てきました。この辺がクリアできた際に、また追記するかもしれません。

Discussion