Otto-Robotを作成


Otto-Robot「Start」(1号機)を作成してみました。

Otto-Robot「start」(1号機)について



 Otto-Robotは、個人的な利用であればオープンソースなので、作ってみました。
OttoのWebサイト は、https://www.ottodiy.com/です。  以下が、最初のOtto-Roboto(1号機)の製作過程です。



  完成動画


 完成したOtto-Robot(1号機)の起動動画です。
最後は自分で転倒します。





  各ファイルの取得


1.Ottoのサイトを開くと、次の購入サイト画面が表示されますので、右上のXをクリックします。
(2021/01時点)


2.次のOttoサイトの画面が表示されます。


3.画面上のメニューの「Academy」をクリックします。次の画面が表示されます。


4.3Dプリントのstlファイル等の取得
 正規版は、次の①のように取得しますが、後が面倒なので②の「Wikifactory」からファイルを取得します。

(1)正規版は、「Academy」画面を下にスクロールして「learn to Design」の所にある「3D CAD Source」ボタンを
 クリックして取得します。但し、PCに「Fusion 360」がインストールされていることが必要です。

(2)「Wikifactory」の「Otto DIY」からstlファイルを取得します。
 「Academy」画面をさらに下にスクロールして「Apply New!」を表示します。


(3)画面の「Otto"Starter"」をクリックすると、次のように「Wikifactory」の「Otto DIY」に移動します。


(4)画面中央の「Files」をクリックすると、必要なファイルが表示されます。


(5)画面下のダウンロードボタンをクリックしてダウウンロードします。
 Zipファイルを解凍すると「otto-diy」フォルダーに次のファイルが入っています。


(6)「3Dprint」フォルダーには以下の3Dプリンター用のstlファイルが入っています。


(7)「Code」フォルダーにはottoを動かすスケッチプログラムが入っています。


(8)「Instruction manual」フォルダーには製作マニュアルと配線図が入っています。


 配線図は、「fritzing」で描かれたものです。参考として掲示しておきます。




  Arduino IDE用のライブラリーファイルを取得


1.「Otto Academy」画面に戻り、「Programming Guide」の所で「Libraries+Code」をクリックします。


2.以下のottoのArduino IDE用のライブラリーがダウンロードされます。


3.このライブラリーファイルをArduino IDEにインストールします。
(1)Arduino IDEを起動し、メニューの「スケッチ」をクリックして、「ライブラリをインクルード」、
 「.ZIP形式のライブラリをインストール」の順にクリックして、上記の「OttoDIYLib-master.zip」を
 インストールします。


(2)ライブラリーをインストール後、ライブラリの「contributedライブラリ」の中に「OttoDIYLib」が 入っていればOKです。

 これでottoを起動する準備が出来ました。




  Ottoの組立


1.全てのサーボは、90°の位置に設定しておきます。

2.組立手順は、「Instruction manual」フォルダーに入っている「OttoDIY_Manual_V10.pdf」を 参照して組み立ててください。

3.今回は、電源として単3電池4本を使わないで、006P形ニッケル水素充電池8.4V(NiMH)を使用しました。 したがって、NANO用の拡張ボード「ナノV3.0ナノプロトタイプシールドi/o拡張ボード」 (Aliexpressで購入)のVin端子にスイッチを通して電池を接続しました。




  Ottoの起動


1.ottoの電源スイッチはoffにしておいて、NANOとパソコンをUSBコードで接続し、 「Code」フォルダーの「Otto_allmoves_V9」にあるスケッチ「Otto_allmoves_V9.ino」を 起動してください。

2.Arduino IDEで、ボードとシリアルポートを選択し、スケッチを書き込んでください。Ottoが起動します。
確認ができたらUSBコードを外してottoの電源スイッチをONにして起動してみます。

3.「Otto_allmoves_V9.ino」は、ottoの全ての動きがプログラムされています。最後は、自分で転倒します。




  「Otto9.h」の関数


 参考として「Otto9.h」における関数の全容は以下の通りです。
ちなみに使用方法は、次のようにします。

