21分紅茶はホントに22分じゃダメ!ロボットアームで超正確に作ってみた

2020年9月11日

アイスティー

 「フランス人マダムに教えてもらった、世界一おいしいアイスティー」ってご存じですか?とびきりおいしいんです。渋みが一切なくスッキリしていて、イギリス人ならキレイすぎてつまらんと言い出しそうなアイスティー。わりと簡単に作れるのですが、1点ややこしい箇所があります。

「20分でも22分でもダメ。21分、ちゃんと守るのよ」

フランス人マダムに教えてもらった、世界一おいしいアイスティーの作り方

 ティーバッグを鍋に入れたあとの、蒸らし時間の話なのですが、指定が細かすぎませんかってなもんで。ピッタリ21分でつくった紅茶が飲みたかったので、ロボットアームをつくりました

なぜ、ロボットアームが必要なのか

 詳細なレシピは元記事を読んでもらうとして、簡単に説明しますね。「2リットルの湯を鍋で沸かし、ティーバッグを3包入れます。21分後にゆっくりと取り出します」。これだけなんです。文章にすると簡単ですが、実際にやってみると“21分後に取り出す”って、難しいんです。

 現実世界を見てみましょう。まずですね、お湯が沸いたので、鍋にティーバッグを入れますね。そして、気づくのです。

 タイマーどこ!???!

タイマーを探す人
タイマーが簡単に行方不明になる問題

 だいたい、これで30秒はロスします。 

 次にですね。21分経って、タイマーが鳴るじゃないですか。その瞬間、思うんです。

 ちょっとまってーーーーーーー!

タイマーが鳴っているのに、ゲームをしていて手が離せない人
すぐに手が離せるわけがない

 セフィロス倒してる最中に呼び出されてもですね、そう簡単にティーバッグを引き上げになどいけないんです。家も広いですからね(“動線がわるい”をポジティブに言い換えた表現)。引き上げに行くまでに30秒はかかります。つまり、今まで、筆者が飲んでいた21分紅茶は、22分かもしれない紅茶だったんです。

 それでも十分においしかったので、「別に22分でも同じだろ」と自分に言い聞かせて満足していましたが、やっぱり、心のどこかにひっかっかってるんです。「20分でも、22分でもダメ。21分じゃないと」の言葉が。

 こうなったら、機械化しかない、ですよね

 Amazonサーフィンをしていたら、ロボットアームを発見しました。7000円で買えるんですよー。すごいねー。令和ってすごいねー。これがあったら、なんでもできちゃうじゃーん。と、ウキウキしました。

 こいつにティーバッグを引き上げてもらおうと、ポチったのです。

めっちゃ組み立てるヤツだった

 ジャジャーン。ロボットアームが届きました。

Adeept Robotic Arm Kit for Arduino
ロボットアーム!

 箱を開けると、あらびっくり。ガチで組み立てるヤツでした。

箱の中身
部品しかはいっとらん
アクリル板
これ、小学生の自由研究にイイヤツじゃないか

 難しそうなんですけど……と、心が折れかけましたが、“自分ならできる”と根拠なく信じることに決めて、作業に取りかかりました。公式が出しているYouTubeの動画をなんども巻き戻して確認します。この動画があるから大丈夫だろうと思って買ったんですけど、機械のバージョンが違うのかボルトのサイズが違うんですよ。指定されたボルトが手元にないっていうね。マニュアル(英語)はあっていたので、その2つを付き合わせて解読。組み立てには、半日かかりました。

Arduinoやボルト
Arduinoまで同梱されてる
ロボットアームが完成したところ
組み立てたぜー

 ロボットアームってこういう仕組みなんだっていうのが、つくると良くわかります。勉強にはなりますが、筆者はいま、ロボットアームの仕組みを知りたかったわけじゃないので、ちょっと残念でした。何が残念かというと、モーターが想像以上に貧弱です。これでは納豆を1万回かきまぜてくれる体力すらなさそうです。いろいろ自動でかき混ぜてもらおうと思ってたのに。

 とりあえず、ティーバッグくらいなら持ち上げられそうなので、プログラミングの工程に進みます。

