[ロボ実験記録] ロボットアームと電動ピペットで水を移動するまで
概要
以下のシステムを作るまでのまとめです。
ロボットアーム
Dobot magicianという教育用のロボットアームを使いました。15万円くらいです。
Pythonで制御するプログラムにしました。
ロボット制御で有名なROSは使っていません(使いこなせていません)。
制御プログラムは以下の記事で公開しています。
アームの先端には、3Dプリンタで作成したピペットアームのホルダを装着しました。
突貫工事で作ったので、クオリティが低いです。そのうち、改造予定です。
fusion360のデータはこちら。
ピペット
Pipetty proの特注品を使いました。
USBまたはBluetooth通信で制御が可能です。
制御プログラムについては、以下の記事でまとめています。
制御プログラム
初期化関連
#dobot magicianの初期化
from DobotDriver.DobotWrapper import DobotWrapper
dobot=DobotWrapper("COM3")
dobot.initiate()
#pipettyの初期化
from pipetty.Pipetty import Pipetty
pipetty = Pipetty()
#通信確認と、タイムアウト時間の設定
pipetty.check_connect()
pipetty.set_timeout()
マウス+キーボードでシステムを制御してみます。
はじめは、AIやアルゴリズムではなく人間がロボットアームを制御することで、ロボットの気持ちを知ることができます。
import tkinter as tk
start_x, start_y = 0, 0
dobot_x, dobot_y, dobot_z = 0, 0, 0
def on_drag_start(event):
global start_x, start_y, dobot_x, dobot_y, dobot_z
start_x, start_y = event.x, event.y
dobot_x, dobot_y, dobot_z ,_= dobot.get_position()
def on_drag(event):
global start_x, start_y, dobot_x, dobot_y, dobot_z
dx, dy = event.x - start_x, event.y - start_y
dx=dx/5
dy=dy/5
dobot.move_arm(dobot_x-dx, dobot_y+dy, dobot_z, 0)
#start_x, start_y = event.x, event.y
def on_mousewheel(event):
global dobot_x, dobot_y, dobot_z
dobot_x, dobot_y, dobot_z ,_= dobot.get_position()
delta = event.delta/10 # normalize delta value to -1 or 1
dobot_z -= delta
dobot.move_arm(dobot_x, dobot_y, dobot_z, 0)
def on_keypress(event):
global dobot_x, dobot_y, dobot_z
dobot_x, dobot_y, dobot_z ,_= dobot.get_position()
delta = 5
if event.keysym == 'Up':
dobot_z += delta
dobot.move_arm(dobot_x, dobot_y, dobot_z, 0)
#pipetty.vacuum(10)
elif event.keysym == 'Down':
dobot_z -= delta
dobot.move_arm(dobot_x, dobot_y, dobot_z, 0)
elif event.keysym=="Left":
pipetty.vacuum(10)
elif event.keysym=="Right":
pipetty.home()
root.unbind('<KeyPress>') # Unbind key press event after the first detection
def on_keyrelease(event):
root.bind('<KeyPress>', on_keypress) # Re-bind key press event after key release
root = tk.Tk()
frame = tk.Frame(root, width=500, height=500)
frame.bind('<Button-1>', on_drag_start) # Button-1 is the event when left mouse button is pressed
frame.bind('<B1-Motion>', on_drag) # B1-Motion is the event when left mouse button is held down and mouse is moved
frame.bind('<MouseWheel>', on_mousewheel)
frame.pack()
root.bind('<Key>', on_keypress)
root.bind('<KeyRelease>', on_keyrelease)
root.mainloop()
このコードを実行すると、ウィンドウが生成されます。
その上でマウスをドラッグすると、呼応してアームのXY座標が変化します。
カーソルキーの上、下で、アームの高さを上下できます
カーソルキーの左を押すと100 uLの吸引、右を押すと全て吐き出します
自動で液体を移動する
ガラス瓶1から瓶2へ液体を移動するプログラムを作ります。
初めに、以下のコマンドを実行し、ガラス瓶のx,y座標を把握しておきます。
dobot_x, dobot_y, dobot_z ,_= dobot.get_position()
dobot_x, dobot_y, dobot_z
その結果、以下のように容器1,2の座標を指定することになりました。
container1_pos=(250, -60)
container2_pos=(229,28)
同様に、ピペットを瓶の底まで下げたとき、瓶よりも十分に上に上げたときの座標も確認して、記録します。
up_z=50
down_z=-22
液体を移動する関数を定義します。
def lift_arm(dobot,up_z):
dobot_x, dobot_y, dobot_z ,_= dobot.get_position()
dobot.move_arm(dobot_x, dobot_y, up_z,0)
def transfer_liquid(container1_pos,container2_pos,
volume,
up_z,down_z,inter_z):
lift_arm(dobot,up_z)
dobot.move_arm(container1_pos[0], container1_pos[1], up_z,0)
lift_arm(dobot,down_z)
pipetty.vacuum(volume)
lift_arm(dobot,up_z)
dobot.move_arm(container2_pos[0], container2_pos[1], up_z,0)
lift_arm(dobot,inter_z)
pipetty.home()
人間はピペット操作を無意識に行いますが、ロボットに対しては全てを明示的に説明する必要があります。
上記のプログラムを日本語に直すと、以下の通りになります。
とりあえずアームを上に上げる (lift_arm(dobot,up_z))
瓶類にぶつかるのを防ぐため
容器1の上にアームを移動する( dobot.move_arm(container1_pos[0], container1_pos[1], up_z,0))
アームを下ろす(lift_arm(dobot,down_z))
液を吸う (pipetty.vacuum(volume))
アームを上げる
容器2の上にアームを移動する(dobot.move_arm(container2_pos[0], container2_pos[1], up_z,0))
アームを少し下げる(lift_arm(dobot,inter_z))
液を排出する(pipetty.home())
今回のプログラムでは、せっかくなので、移動操作を3回繰り返しています。
動作の様子は、改めてこちら。
センシングについて考慮すべき点
今回のプログラムでは、システムに視覚を持たせない、「目隠しUFOキャッチャー」状態で実験を行いました。
言い換えると、アームの移動先は全て、人間側で教えてあげました。
簡単な系においては、目隠しUFOキャッチャーのアプローチでOKですが、以下のような欠点もあります。
物体の座標を厳密に計測・指定する必要がある(面倒)
物体が(意図せず)移動した際の対応が難しい
そのため、各種センシング技術を使ってアーム座標を全自動で決定するアプローチが、潜在的には重要です。
考えられるアプローチと想定課題について、考察します
X,Y座標の決定
画像認識が重要になります。三脚にUSBカメラを固定して、見下ろしながら作業するイメージです。
以下の通り、手法はいくつかありますが、実装難度や精度に課題があったりするので、注意が必要です。
Arucoマーカー
QRコードのような人工物を容器に貼り付けておき、カメラ上での座標を簡便に認識できます。
Arucoマーカーの便利な点は、画面上の座標に加え、カメラからの距離(3次元データ)も取得できることです。
ただし、この方法で取得できるのはあくまでマーカーの位置になります。
そのため、マーカーと容器・ピペットチップの先端etcの相対位置は、予め計測しておく必要があります。
物体認識
OpenCVによる輪郭抽出やディープラーニングによって、物体そのもののを認識し、座標を取得します。
この手法は基本的には2次元画面上の座標推定となるため、三次元データ(距離)を得るには、深度カメラや、ステレオカメラが必要になります。
深度カメラは5万円くらいで販売されています。
基本的にはレーザー方式で距離を計測するのですが、ガラスのような透明材料に弱かったりします。化学実験ではガラス器具をたくさん使うので、やや困ります。
まだ使いこなせてませんが、距離精度も、完璧ではない印象です。
ステレオカメラは、人間の目のように、複数のレンズで座標を認識する方式です。原理的には、USBカメラ2台で実装できますが、あまりコードが公開されていないので、色々と難しい点があるのではないかと思っています。
Z座標
地味に難しいのは、アームの高さ方向(z座標)の制御です。
ピペットの先端が上にありすぎると、液体を吸うことができません。
一方、ピペットを降下しすぎると、地面に衝突してしまいます。
人間はどのようにしてこの問題を防いでいるかというと、、
容器を横から見て、高さを合わせる(視覚)
ピペットの先端をそっとガラス容器の底にあてて高さを合わせる(触覚)
(液体が少ない場合、容器を傾ける (2つ目の手))
これをフルにロボットで代替しようとすると、
自在に動く(または横視点で固定された)カメラ
触覚センサ
二本目のロボットアームでの協調操作
が必要になります。カメラは比較、低コストですが、後者2つは研究レベルの案件になってきます。
人間側で、軽く高さ座標を教えてあげる、クッションやバネを容器の下 or アームに装着して、高さ方向に遊びをもたせる、などの工夫をする方が、多くの人にとっては低コストなアプローチかもしれません。
まとめ
化学実験の最低限のプロセスである、試薬の移動操作を自動化する手段について紹介しました。
今後は、実際の試薬で試しつつ、以下の操作も自動化を検討したいと思います(無限にありますね..)。
撹拌、過熱
ピペットチップの交換
瓶の移動
蓋の装着
蓋の取り外し
不活性条件での合成
各種装置への接続
精製
などなど
20年以上前の、こちらの総説も興味深いです。