team M and Aの部屋

ゆるーい電子工作好きな夫婦のブログです。

作品紹介:ミニそんたくん

そんたくんとは、新型コロナウイルスが流行する少し前に、なんとなく見つけたCO2センサで作ってみた作品。

tmanda.hatenablog.com

まさかこんなにCO2測定が世の中で流行るとは、、、

 

そのそんたくんのミニバージョンができました。

f:id:tmanda:20211211211305j:plain

幅70mm, 高さ50mm, 厚さ30mm

元祖そんたくんが150mm×120mm×30mmなのでかなり小さくなりました。

ミニでもそんたくんなので空気(CO2)濃度を測定して、高いか低いかほっぺの色でお知らせしてくれます。

f:id:tmanda:20211211211914j:plain

ESP8266も載せたので、CO2濃度をWiFiで飛ばすことができます。現在ThingSpeakを使っています。

元祖そんたくんにあった口はありません。スピーカーは入っているので、潜在能力的には音を出せるのですが、まだソフトを実装していません。

他には、お鼻がタクトスイッチになっていたり、SDカードも搭載していたりと元祖そんたくんにはなかった機能を追加しています。(ソフトはまだ・・・)

 

中身はこんな感じ。

f:id:tmanda:20211211212024j:plain

金色がCO2センサです。これはNDIR式なのでそれなりに良い精度で値を表示してくれます。MH-Z19Bという型番のもので、今までAliexpressで購入していたのですが、いつの間にか同シリーズのものが秋月でも売られるようになっていました。

akizukidenshi.com

 

ちなみにCO2センサはNDIR式の方がガスセンサ式よりもよいそうです。

参考: https://www.youtube.com/watch?v=sGHRCQmjrHQ&t=0s

 

ケースはいつもお世話になっているDMM 3Dプリントサービスで作りました。素材は一番安いナイロン白。結構いい精度で作ってもらえます。

 

今回の基板には、がじぇるねのGR-COTTONと同じRL78マイコンを実装したので、Arduinoコードがそのまま使えます。

www.renesas.com

 

小さくても高機能(になれる)ミニそんたくん、もうちょっとコードを書いてもっと能力を出せるようにしてあげないと。。。

フラックスの罠にはまる・・・

最近、QFP部品のはんだ付けに挑戦しました。

f:id:tmanda:20210619185333j:plain

 0.5mmピッチのRenesas製RL78マイコンです。

akizukidenshi.com

 

QFPのはんだ付けの動画をYoutubeでいろいろ見て、フラックスがあった方が良さそうだということで使いました!

f:id:tmanda:20210619185353j:plain

昔はんだごてを買ったときに、確かセットについていたフラックス。よくよく見ると、「プリント基板には使用できません」の文字が。。。

そんなことには気付かず、ジュージュー言わせながらはんだ付け完了!!

 

ちょっと濃度低いかもなと思いながら、消毒用アルコールで洗浄後、いざ、動作確認、、、

 

動かない!!

 

はんだブリッジは虫眼鏡でチェックしたのに、、、

念のため、はんだごてを当ててみると、ジューーーー・・・

まだフラックスが残っていたのか。

洗浄→動作確認→動かない→はんだごてジューーー→洗浄・・・

 

これを何度か何度か繰り返して、なんとかようやく動くようになりました。

QFPのICの間に入り込んで残ったものがなかなか取れなかったのかな。。。

 

そして気付いた。「プリント基板には使用できません」

 

Google先生にも教えてもらいました。フラックスには洗浄タイプと無洗浄タイプがあって、洗浄タイプはしっかり取りきらないといけないんですね。

 

そして手に入れた!無洗浄タイプでプリント基板用と書かれたフラックス!!

f:id:tmanda:20210619185403j:plain

 

このフラックスで作った2枚目の基板はあっさり動作確認完了。

めでたしめでたし。

作品紹介:ほっとぷれーと

玄関に置くほっとな鍵置きを作りました。


www.youtube.com

 

家に帰ってきて、ほっとぷれーとに鍵を置くと、

  • 家族の声で「おかえり」と言ってもらえる
  • LINEで帰宅したことを家族に伝える

お出かけするときに、ほっとぷれーとから鍵を取ると、

  • 家族の声で「いってらっしゃい」と言ってもらえる
  • LINEで出かけたことを家族に伝える

 

仕事で家にいないときに子供の帰宅を確認したり、単身赴任や一人暮らしの寂しさの紛らわしたり、遠くのおじいちゃんおばあちゃんを見守ったり、そんな風に使えるといいかもなぁと考えています。

 

鍵を置いたこと・取ったことの検知には、改札で使うICカードと同様の仕組みを使っています。ほっとぷれーとの中には、↓のFeliCaリーダーが入っています。

www.switch-science.com

 

f:id:tmanda:20210619180903j:plain

 

そして動画に出てきたアリクイとラッコのキーホルダーにはNFCタグのシールが貼ってあります。(白い丸いシールです)