プログラムするのも大変な件

 で、こっから、ロボットアームちゃんに、紅茶を引き上げるプログラムをすれば目標達成です。Arduinoを使ってプログラムするんですけど……LED光らせるくらいしかやったことない筆者には難関がすぎる。なったって、この製品、

 説明が、雑。

 雑というか、無に等しい。サンプルコードが6つあるだけ。「こんなんでわかるかー!」ってちゃぶ台投げたくなります。ウェブ検索して見つけたのは、公式サイトにある掲示板オンリー!イェイー!この掲示板のたったひとつのスレッドを参考にして、プログラムを書きました。

 どんなプログラムかというと、「ボタンを押すとゆっくりとアームが下がる。21分後にアームが上がる。ついでに、残り時間をOLED画面に表示」。これだけです。ロボットアームちゃんに鍋のフタを外してもらうとかはあきらめました。

OLEDに7と13を表示
残り時間7分13秒を示しています

 コードものせておきます。が、よくわからんままコピペしてみたら、なんか動いたってクオリティです。参考にする方は、そのへん、ご了承ください。

#include "U8glib.h"
/*I2C*/
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE); 
#include <Servo.h>
int servopin1 = 9;    //Define servo interface digital interface 9
int servopin2 = 6;    //Define servo interface digital interface 6
int servopin3 = 5;    //Define servo interface digital interface 5

unsigned long wait_time = 1260000; //21min = 1260000

int dataServo1=90;
int dataServo2=90;
int dataServo3=90;
Servo servo1;
Servo servo2;
Servo servo3;
int angle = 90;        //Angle of rotation of the servo
int val1;
int val2;
int val3;
boolean autoLock = false;
//boolean key_mouse_lock = false;
boolean closeLock = false;
const int buttonPin = 4;     // the number of the pushbutton pin

unsigned long start_time;
unsigned long now_time;
unsigned long rest_time_min;
unsigned long rest_time_sec;