#include <Otto9.h>
Otto9 Otto;  //This is Otto!
・・・・・・・・・・・・・・・・・・・
Otto.init(PIN_YL, PIN_YR, PIN_RL, PIN_RR, true, A6, PIN_Buzzer, PIN_Trigger, PIN_Echo);
Otto.sing(S_connection);
Otto.home();
・・・・・・・・・・・・・・
Otto.walk(2,1000,1);
						

「Otto9.h」における関数

Otto9::initDC(int NoiseSensor, int Buzzer, int USTrigger, int USEcho)
Otto9::initMATRIX(int DIN, int CS, int CLK, int rotate)
Otto9::matrixIntensity(int intensity)
Otto9::initBatLevel(int batteryPIN)
Otto9::attachServos()
Otto9::detachServos()
Otto9::setTrims(int YL, int YR, int RL, int RR)
Otto9::saveTrimsOnEEPROM()
Otto9::_moveServos(int time, int  servo_target[])
Otto9::_moveSingle(int position, int servo_number)
Otto9::oscillateServos(int A[4], int O[4], int T, double phase_diff[4], float cycle=1)
Otto9::_execute(int A[4], int O[4], int T, double phase_diff[4], float steps = 1.0)
Otto9::home()
Otto9::getRestState()
Otto9::setRestState(bool state)

Otto9::jump(float steps, int T)
//---------------------------------------------------------
//-- Otto movement: Jump
//--  Parameters:
//--    steps: Number of steps
//--    T: Period
//---------------------------------------------------------

Otto9::walk(float steps, int T, int dir)
/---------------------------------------------------------
//-- Otto gait: Walking  (forward or backward)    
//--  Parameters:
//--    * steps:  Number of steps
//--    * T : Period
//--    * Dir: Direction: FORWARD / BACKWARD
//---------------------------------------------------------

Otto9::turn(float steps, int T, int dir)
/---------------------------------------------------------
//-- Otto gait: Turning (left or right)
//--  Parameters:
//--   * Steps: Number of steps
//--   * T: Period
//--   * Dir: Direction: LEFT / RIGHT
//---------------------------------------------------------
Otto9::bend (int steps, int T, int dir)
/---------------------------------------------------------
//-- Otto gait: Lateral bend
//--  Parameters:
//--    steps: Number of bends
//--    T: Period of one bend
//--    dir: RIGHT=Right bend LEFT=Left bend
//---------------------------------------------------------

Otto9::shakeLeg (int steps,int T,int dir)
/---------------------------------------------------------
//-- Otto gait: Shake a leg
//--  Parameters:
//--    steps: Number of shakes
//--    T: Period of one shake
//--    dir: RIGHT=Right leg LEFT=Left leg
//---------------------------------------------------------

Otto9::updown(float steps, int T, int h)
/---------------------------------------------------------
//-- Otto movement: up & down
//--  Parameters:
//--    * steps: Number of jumps
//--    * T: Period
//--    * h: Jump height: SMALL / MEDIUM / BIG 
//--              (or a number in degrees 0 - 90)
//---------------------------------------------------------

Otto9::swing(float steps, int T, int h)
/---------------------------------------------------------
//-- Otto movement: swinging side to side
//--  Parameters:
//--     steps: Number of steps
//--     T : Period
//--     h : Amount of swing (from 0 to 50 aprox)
//---------------------------------------------------------

Otto9::tiptoeSwing(float steps, int T, int h)
/---------------------------------------------------------
//-- Otto movement: swinging side to side without touching the floor with the heel
//--  Parameters:
//--     steps: Number of steps
//--     T : Period
//--     h : Amount of swing (from 0 to 50 aprox)
//---------------------------------------------------------

Otto9::jitter(float steps, int T, int h)
/---------------------------------------------------------
//-- Otto gait: Jitter 
//--  Parameters:
//--    steps: Number of jitters
//--    T: Period of one jitter 
//--    h: height (Values between 5 - 25)   
//---------------------------------------------------------

Otto9::ascendingTurn(float steps, int T, int h)
/---------------------------------------------------------
//-- Otto gait: Ascending & turn (Jitter while up & down)
//--  Parameters:
//--    steps: Number of bends
//--    T: Period of one bend
//--    h: height (Values between 5 - 15) 
//---------------------------------------------------------