f:id:tmanda:20210619180851j:plain

 

FeliCaリーダーでこの白いシールを読み取ることで、鍵を置いたり取ったりしたことを検知しています。 

 

接触って面白い!!

工具のきもち LINEスタンプ

工具のきもちを表現したLINEスタンプがデビューしました!

 

工具ってよく見ると1つ1つ顔が違いますよね。

そんな工具たちはいったいどんな気持ちで過ごしているんだろうと思いませんか。 

 

 ↓↓作品はこちら↓↓

 https://store.line.me/stickershop/product/11936314

f:id:tmanda:20200523225157p:plain 

工具といっても幅広いので、電子工作で身近なもの、

日常使うような工具に絞ってスタンプにしてみました。

ぜひ使ってみてくださいね!

ガーデニングはじめました

Stay homeということでガーデニングをはじめました。

種を植えてから2週間ほど経ち、双葉もだいぶ大きくなってきました。


Arduino (GR-ROSE) Robot Gardener

 

お出かけできるようになっときに備えて、水やりの自動化を目論見中です。
水を流す・止めるの制御には、サイフォンの原理を利用しています。水源のペットボトルをある高さで固定しておき

  • アームの先端が高いときは水が流れない
  • アームの先端が低いときは水が流れる

となるので、これなら弁とか蛇口とか難しいことを考える必要がなさそう!

サイフォン - Wikipedia

アーム&ペットボトルの固定とか実験用のビニール袋がかっこよくないとかまだまだ改良ポイントはいっぱい。

ロボットアームとArduino (GR-ROSE)で機構学のお勉強

tmanda.hatenablog.com で紹介したロボットアームを制御するための機構学のお勉強です。 f:id:tmanda:20200506103951p:plain ↑これの話です。

さっそくはじめていきましょう。

まずはロボットアームの関節角度を定義します。今回はロボットアームが垂直に立った状態を0度とします。
サーボモータの可動範囲は0度±135度) f:id:tmanda:20200506130807p:plain

ロボットアームの関節の位置(サーボモータの回転軸の位置)を計算します。 f:id:tmanda:20200509141301p:plain

今回はロボットアームの先端が水平に同じ高さになるように制御します。 f:id:tmanda:20200506131038p:plain 

「ロボットアームの先端が水平に同じ高さ」を数式で表すと次のようになります。 f:id:tmanda:20200509141308p:plain

①②の式を代入すると、 f:id:tmanda:20200509141354p:plain ここで黄色マークした式をこの後で使います。根本のモータを好きなように制御したときの他の2つのモータ角度を計算します。 f:id:tmanda:20200506131411p:plain

あとはプログラムにモータ角度をセットするコードを書くということになります。

※注意点
1. モータの可動範囲は実物のアームが干渉しない範囲になります。アーム同士がぶつからないようにしましょう。
2. 今回は高さを一定に保つ制御をしていますが、リンクが届かない範囲があります。以下の絵を参照。
f:id:tmanda:20200506135721p:plain

今回使用したArduino互換ボード「GR-ROSE」には近藤科学サーボモータを接続できるコネクタとライブラリが用意されているので、すぐに試すことができました。

www.renesas.com

ソースコードは以下です。

#include <ICS.h>

IcsController ICS(Serial1);
IcsServo servo0;
IcsServo servo1;
IcsServo servo2;
IcsServo servo3;

int theta0_pulse = 0;  //3500-11500
int theta1_pulse = 0;
int theta2_pulse = 0;
int theta3_pulse = 0;

bool motion_enable = false;
bool dir0 = false;
bool dir1 = false;

#define TH0_ZERO 7500
#define TH0_LIMIT_MIN 3500
#define TH0_LIMIT_MAX 11500

#define TH1_ZERO 7500
#define TH1_LIMIT_MIN 4500
#define TH1_LIMIT_MAX 10500

#define TH2_ZERO 7500
#define TH2_LIMIT_MIN 4500
#define TH2_LIMIT_MAX 10500

#define TH3_ZERO 7500
#define TH3_LIMIT_MIN 4500
#define TH3_LIMIT_MAX 10500


void setup() {

  Serial.begin(115200);
  pinMode(PIN_LED1, OUTPUT);

  ICS.begin();
  servo0.attach(ICS, 0x01);
  servo1.attach(ICS, 0x02);
  servo2.attach(ICS, 0x03);
  servo3.attach(ICS, 0x04);
  
  theta0_pulse = TH0_ZERO;
  theta1_pulse = servo1.getPosition();
  theta2_pulse = servo2.getPosition();
  theta3_pulse = servo3.getPosition();

  setPosition4axis(theta0_pulse, theta1_pulse, theta2_pulse, theta3_pulse);
  delay(1000);
  digitalWrite(PIN_LED1, HIGH);
}

