はじめに
茶道、難しくないですか?初心者はまず上手に点てられないし、上級者でも何杯も点てると腱鞘炎一歩手前になります。
これをロボットがやってくれたらなあ!と茶道をやっている友人と一緒に作ることにしたというのが動機です。
先行研究はいくつかあったんですが、死ぬほど遅い双腕ロボットやガタガタ振動して粉をまき散らすロボットなど「これはちょっと……」と思うものが多かったです。
そこで完成させたのがこちら。↓
それなりに飲めるものが完成しました。(少し泡が薄いので「表千家の茶」ということにしていました。怒られそう)作り方を解説していきます。
構造
数多の手順とそこに込められた意味がちゃんとある茶道ですが、自動化しようとなるとそれをすべて拾ってはいられません。そのため、主要ないくつかの動作に分けることにしました。
- 抹茶を入れる
- お湯を入れる
- 置いてある茶筅を拾って茶を点てる
簡略化し過ぎた気もしますがこんな感じです。次からはそれぞれについて解説していきます。イメージしやすいように、全体の上面図を以下に貼っておきます。
抹茶を入れる
抹茶をすくう、茶碗に入れる、という動作を3つのサーボモータで実現しました。使ったサーボモータはこれ。
1つは抹茶を出す機構に。アクリルで作った箱に抹茶を詰め、サーボモータの力で床板を押し出してスプーンに落とせるようにしました。抹茶の粉はかなり粘度が高く、うまく落ちないことも多かったため穴の大きさなどの調整が大変でした。
残り2つはスプーンの動作に。初期位置から抹茶を出す機構まで移動し、茶碗の上にスプーンの中心が来るように回転します。その後先ほどの回転の半径方向に回転し、茶碗に抹茶を落とします。
スプーンの台もSolidWorksで設計しアクリルで製作。穴は茶碗に落とす用のサーボのケーブルをしまうためのものです。
お湯を入れる
お湯を受け止めて茶碗に入れるひしゃくの動きは前述のスプーンと同じく2つのサーボモータで実現しました。設計は上の画像とほぼ同じなので割愛。共振を起こしやすいため剛性にはかなり気を使い、サーボも強めのこれを使いました。
お湯は某オーヤマの電気ポットから得ることにしましたが、かっこいい見た目である反面ボタンをサーボなどで押すことが難しくなっています。
そこで、上のシールを剥がすことで基盤をむき出しにしで直接信号を取得しようとしました。幸い基板上のプリントが大変分かりやすく、ボタンの入力に対応する部分に信号線を取り付けることができました。
茶を点てる
このロボットの本質ですね。既製品のロボットアームに少し手を加えて制御することによって達成しました。ロボットアームはArduinoで簡単に動かせるBraccioを使いました。詳しくはソフトウェアの部分で解説します。
Braccioはベースの回転と手首の回転に加え3関節を持つ、値段終わりに自由度の高いロボットアームですが、目標とする動きをするためには関節が1つ足りませんでした。そのため、新たに腕を設計して3dプリンタで出力し、連続回転のできるS35 STDを用いて動かすことにしました。
その回転部分に茶筅を高速運動させる機構を取り付けます。
モータにクランクを取り付け、その往復運動で茶筅を前後に動かしました。使用したモータはマブチの540ですが、機構の問題かトルクが足りなかったので直流安定化装置から電源を取っていました。小型、高トルク、高回転数を満たすモータは幻想ですかね。(ブラシレスなら結構ありそう。)
Braccio本体はスプレーで塗装して統一感を出しました。
ソフトウェア
BraccioにはBraccioシールドというArduino UNO用のシールドが付属しています。そのため、簡単のために全ての動作をArduinoで行いました。サーボを多く使ったのとBraccio側でピンを占有している箇所がありピン数が足りなかったため、2つのArduino UNOを用意して片方の動作終了と同時に文字列をシリアル送信することでリレーのように動作させることにしました。そのためコードは2つあります。
具体的な方法としては、ロボットアーム関係の動作7とスプーンの回転などのサーボモータの動作を5の計12の状態に分け、現在の状態番号をシリアル送信します。
メイン(Braccio関係)
#include <Braccio.h>
#include <Servo.h>
Servo base;
Servo shoulder;
Servo elbow;
Servo wrist_rot;
Servo wrist_ver;
Servo gripper;
Servo sv; //Servoオブジェクト“sv”を作成する
void setup() {
//Initialization functions and set up the initial position for Braccio
//All the servo motors will be positioned in the "safety" position:
//Base (M1):90 degrees
//Shoulder (M2): 45 degrees
//Elbow (M3): 180 degrees
//Wrist vertical (M4): 180 degrees
//Wrist rotation (M5): 90 degrees
//gripper (M6): 10 degrees
sv.attach(2);
Braccio.begin();
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
Serial.begin(9600);
}
void loop() {
/*
Step Delay: a milliseconds delay between the movement of each servo. Allowed values from 10 to 30 msec.
M1=base degrees. Allowed values from 0 to 180 degrees
M2=shoulder degrees. Allowed values from 15 to 165 degrees
M3=elbow degrees. Allowed values from 0 to 180 degrees
M4=wrist vertical degrees. Allowed values from 0 to 180 degrees
M5=wrist rotation degrees. Allowed values from 0 to 180 degrees
M6=gripper degrees. Allowed values from 10 to 73 degrees. 10: the toungue is open, 73: the gripper is closed.
*/
int s=0;
int n=13;
for(;;) {
if(digitalRead(4)==LOW) {
s=s+1;
delay(20);
Serial.write(s);
if(s>n){
s=0;
delay(20);
}
while(digitalRead(4)==LOW) {}
}
if(s==0){
sv.write(180);
Braccio.ServoMovement(30, 130, 15, 72, 0, 0, 73); //配置時。茶筅が上を向く
}
else if(s==7){
Braccio.ServoMovement(30, 130, 54, 150, 26 , 0, 73); //茶碗から持ち上げる
sv.write(10);
}
else if(s==8){
Braccio.ServoMovement(30, 95, 54, 150, 26 , 0, 73); //茶碗から持ち上げる
sv.write(30);
}
else if(s==9){
Braccio.ServoMovement(30, 95, 32, 90, 15, 0, 73);
sv.write(20);
}
else if(s==10){
digitalWrite(7, LOW);
analogWrite(8, 153);
}
else if(s==11){
Braccio.ServoMovement(0, 90, 32, 90, 15, 0, 73);
Braccio.ServoMovement(0, 100, 32, 90, 15, 0, 73);
}
if(s==12){
Braccio.ServoMovement(30, 95, 54, 150, 26 , 0, 73);
}
//Wait 1 second
}
}
受け取り側(Braccio以外)
#include <VarSpeedServo.h> //ライブラリ<Servo.h>を組み込む
VarSpeedServo rot; //Servoオブジェクト“sv”を作成する
VarSpeedServo bas;
void setup() {
// put your setup code here, to run once:
rot.attach(7);
bas.attach(8);
pinMode(13,OUTPUT);
digitalWrite(13,HIGH);
pinMode(12,OUTPUT);
digitalWrite(12,HIGH);
Serial.begin(9600);
rot.write(0);
bas.write(0);
}
int s;
int count = 0;
int n = 13;
void loop() {
// put your main code here, to run repeatedly:
if (Serial.available() > 0) { // データの受信を確認
s = int(Serial.read());
Serial.println(s);
}
Serial.println(s);
// put your main code here, to run repeatedly:
/*
if(digitalRead(2)==LOW) {
Serial.println(s);
s=s+1;
if(s>13)
s=0;
count=0;
delay(20);
while(digitalRead(2)==LOW) {}
}
*/
if (s==1){ //ひしゃくをポット下に
bas.write(0,30);
}
if (s==2) { //電気ポットロック解除
digitalWrite(13, LOW);
delay(100);
digitalWrite(13, HIGH);
}
if (s==3) { //お湯を出す
if (count==0){
digitalWrite(12, LOW);
delay(2500);
digitalWrite(12,HIGH);
delay(100);
digitalWrite(13, LOW);
delay(500);
digitalWrite(13, HIGH);
count = 1;
}
delay(100);
}
if (s==4){
count = 0;
bas.write(90,30);
}
if (s==5){
rot.write(120,30);
}
if (s==6){
rot.write(0,30);
bas.write(0,30);
}
}
かなりのクソコードです。ごめんなさい。
まとめ
茶道、本当に難しい。リスペクトを維持しながら自動化という謎のこだわりを続けた結果かなり苦労することになりました。
得たものは試作段階で何杯も抹茶を飲んだことでついたカフェイン耐性と、意外と家電製品はハックできるという知見ですね。
投稿者の人気記事
-
M1YamA
さんが
2021/02/18
に
編集
をしました。
(メッセージ: 初版)
-
M1YamA
さんが
2021/02/18
に
編集
をしました。
ログインしてコメントを投稿する