Otto9::moonwalker(float steps, int T, int h, int dir)
/---------------------------------------------------------
//-- Otto gait: Moonwalker. Otto moves like Michael Jackson
//--  Parameters:
//--    Steps: Number of steps
//--    T: Period
//--    h: Height. Typical valures between 15 and 40
//--    dir: Direction: LEFT / RIGHT
//---------------------------------------------------------

Otto9::crusaito(float steps, int T, int h, int dir)
/---------------------------------------------------------
//-- Otto gait: Crusaito. A mixture between moonwalker and walk
//--   Parameters:
//--     steps: Number of steps
//--     T: Period
//--     h: height (Values between 20 - 50)
//--     dir:  Direction: LEFT / RIGHT
//-----------------------------------------------------------

Otto9::flapping(float steps, int T, int h, int dir)
/---------------------------------------------------------
//-- Otto gait: Flapping
//--  Parameters:
//--    steps: Number of steps
//--    T: Period
//--    h: height (Values between 10 - 30)
//--    dir: direction: FOREWARD, BACKWARD
//---------------------------------------------------------

Otto9::getDistance()
//-- Otto getDistance: return Otto's ultrasonic sensor measure
//---------------------------------------------------------

Otto9::getNoise()
//-- Otto getNoise: return Otto's noise sensor measure
//---------------------------------------------------------

Otto9::getBatteryLevel()
//-- Otto getBatteryLevel: return battery voltage percent
//---------------------------------------------------------

Otto9::getBatteryVoltage()
//The first read of the batery is often a wrong reading, so we will discard this value.

//////////////////////////////////////////////////////////////////
//-- MOUTHS & ANIMATIONS ----------------------------------------//
///////////////////////////////////////////////////////////////////
Otto9::setLed(byte X, byte Y, byte value)
// EXAMPLE putAnimationMouth(dreamMouth,0)

Otto9::putAnimationMouth(unsigned long int aniMouth, int index)
//EXAMPLE putMouth(smile);

Otto9::putMouth(unsigned long int mouth, bool predefined)
Otto9::clearMouth()
Otto9::writeText(const char * s, byte scrollspeed)

///////////////////////////////////////////////////////////////////
//-- SOUNDS -----------------------------------------------------//
///////////////////////////////////////////////////////////////////
Otto9::_tone (float noteFrequency, long noteDuration, int silentDuration)
// tone(10,261,500);
    // delay(500);
Otto9::bendTones (float initFrequency, float finalFrequency, float prop, long noteDuration, int silentDuration)
//Examples:
  //  bendTones (880, 2093, 1.02, 18, 1);
  //  bendTones (note_A5, note_C7, 1.02, 18, 0);