void loop() {
  if(Serial.available()){
    switch(Serial.read()){
      case 's':
        motion_enable = !motion_enable;
        break;
      case '0':
        motion_enable = false;
        theta0_pulse = TH0_ZERO;
        theta1_pulse = TH1_ZERO;
        theta2_pulse = TH2_ZERO;
        theta3_pulse = TH3_ZERO;
        break;
      default:
        break;
    }
  }
  
  if(motion_enable){
    int tmp;
    int dth = 50;

    if(theta0_pulse > (TH0_LIMIT_MAX - 400)){
      dth = 50 - (TH0_LIMIT_MAX - 400 - theta0_pulse)/8;
      if(dth < 5) dth = 5;
    } else if(theta0_pulse < (TH0_LIMIT_MIN + 400)) {
      dth = 50 - (TH0_LIMIT_MIN + 400 - theta0_pulse)/8;
      if(dth < 5) dth = 5;
    } else {
      dth = 50;
    }
    if(dir0){
      theta0_pulse += dth;
      if(theta0_pulse > TH0_LIMIT_MAX){
        theta0_pulse = TH0_LIMIT_MAX;
        dir0 = !dir0;
      }
    } else {
      theta0_pulse -= dth;
      if(theta0_pulse < TH0_LIMIT_MIN){
        theta0_pulse = TH0_LIMIT_MIN;
        dir0 = !dir0;
      }
    }//*/
    if(theta1_pulse > 8620){
      dth = 100 - (theta1_pulse-8620)/4;
      if(dth < 5) dth = 5;
    } else if(theta1_pulse < 6000) {
      dth = 100 - (6000 - theta1_pulse)/4;
      if(dth < 5) dth = 5;
    } else {
      dth = 100;
    }
    if(dir1){
      theta1_pulse += dth;
      if(theta1_pulse > 9000){
        theta1_pulse = 9000;
        dir1 = !dir1;
      }
    } else {
      theta1_pulse -= dth;
      if(theta1_pulse < 5620){
        theta1_pulse = 5620;
        dir1 = !dir1;
      }
    }//*/
    tmp = calc_theta2_pulse(theta1_pulse);
    if(tmp != 0) theta2_pulse = tmp;
    theta3_pulse = TH3_ZERO - ((theta1_pulse - TH1_ZERO) + (theta2_pulse - TH2_ZERO));
  }

  setPosition4axis(theta0_pulse, theta1_pulse, theta2_pulse, theta3_pulse);
  delay(25);
}

void setPosition4axis(int pos0, int pos1, int pos2, int pos3){
  if(pos0 < TH0_LIMIT_MIN){
    pos0 = TH0_LIMIT_MIN;
  } else if(pos0 > TH0_LIMIT_MAX){
    pos0 = TH0_LIMIT_MAX;
  }
  if(pos1 < TH1_LIMIT_MIN){
    pos1 = TH1_LIMIT_MIN;
  } else if(pos1 > TH1_LIMIT_MAX){
    pos1 = TH1_LIMIT_MAX;
  }
  if(pos2 < TH2_LIMIT_MIN){
    pos2 = TH2_LIMIT_MIN;
  } else if(pos2 > TH2_LIMIT_MAX){
    pos2 = TH2_LIMIT_MAX;
  }
  if(pos3 < TH3_LIMIT_MIN){
    pos3 = TH3_LIMIT_MIN;
  } else if(pos3 > TH3_LIMIT_MAX){
    pos3 = TH3_LIMIT_MAX;
  }
  Serial.print(servo0.setPosition(pos0)); Serial.write('\t');
  Serial.print(servo1.setPosition(pos1)); Serial.write('\t');
  Serial.print(servo2.setPosition(pos2)); Serial.write('\t');
  Serial.print(servo3.setPosition(pos3)); Serial.println();//*/
}


int calc_theta2_pulse(int theta1){
  const float l1 = 68.0f;
  const float l2 = 60.0f;
  const float l2_ref = 89.8f;
  const float pulse_to_rad = 135.0f*M_PI/(4000.0f*180.0f);
  const float rad_to_pulse = (4000.0f*180.0f)/(135.0f*M_PI);
  
  const float theta1_rad = (float)(theta1 - TH1_ZERO) * pulse_to_rad;
  const float p2_y = l1 * cos(theta1_rad);
  
  float theta2_rad;
  float cos_theta2 = (l2_ref - p2_y)/l2;
  
  if(cos_theta2 > 1.0f){
    return 0; //Error
  }
  theta2_rad = acos(cos_theta2) - theta1_rad;
  
  return ((theta2_rad * rad_to_pulse) + TH2_ZERO);
}

おうちロボット展

しばらく棚の中で眠っていた彼

robot (before)

二足歩行ロボット

ついに復活のときが!


4-axis Robot arm (GR-ROSE)

 

ロボットアームのお勉強に作ってみました。アームの先端が同じ高さで水平になるように制御しています。

 

Excelで関節角度の計算式をチェック  

f:id:tmanda:20200506103951p:plain

Excelで関節角度の計算

 

計算の詳細はこちらで!

tmanda.hatenablog.com