myCobotとOAK-D OpenCV DepthAIカメラで常に目の前で動画を楽しめるスマホアームを作ってみた!

12月 4, 2021

YouTubeやNetflixの登場で寝ながらスマホを見るようになりました. しかしずっとスマホを手で持っていると疲れてしまいます. 今回は手でスマホを持たなくても, 目の前に適度な距離感で位置調整してくれる動くスマホアームを作ってみました. ぜひお試しを!

準備したもの

Elephant Robotics社製のロボットアームを今回は使用しました. 他製品と比べて安価で, 初心者としても比較的手が出しやすいものだと思います.


myCobot 280 Pi- 6 DOF Collaborative Robot (Raspberry Pi version)

顔に追従するためのカメラにはOAK-D OpenCV DepthAIカメラを採用しました. 単なる映像のキャプチャだけでなく, 顔認識機能に必要なニューラルネットの演算を補助してくれるので, マイコンにGPUがついていなくても高速に顔認識することができます.

どんなもの?

常にディスプレイを目の前に適度な距離感で位置調整するスマホアームです. 主にOAK-Dカメラとロボットアーム"myCobot"で構成されています. OAK-Dカメラは映像はもちろんのこと, 深度情報も取得することができ, カメラから顔までの距離を割り出してくれます. myCobotは回転軸が6軸あるロボットアームで多様な動作を作り出すことができます. OAK-Dカメラを通して得られる映像から顔の3次元位置を割り出し, myCobotで目の前までスマホディスプレイを送り届けています. このようにして手でスマホを持たなくても動画を楽しめるようになります.

myCobotへOAK-Dカメラとスマホの取り付け

myCobotの先端部にはM2.6のネジ穴が4つついています. スマホを入れるケースを3Dプリントし, このネジ穴を利用してそのケースをmyCobotへ取り付け, スマホを固定していきます.

一方でOAK-Dカメラには1/4インチのねじ穴がついています. 3Dプリントするケースに1/4インチねじ用の穴も開けておき, カメラが固定できるようにしておきます.

参考に今回用いたSTLデータを置いておきます.

ロボットアームの動作

  • X方向の動き : J1軸の回転
  • Y方向の動き : J4軸の回転
  • Z方向の動き : J2とJ3軸の回転(J2とJ3は反対方向に回転)

J2とJ3軸を用いて深度方向の動きをさせます. J2だけ動かすとY方向にも影響するので, J3をJ2軸とは反対方向に同じ量の回転をさせ, 影響を抑えています.

3D Face Tracking

XY平面上での顔追従

OAK-Dカメラから得られる画像に対して顔検出することで, カメラフレーム上の顔の座標(x, y)を取得することができます.

OAK-Dカメラのフレームの中心座標を目標値, 顔認識で得られた顔の座標(x, y)をフィードバック値としてPID制御しています.

深度方向(Z方向)の顔追従

OAK-Dカメラはステレオカメラが搭載されているので面だけでなく深度方向の顔座標zを取得することができます. 顔とディスプレイが近すぎず, 遠すぎない距離を目標値, ステレオカメラで計測した顔の座標(z)をフィードバック値としてPID制御しています.

myCobotとOAKカメラ

OAKカメラとmyCobot付属のRaspberryPiをUSB接続します.
OAKカメラが目標値である顔の座標を割り出し, myCobot付属のRaspberryPiがその座標に合わせてPID制御してカメラの向きを変えています.

セットアップ

myCobot付属のRaspberryPiに対して環境構築していきます.

myCobot

myCobotのRaspberryPiバージョンでは電源を入れれば, すぐに使用することができる状態になっています.
ロボットアームはpythonで動作させることができ, 公式でもサポートされています.

# test
from pymycobot.mycobot import MyCobot

mycobot = MyCobot('/dev/ttyUSB0')
# 直立させる
mycobot.send_angles([0,0,0,0,0,0], 80)

OAK-D OpenCV DepthAIカメラ

OAK-Dカメラを動かすdepthaiというライブラリをインストールします.

# install dependency
sudo curl -fL http://docs.luxonis.com/_static/install_dependencies.sh | bash

# get sources
git clone https://github.com/luxonis/depthai.git

# install depthai
python3 install_requirements.py

デモ

実行環境が整ったらデモを動かしてみてください. 一定距離を保ちつつ, カメラが顔をトラッキングすればうまくいっています.

# get demo sources
git clone https://github.com/tech-life-hacking/depthai.git

# execute demo
python3 depthai_demo.py

PIDの調整

myCobotの動きが不安定なときはPID値を調整してみてください.

# settings
PID_control.PID(P値, I値, D値)
pidX.setTargetPosition(フレーム上の点の位置(X方向):範囲0-1, 0.5が中央)
pidY.setTargetPosition(フレーム上の点の位置(Y方向):範囲0-1, 0.5が中央)
pidZ.setTargetPosition(カメラと顔の距離(m), 0.5m = 50cm)

# default
pidX = PID_control.PID(10, 10, 3.75)
pidY = PID_control.PID(6.5, 5, 2.5)
pidZ = PID_control.PID(50, 30, 20)
pidX.setTargetPosition(0.5)
pidY.setTargetPosition(0.5)
pidZ.setTargetPosition(0.5)

目標値決め

myCobotがカメラをどこに向けるかの目標値を下のコードで決めています. nnData[0]はOAK-Dカメラが検出した顔を囲むBoundingBoxの四隅の座標を示してくれます. その四隅の座標の和を2で割ると顔を囲むBoundingBoxの中心点を割り出してくれます. spatialCoordinates.zはカメラと顔の距離の計測結果を返してくれるメソッドです.

x = (self._nnData[0].xmin + self._nnData[0].xmax) / 2
y = (self._nnData[0].ymin + self._nnData[0].ymax) / 2
z = int(self._nnData[0].spatialCoordinates.z) / 1000

おわりに

今回はOAK-Dカメラでの顔認識と複雑な動きができるロボットアームを用いて顔のトラッキングをしてみました.
人間の動きをコンピュータビジョンで捉え, それにしたがってロボットアームを動作させると, すごく多様な動きをするということがわかると思います. みなさんの開発の参考になると幸いです.