Otto9::sing(int songName)
    case S_connection:
      _tone(note_E5,50,30);
      _tone(note_E6,55,25);
      _tone(note_A6,60,10);

    case S_disconnection:
      _tone(note_E5,50,30);
      _tone(note_A6,55,25);
      _tone(note_E6,50,10);

    case S_buttonPushed:
      bendTones (note_E6, note_G6, 1.03, 20, 2);
      delay(30);
      bendTones (note_E6, note_D7, 1.04, 10, 2);

    case S_mode1:
      bendTones (note_E6, note_A6, 1.02, 30, 10);  //1318.51 to 1760

    case S_mode2:
      bendTones (note_G6, note_D7, 1.03, 30, 10);  //1567.98 to 2349.32

    case S_mode3:
      _tone(note_E6,50,100); //D6
      _tone(note_G6,50,80);  //E6
      _tone(note_D7,300,0);  //G6

    case S_surprise:
      bendTones(800, 2150, 1.02, 10, 1);
      bendTones(2149, 800, 1.03, 7, 1);

    case S_OhOoh:
      bendTones(880, 2000, 1.04, 8, 3); //A5 = 880
      delay(200);
      for (int i=880; i<2000; i=i*1.04) {
           _tone(note_B5,5,10);
      }

    case S_OhOoh2:
      bendTones(1880, 3000, 1.03, 8, 3);
      delay(200);
      for (int i=1880; i<3000; i=i*1.03) {
          _tone(note_C6,10,10);
      }

    case S_cuddly:
      bendTones(700, 900, 1.03, 16, 4);
      bendTones(899, 650, 1.01, 18, 7);

    case S_sleeping:
      bendTones(100, 500, 1.04, 10, 10);
      delay(500);
      bendTones(400, 100, 1.04, 10, 1);

    case S_happy:
      bendTones(1500, 2500, 1.05, 20, 8);
      bendTones(2499, 1500, 1.05, 25, 8);

    case S_superHappy:
      bendTones(2000, 6000, 1.05, 8, 3);
      delay(50);
      bendTones(5999, 2000, 1.05, 13, 2);

    case S_happy_short:
      bendTones(1500, 2000, 1.05, 15, 8);
      delay(100);
      bendTones(1900, 2500, 1.05, 10, 8);

    case S_sad:
      bendTones(880, 669, 1.02, 20, 200);

    case S_confused:
      bendTones(1000, 1700, 1.03, 8, 2); 
      bendTones(1699, 500, 1.04, 8, 3);
      bendTones(1000, 1700, 1.05, 9, 10);

    case S_fart1:
      bendTones(1600, 3000, 1.02, 2, 15);

    case S_fart2:
      bendTones(2000, 6000, 1.02, 2, 20);

    case S_fart3:
      bendTones(1600, 4000, 1.02, 2, 20);
      bendTones(4000, 3000, 1.02, 2, 20);