void setup() {
  // put your setup code here, to run once:
  pinMode(servopin1,OUTPUT);//Set the servo interface as the output interface
  pinMode(servopin2,OUTPUT);//Set the servo interface as the output interface
  pinMode(servopin3,OUTPUT);//Set the servo interface as the output interface
  Serial.begin(9600);
  servo1.attach(servopin1);
  servo2.attach(servopin2);
  servo3.attach(servopin3);
  //servo(1~5).write(90);has 90 equal to 0 point

// Display init
 if ( u8g.getMode() == U8G_MODE_R3G3B2 )
    u8g.setColorIndex(255);     // white
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT )
    u8g.setColorIndex(3);         // max intensity
  else if ( u8g.getMode() == U8G_MODE_BW )
    u8g.setColorIndex(1);         // pixel on
  u8g.setFont(u8g_font_6x10);
  u8g.setFontRefHeightExtendedText();
  u8g.setDefaultForegroundColor();
  u8g.setFontPosTop();

  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) 
    u8g.setColorIndex(255);     // white
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT )
    u8g.setColorIndex(3);         // max intensity
  else if ( u8g.getMode() == U8G_MODE_BW )
    u8g.setColorIndex(1);         // pixel on
  u8g.setFont(u8g_font_6x10);
  u8g.setFontRefHeightExtendedText();
  u8g.setDefaultForegroundColor();
  u8g.setFontPosTop();

  delay(5000);
  servo1.write(90);//original base rotation
  servo2.write(90);//original shoulder angle
  servo3.write(90);//initial elblow angle
  delay(200);
  //servo1Pulse(90);
}
void loop() {

    val1 = 90;//Control the value of servo 1  
    val2 = 90;//Control the value of servo 2
    val3 = 90;//Control the value of servo 3  
    for(int i=0;i<180;i++){ServoAngle();}

    u8g.firstPage();
  do {
    u8g.drawStr( 0, 22, "Push button to start.");
  } while ( u8g.nextPage() );

  while(digitalRead(buttonPin)==HIGH){
  }

    start_time = millis();

    val1 = 90;//Control the value of servo 1  
    val2 = 10;//Control the value of servo 2
    val3 = 30;//Control the value of servo 3  
    for(int i=0;i<180;i++){ServoAngle();}

    do {
      now_time = millis() - start_time;
      rest_time_min = (wait_time - now_time) / 60000;
      rest_time_sec = (wait_time - now_time) / 1000 % 60;  

    u8g.firstPage();
    do {
        u8g.setPrintPos(0,22);
        u8g.print(rest_time_min);
        u8g.setPrintPos(0,48);
        u8g.print(rest_time_sec);
    } while ( u8g.nextPage() );

      delay(1000);

  } while(now_time <= wait_time);

  
    val1 = 90;//Control the value of servo 1  
    val2 = 90;//Control the value of servo 2
    val3 = 90;//Control the value of servo 3  
    for(int i=0;i<180;i++){ServoAngle();}

     while(digitalRead(buttonPin)==HIGH){
  }

}
void ServoAngle(void)
{
  servo1.write(dataServo1);//goes to dataServo1 degrees
  servo2.write(dataServo2);//goes to dataServo2 degrees
  servo3.write(dataServo3);//goes to dataServo3 degrees

  if(dataServo1>val1){dataServo1--;  }
  if(dataServo1<val1){dataServo1++;  }
  if(dataServo1>180) {dataServo1=180;}
  if(dataServo1<0)   {dataServo1=0;  }

  if(dataServo2>val2){dataServo2--;  }
  if(dataServo2<val2){dataServo2++;  }
  if(dataServo2>180) {dataServo2=180;}
  if(dataServo2<0)   {dataServo2=0;  }

  if(dataServo3>val3){dataServo3--;  }
  if(dataServo3<val3){dataServo3++;  }
  if(dataServo3>180) {dataServo3=180;}
  if(dataServo3<0)   {dataServo3=0;  }

  delay(75);//wait for 0.05second
}

さあ、21分紅茶をつくるぞっ!

 道具が完成したので、21分紅茶をつくります。

 動画はのちほど編集して別途公開します。今日はパラパラ写真でお楽しみあれ。

コンロの上の鍋
お湯が沸きました
鍋の脇にロボットアームをセット
ロボットアームちゃんをセットします
基板上のボタンを押す
ボタンを押します
アームが下がる様子
ガガガガガガッ
アームが下がりきったところ
フタはうまく閉じなかったので、手動で直しました
タイマー21分を脇に置く
待ちます
タイマーが残り1分を示す
動き出しました
アームが上がる様子
引き上げてくれたー!
アームが下がったところ
と思ったら、力が足りなかったのかショボーン状態に。おおおおおおおおおい
ロボットアームごと引き上げる様子
ロボットアームごと引き上げました
できた

21分紅茶はさわやかだった

 ぜんぜん成功していないんですけど、できた紅茶を飲んでみたんです。

 なんという、おいしさ。

本物の21分紅茶

 正直、20分でも、22分でも同じだと思っていました。ところが、今回つくった21分紅茶を飲んだら。違うんです。今まで飲んでいた、“22分かも知れない紅茶”とは違うんです。さわやかで、とにかく渋みが一切ありません。甘みがしっとりと奥深く微笑む泉のよう。美大生がつくった彫刻とミロのビーナス級の違いです。すごーい。すごーい。ほんとに21分じゃないとダメだったんだー。


 この実験をはじめる前は、本当に20分でも22分でもたいして変わらないだろうと思っていました。装置ができた暁には、どこまで時間を短くしたら、家族が違いに気がつくかを実験しようと思っていたくらいです。ところが、本当に21分紅茶がおいしくてビックリしました。ぜひともみなさんも、きっちり時間を計った21分紅茶をためしてみてください。そして、これより楽に作る方法があったら教えてください。

 ワッホイ、ワッホイ。 

動画公開しました

トマトマン、かわええよぉー。