秋月 5 finger 制御編 (後編)

 とりあえず サーボ1つで軽くテストできました ので、5指バージョンかつ 5V 動作に拡張します。
 実験は ESP32 を用いましたため、信号線を 3.3V→5V するレベルコンバートが必要ですが、てっとり早くトランジスタと抵抗で簡単に仕上げてみました。

 
http://dl.ftrans.etr.jp/?6ff8b6f3cb45479f86140ad16249f31746f161c1.png


 ECB じゃなくて EBC のほうが実装的に都合が良かったため 2N3904 を使いましたが、2SC1815 とかでも大丈夫です。


http://dl.ftrans.etr.jp/?e1d4338cd77843e2a24fc5e1042a20a6c4b07722.jpg http://dl.ftrans.etr.jp/?af251a6b51ab4dbba4177ce3e3d0dab4f80c162a.jpg


 プログラムのほうは、ライブラリ的なものと、メインと分けてみました。


■ライブラリ的なほう(finger.h)

#ifndef _WAKWAK_FINGER_
#define _WAKWAK_FINGER_

#ifndef ESP32
#include <Servo.h>
#endif

class Finger
{
  public:
         Finger(int pin, bool reverse = false);
    void set(int *job);
    void tick();
    
  protected:
    int *job;
    int job_pos;
    unsigned long wait;
    
  private:
    int pin;
    bool reverse;
#ifdef ESP32
    int channel;
#else
    Servo servo;
#endif
    void setDegree(int degree = -1);
};

#endif

■ライブラリ的なほう(finger.ino)

#include "finger.h"

Finger::Finger(int pin, bool reverse)
{
  Finger::pin = pin;
  Finger::reverse = reverse;
  setDegree();
}

void Finger::set(int *job)
{
  Finger::job = job;
  Finger::wait = 0;
  Finger::job_pos = 0;
}

void Finger::tick()
{
  if(millis() > wait && job[job_pos] >= 0)
  {
    setDegree(job[job_pos]);
    job_pos++;

    wait = millis() + job[job_pos];
    job_pos++;
  }
}

void Finger::setDegree(int degree)
{
#ifdef ESP32
  const int degree_0 = 500;       // 0.5ms at 0 degree
  const int degree_180 = 2400;    // 2.4ms at 180 degree
  const int pulse_width = 20000;  // 20ms
  static int last_channel = 0;
#endif

  if(degree < 0)
  {
    // Initialize
#ifdef ESP32
    channel = last_channel;
    int freq = 1000000 / pulse_width;
    ledcSetup(channel, freq, 10);
    ledcAttachPin(pin, channel);     // for PWM
    last_channel ++;
#else
    servo.attach(pin);
#endif    
  } else {
    if(reverse)
      degree = 180 - degree;
  
#ifdef ESP32
    int pulse = (degree_0 + degree * (degree_180 - degree_0) / 180.0F);
    if(pulse < degree_0)
      pulse = degree_0;
        
    pulse = 1023 * pulse / pulse_width;
    ledcWrite(channel, pulse);
#else
    servo.write(degree);
#endif    
  }
}


■メイン部分

#include "finger.h"

// degree, delay, degree, delay ...
int job_1[] = {110, 5000, 110, 5000, 70, 5000, -1};
int job_2[] = {110, 5000, 70, 5000, 70, 5000, -1};
int job_3[] = {110, 5000, 70, 5000, 70, 5000, -1};
int job_4[] = {110, 5000, 110, 5000, 70, 5000, -1};
int job_5[] = {110, 5000, 110, 5000, 70, 5000, -1};

Finger *fingers[] = { new Finger(23)
                    , new Finger(22)
                    , new Finger(21)
                    , new Finger(19, true)
                    , new Finger(18, true) };

void setup() {
  // put your setup code here, to run once:
  fingers[0]->set(job_1);
  fingers[1]->set(job_2);
  fingers[2]->set(job_3);
  fingers[3]->set(job_4);
  fingers[4]->set(job_5);
}

void loop() {
  for(int i=0; i<sizeof(fingers) / sizeof(fingers[0]); i++)
    fingers[i]->tick();
}

 Servo.h が使える ESP8266 等と Servo.h が使えない ESP32 とで共用ソースにしてみましたが、マイコン側が PWM を 5ch 使えるかどうかは要確認です。
 あと、new Finger() の引数がピン番号なのですが、ESP32 前提になってますので要注意。


 薬指と小指は、親指と比較して逆回転なのですが、その辺はライブラリ側で吸収してます。
 サンプルは5指が5秒おきに同期して動きますが、プログラムとしては擬似的ながらも非同期ぽく動作しますので5指バラバラに動かす・・・極端いえば(理論的には)ピアノを弾かせることもできます。


http://dl.ftrans.etr.jp/?26d5a62065754fa09406dd7108816032246b3ef4.jpg


 結構、電気を食います。




 以下、動作結果についてネタバレ要素を含んでますので、動いたときの楽しみを大事になさる方は、いますぐにブラウザを閉じて下さい。
 いいですか。


 本当に閉じましたか?


 では・・・




 こいつ・・・


 握力なさすぎ!!!!

 
 かなり組み立てるの面倒なんですが、左手も手元にあるものの、組み立てる気が起きません。
 それくらいに残念な握力です。


 ピアノ?
 そんなの絶対に無理無理、鍵盤を押す力もありませんよ、これ。



 グー・チョキ・パー を全力でやらせてみて、こんなもんです。