//////////////////////////////////////////////////////////////////
//-- GESTURES ---------------------------------------------------//
///////////////////////////////////////////////////////////////////
Otto9::playGesture(int gesture)
    case OttoHappy: 
        _tone(note_E5,50,30);
        putMouth(smile);
        sing(S_happy_short);
        swing(1,800,20); 
        sing(S_happy_short);
        home();
        putMouth(happyOpen);

    case OttoSuperHappy:
        putMouth(happyOpen);
        sing(S_happy);
        putMouth(happyClosed);
        tiptoeSwing(1,500,20);
        putMouth(happyOpen);
        sing(S_superHappy);
        putMouth(happyClosed);
        tiptoeSwing(1,500,20); 
        home();  
        putMouth(happyOpen);

    case OttoSad: 
        putMouth(sad);
        gesturePOSITION[0] = 110;//int sadPos[6]=      {110, 70, 20, 160};
        gesturePOSITION[1] = 70;
        gesturePOSITION[2] = 20;
        gesturePOSITION[3] = 160;
        _moveServos(700, gesturePOSITION);     
        bendTones(880, 830, 1.02, 20, 200);
        putMouth(sadClosed);
        bendTones(830, 790, 1.02, 20, 200);  
        putMouth(sadOpen);
        bendTones(790, 740, 1.02, 20, 200);
        putMouth(sadClosed);
        bendTones(740, 700, 1.02, 20, 200);
        putMouth(sadOpen);
        bendTones(700, 669, 1.02, 20, 200);
        putMouth(sad);
        delay(500);
        home();
        delay(300);
        putMouth(happyOpen);

    case OttoSleeping:
        gesturePOSITION[0] = 100;//int bedPos[6]=      {100, 80, 60, 120};
        gesturePOSITION[1] = 80;
        gesturePOSITION[2] = 60;
        gesturePOSITION[3] = 120;
        _moveServos(700, gesturePOSITION);     
        for(int i=0; i<4;i++){
          putAnimationMouth(dreamMouth,0);
          bendTones (100, 200, 1.04, 10, 10);
          putAnimationMouth(dreamMouth,1);
          bendTones (200, 300, 1.04, 10, 10);  
          putAnimationMouth(dreamMouth,2);
          bendTones (300, 500, 1.04, 10, 10);   
          delay(500);
          putAnimationMouth(dreamMouth,1);
          bendTones (400, 250, 1.04, 10, 1); 
          putAnimationMouth(dreamMouth,0);
          bendTones (250, 100, 1.04, 10, 1); 
          delay(500);
        } 
        putMouth(lineMouth);
        sing(S_cuddly);
        home();  
        putMouth(happyOpen);

    case OttoFart:
        gesturePOSITION[0] = 90;// int fartPos_1[6]=   {90, 90, 145, 122};
        gesturePOSITION[1] = 90;
        gesturePOSITION[2] = 145;
        gesturePOSITION[3] = 122;
        _moveServos(500,gesturePOSITION);
        delay(300);     
        putMouth(lineMouth);
        sing(S_fart1);  
        putMouth(tongueOut);
        delay(250);
        gesturePOSITION[0] = 90;// int fartPos_2[6]=   {90, 90, 80, 122};
        gesturePOSITION[1] = 90;
        gesturePOSITION[2] = 80;
        gesturePOSITION[3] = 122;
        _moveServos(500,gesturePOSITION);
        delay(300);
        putMouth(lineMouth);
        sing(S_fart2); 
        putMouth(tongueOut);
        delay(250);
        gesturePOSITION[0] = 90;// int fartPos_3[6]=   {90, 90, 145, 80};
        gesturePOSITION[1] = 90;
        gesturePOSITION[2] = 145;
        gesturePOSITION[3] = 80;
        _moveServos(500,gesturePOSITION);
        delay(300);
        putMouth(lineMouth);
        sing(S_fart3);
        putMouth(tongueOut);    
        delay(300);
        home(); 
        delay(500); 
        putMouth(happyOpen);

    case OttoConfused:
        gesturePOSITION[0] = 110;//int confusedPos[6]= {110, 70, 90, 90};
        gesturePOSITION[1] = 70;
        gesturePOSITION[2] = 90;
        gesturePOSITION[3] = 90;
        _moveServos(300, gesturePOSITION); 
        putMouth(confused);
        sing(S_confused);
        delay(500);
        home();  
        putMouth(happyOpen);

    case OttoLove:
        putMouth(heart);
        sing(S_cuddly);
        crusaito(2,1500,15,1);
        home(); 
        sing(S_happy_short);  
        putMouth(happyOpen);

    case OttoAngry: 
        gesturePOSITION[0] = 90;//int angryPos[6]= {90, 90, 70, 110};
        gesturePOSITION[1] = 90;
        gesturePOSITION[2] = 70;
        gesturePOSITION[3] = 110;
        _moveServos(300, gesturePOSITION); 
        putMouth(angry);
        _tone(note_A5,100,30);
        bendTones(note_A5, note_D6, 1.02, 7, 4);
        bendTones(note_D6, note_G6, 1.02, 10, 1);
        bendTones(note_G6, note_A5, 1.02, 10, 1);
        delay(15);
        bendTones(note_A5, note_E5, 1.02, 20, 4);
        delay(400);
        gesturePOSITION[0] = 110;//int headLeft[6]= {110, 110, 90, 90};
        gesturePOSITION[1] = 110;
        gesturePOSITION[2] = 90;
        gesturePOSITION[3] = 90;
        _moveServos(200, gesturePOSITION); 
        bendTones(note_A5, note_D6, 1.02, 20, 4);
        gesturePOSITION[0] = 70;//int headRight[6]= {70, 70, 90, 90};
        gesturePOSITION[1] = 70;
        gesturePOSITION[2] = 90;
        gesturePOSITION[3] = 90;
        _moveServos(200, gesturePOSITION); 
        bendTones(note_A5, note_E5, 1.02, 20, 4);
        home();  
        putMouth(happyOpen);

    case OttoFretful: 
        putMouth(angry);
        bendTones(note_A5, note_D6, 1.02, 20, 4);
        bendTones(note_A5, note_E5, 1.02, 20, 4);
        delay(300);
        putMouth(lineMouth);
        for(int i=0; i<4; i++){
          gesturePOSITION[0] = 90;//int fretfulPos[6]= {90, 90, 90, 110};
          gesturePOSITION[1] = 90;
          gesturePOSITION[2] = 90;
          gesturePOSITION[3] = 110;
          _moveServos(100, gesturePOSITION);   
          home();
        }
        putMouth(angry);
        delay(500);
        home();  
        putMouth(happyOpen);

    case OttoMagic:
        //Initial note frecuency = 400
        //Final note frecuency = 1000
        // Reproduce the animation four times
        for(int i = 0; i<4; i++){ 
          int noteM = 400; 
            for(int index = 0; index<6; index++){
              putAnimationMouth(adivinawi,index);
              bendTones(noteM, noteM+100, 1.04, 10, 10);    //400 -> 1000 
              noteM+=100;
            }
            clearMouth();
            bendTones(noteM-100, noteM+100, 1.04, 10, 10);  //900 -> 1100
            for(int index = 0; index<6; index++){
              putAnimationMouth(adivinawi,index);
              bendTones(noteM, noteM+100, 1.04, 10, 10);    //1000 -> 400 
              noteM-=100;
            }
        } 
        delay(300);
        putMouth(happyOpen);

    case OttoWave:
        // Reproduce the animation four times
        for(int i = 0; i<2; i++){ 
            int noteW = 500; 
            for(int index = 0; index<10; index++){
              putAnimationMouth(wave,index);
              bendTones(noteW, noteW+100, 1.02, 10, 10); 
              noteW+=101;
            }
            for(int index = 0; index<10; index++){
              putAnimationMouth(wave,index);
              bendTones(noteW, noteW+100, 1.02, 10, 10); 
              noteW+=101;
            }
            for(int index = 0; index<10; index++){
              putAnimationMouth(wave,index);
              bendTones(noteW, noteW-100, 1.02, 10, 10); 
              noteW-=101;
            }
            for(int index = 0; index<10; index++){
              putAnimationMouth(wave,index);
              bendTones(noteW, noteW-100, 1.02, 10, 10); 
              noteW-=101;
            }
        }    
        clearMouth();
        delay(100);
        putMouth(happyOpen);

    case OttoVictory:
        putMouth(smallSurprise);
        //final pos   = {90,90,150,30}
        for (int i = 0; i < 60; ++i){
          int pos[]={90,90,90+i,90-i};  
          _moveServos(10,pos);
          _tone(1600+i*20,15,1);
        }
        putMouth(bigSurprise);
        //final pos   = {90,90,90,90}
        for (int i = 0; i < 60; ++i){
          int pos[]={90,90,150-i,30+i};  
          _moveServos(10,pos);
          _tone(2800+i*20,15,1);
        }
        putMouth(happyOpen);
        //SUPER HAPPY
        //-----
        tiptoeSwing(1,500,20);
        sing(S_superHappy);
        putMouth(happyClosed);
        tiptoeSwing(1,500,20); 
        //-----
        home();
        clearMouth();
        putMouth(happyOpen);

    case OttoFail:
        putMouth(sadOpen);
        gesturePOSITION[0] = 90;//int bendPos_1[6]= {90, 90, 70, 35};
        gesturePOSITION[1] = 90;
        gesturePOSITION[2] = 70;
         gesturePOSITION[3] = 35;
        _moveServos(300,gesturePOSITION);
        _tone(900,200,1);
        putMouth(sadClosed);
        gesturePOSITION[0] = 90;//int bendPos_2[6]= {90, 90, 55, 35};
        gesturePOSITION[1] = 90;
        gesturePOSITION[2] = 55;
        gesturePOSITION[3] = 35;
        _moveServos(300,gesturePOSITION);
        _tone(600,200,1);
        putMouth(confused);
        gesturePOSITION[0] = 90;//int bendPos_3[6]= {90, 90, 42, 35};
        gesturePOSITION[1] = 90;
        gesturePOSITION[2] = 42;
        gesturePOSITION[3] = 35;
        _moveServos(300,gesturePOSITION);
        _tone(300,200,1);
        gesturePOSITION[0] = 90;//int bendPos_4[6]= {90, 90, 34, 35};
        gesturePOSITION[1] = 90;
        gesturePOSITION[2] = 34;
         gesturePOSITION[3] = 35;
        _moveServos(300,gesturePOSITION);
        putMouth(xMouth);
        detachServos();
        _tone(150,2200,1);
        delay(600);
        clearMouth();
        putMouth(happyOpen);
        home();