06紅外線遙控

(2017/05/06)

由於想在夏令營來推OTTO機器人,但發現小朋友沒有手機,要用藍牙來控制比較不方便,因此還是要用【紅外線遙控器】來控制比較方便!一開始使用之前所用的 IRremote 程式庫(之前的文章),由於TIMER與TONE衝突,修改使用TIMER1(修改檔案改到boarddef這個檔案),以為解決了,沒想到又跟Servo衝突!花了好多時間,後來才想到motoBlockly也有製作出紅外線遙控器的積木,因此就改用motoBlockly來寫此程式!!利用此方式可以方便學生來編OTTO的舞蹈,又將OTTO機器人與小學生的距離縮短了~~

接線:

這部分只增加了一個紅外線接收器(接在D7),可將之前的藍牙接收器給移除

motoBlockly 程式:motoBlockly網站

積木程式(otto-irremote.xml)於附件

將上方積木程式轉成Arduino語言

#include <motoIRremote.h>

decode_results ir_results;

void IRkeyUnsetFunction( ) { Serial.println("unknow!"); }

struct _Object {

void (* functionPointer)()=IRkeyUnsetFunction;

};

IRrecv ir_receiv(7);

String IR1keycode[17]={"ff4ab5","ff6897","ff9867","ffb04f","ff30cf","ff18e7","ff7a85","ff10ef","ff38c7","ff5aa5","ff52ad","ff42bd","ff629d","ff22dd","ff02fd","ffc23d","ffa857"};

struct _Object IR1key0, IR1key1, IR1key2, IR1key3, IR1key4, IR1key5, IR1key6, IR1key7, IR1key8, IR1key9, IR1key10;

struct _Object IR1key11, IR1key12, IR1key13, IR1key14, IR1key15, IR1key16, IR1key17, IR1key18, IR1key19, IR1key20, IR1key21;

void checkIRcode( ) {

if(ir_receiv.decode(&ir_results))

{

String keycode = String(ir_results.value, HEX);

Serial.print("keycode=");

Serial.println(keycode);

if(keycode == IR1keycode[0])

IR1key0.functionPointer();

else if(keycode == IR1keycode[1])

IR1key1.functionPointer();

else if(keycode == IR1keycode[2])

IR1key2.functionPointer();

else if(keycode == IR1keycode[3])

IR1key3.functionPointer();

else if(keycode == IR1keycode[4])

IR1key4.functionPointer();

else if(keycode == IR1keycode[5])

IR1key5.functionPointer();

else if(keycode == IR1keycode[6])

IR1key6.functionPointer();

else if(keycode == IR1keycode[7])

IR1key7.functionPointer();

else if(keycode == IR1keycode[8])

IR1key8.functionPointer();

else if(keycode == IR1keycode[9])

IR1key9.functionPointer();

else if(keycode == IR1keycode[10])

IR1key10.functionPointer();

else if(keycode == IR1keycode[11])

IR1key11.functionPointer();

else if(keycode == IR1keycode[12])

IR1key12.functionPointer();

else if(keycode == IR1keycode[13])

IR1key13.functionPointer();

else if(keycode == IR1keycode[14])

IR1key14.functionPointer();

else if(keycode == IR1keycode[15])

IR1key15.functionPointer();

else if(keycode == IR1keycode[16])

IR1key16.functionPointer();

ir_receiv.resume();

}

}

void IR1key12Function( ) {

digitalWrite(0,HIGH); //此行改成要按向上鍵時要執行的指令

}

void IR1key16Function( ) {

digitalWrite(0,HIGH); //此行改成要按向下鍵時要執行的指令

}

void IR1key13Function( ) {

digitalWrite(0,HIGH); //此行改成要按向左鍵時要執行的指令

}

void IR1key15Function( ) {

digitalWrite(0,HIGH); //此行改成要按向右鍵時要執行的指令

}

void IR1key14Function( ) {

digitalWrite(0,HIGH); //此行改成要按OK鍵時要執行的指令

}

void IR1key1Function( ) {

digitalWrite(0,HIGH); //此行改成要按1鍵時要執行的指令

}

void IR1key2Function( ) {

digitalWrite(0,HIGH); //此行改成要按2鍵時要執行的指令

}

void IR1key3Function( ) {

digitalWrite(0,HIGH); //此行改成要按3鍵時要執行的指令

}

void IR1key4Function( ) {

digitalWrite(0,HIGH); //此行改成要按4鍵時要執行的指令

}

void IR1key5Function( ) {

digitalWrite(0,HIGH); //此行改成要按5鍵時要執行的指令

}

void IR1key6Function( ) {

digitalWrite(0,HIGH); //此行改成要按6鍵時要執行的指令

}

void IR1key7Function( ) {

digitalWrite(0,HIGH); //此行改成要按7鍵時要執行的指令

}

void IR1key8Function( ) {

digitalWrite(0,HIGH); //此行改成要按8鍵時要執行的指令

}

void IR1key9Function( ) {

digitalWrite(0,HIGH); //此行改成要按9鍵時要執行的指令

}

void IR1key0Function( ) {

digitalWrite(0,HIGH); //此行改成要按0鍵時要執行的指令

}

void IR1key10Function( ) {

digitalWrite(0,HIGH); //此行改成要按*鍵時要執行的指令

}

void IR1key11Function( ) {

digitalWrite(0,HIGH); //此行改成要按#鍵時要執行的指令

}

void setup()

{

ir_receiv.enableIRIn();

pinMode(0, OUTPUT);

}

void loop()

{

checkIRcode();

IR1key12.functionPointer = IR1key12Function;

IR1key16.functionPointer = IR1key16Function;

IR1key13.functionPointer = IR1key13Function;

IR1key15.functionPointer = IR1key15Function;

IR1key14.functionPointer = IR1key14Function;

IR1key1.functionPointer = IR1key1Function;

IR1key2.functionPointer = IR1key2Function;

IR1key3.functionPointer = IR1key3Function;

IR1key4.functionPointer = IR1key4Function;

IR1key5.functionPointer = IR1key5Function;

IR1key6.functionPointer = IR1key6Function;

IR1key7.functionPointer = IR1key7Function;

IR1key8.functionPointer = IR1key8Function;

IR1key9.functionPointer = IR1key9Function;

IR1key0.functionPointer = IR1key0Function;

IR1key10.functionPointer = IR1key10Function;

IR1key11.functionPointer = IR1key11Function;

}

開啟官網中的最簡單的OTTO_avoid的程式(避障程式)

//----------------------------------------------------------------

//-- Otto basic firmware v2 adapted from Zowi (ottobot.org)

//-- CC BY SA

//-- 04 December 2016

//-----------------------------------------------------------------

//-- Otto will avoid obstacles with this code!

//-----------------------------------------------------------------

#include <Servo.h>

#include <Oscillator.h>

#include <US.h>

#include <Otto.h>

Otto Otto; //This is Otto!

//---------------------------------------------------------

//-- First step: Make sure the pins for servos are in the right position

/*

---------------

| O O |

|---------------|

YR 3==> | | <== YL 2

---------------

|| ||

RR 5==> ----- ------ <== RL 4

|----- ------|

*/

#define PIN_YL 2 //servo[2]

#define PIN_YR 3 //servo[3]

#define PIN_RL 4 //servo[4]

#define PIN_RR 5 //servo[5]

///////////////////////////////////////////////////////////////////

//-- Global Variables -------------------------------------------//

///////////////////////////////////////////////////////////////////

//-- Movement parameters

int T=1000; //Initial duration of movement

int moveId=0; //Number of movement

int moveSize=15; //Asociated with the height of some movements

//---------------------------------------------------------

bool obstacleDetected = false;

///////////////////////////////////////////////////////////////////

//-- Setup ------------------------------------------------------//

///////////////////////////////////////////////////////////////////

void setup(){

//Set the servo pins

Otto.init(PIN_YL,PIN_YR,PIN_RL,PIN_RR,true);

Otto.sing(S_connection); //Otto wake up!

Otto.home();

delay(50);

Otto.sing(S_happy); // a happy Otto :)

}

///////////////////////////////////////////////////////////////////

//-- Principal Loop ---------------------------------------------//

///////////////////////////////////////////////////////////////////

void loop() {

if(obstacleDetected){

Otto.sing(S_surprise);

Otto.playGesture(OttoFretful);

Otto.sing(S_fart3);

Otto.walk(2,1300,-1);

Otto.turn(2,1000,-1);

delay(50);

obstacleDetector();

}

else{

Otto.walk(1,1000,1);

obstacleDetector();

}

}

///////////////////////////////////////////////////////////////////

//-- Function to read distance sensor & to actualize obstacleDetected variable

void obstacleDetector(){

int distance = Otto.getDistance();

if(distance<15){

obstacleDetected = true;

}else{

obstacleDetected = false;

}

}

將上面兩個Arduino程式做一個整合(以下程式為一個樣板,直接COPY到Arduino IDE下來使用,並針對自己的需要去修改即可)

以下藍色字是原本OTTO的程式,紅色字是motoBlockly所轉成的遙控器程式

//----------------------------------------------------------------

//-- Otto basic firmware v2 adapted from Zowi (ottobot.org)

//-- CC BY SA

//-- 04 December 2016

//-----------------------------------------------------------------

//-- Otto will avoid obstacles with this code!

//-----------------------------------------------------------------

#include <Servo.h>

#include <Oscillator.h>

#include <US.h>

#include <Otto.h>

#include <motoIRremote.h>

decode_results ir_results;

Otto Otto; //This is Otto!

//---------------------------------------------------------

//-- First step: Make sure the pins for servos are in the right position

/*

---------------

| O O |

|---------------|

YR 3==> | | <== YL 2

---------------

|| ||

RR 5==> ----- ------ <== RL 4

|----- ------|

*/

#define PIN_YL 2 //servo[2]

#define PIN_YR 3 //servo[3]

#define PIN_RL 4 //servo[4]

#define PIN_RR 5 //servo[5]

///////////////////////////////////////////////////////////////////

//-- Global Variables -------------------------------------------//

///////////////////////////////////////////////////////////////////

//-- Movement parameters

int T=1000; //Initial duration of movement

int moveId=0; //Number of movement

int moveSize=15; //Asociated with the height of some movements

//---------------------------------------------------------

}

///////////////////////////////////////////////////////////////////

//-- Setup ------------------------------------------------------//

///////////////////////////////////////////////////////////////////

void setup(){

ir_receiv.enableIRIn();

//Set the servo pins

Otto.init(PIN_YL,PIN_YR,PIN_RL,PIN_RR,true);

// Otto.sing(S_connection); //Otto wake up!

Otto.home();

delay(50);

// Otto.sing(S_happy); // a happy Otto :)

}

///////////////////////////////////////////////////////////////////

//-- Principal Loop ---------------------------------------------//

///////////////////////////////////////////////////////////////////

void loop() {

checkIRcode();

IR1key12.functionPointer = IR1key12Function;

IR1key16.functionPointer = IR1key16Function;

IR1key13.functionPointer = IR1key13Function;

IR1key15.functionPointer = IR1key15Function;

IR1key14.functionPointer = IR1key14Function;

IR1key1.functionPointer = IR1key1Function;

IR1key2.functionPointer = IR1key2Function;

IR1key3.functionPointer = IR1key3Function;

IR1key4.functionPointer = IR1key4Function;

IR1key5.functionPointer = IR1key5Function;

IR1key6.functionPointer = IR1key6Function;

IR1key7.functionPointer = IR1key7Function;

IR1key8.functionPointer = IR1key8Function;

IR1key9.functionPointer = IR1key9Function;

IR1key0.functionPointer = IR1key0Function;

IR1key10.functionPointer = IR1key10Function;

IR1key11.functionPointer = IR1key11Function;

}

小朋友,上面各按鍵的內容可利用下面的指令去【組合】,去創造出自己的舞蹈!!

***很奇怪,只要用到聲音的指令,遙控器就會失靈,這部分有空再來解決!!

動作指令:

void IRkeyUnsetFunction( ) { Serial.println("unknow!"); }

struct _Object {

void (* functionPointer)()=IRkeyUnsetFunction;

};

IRrecv ir_receiv(7);

String IR1keycode[17]={"ff4ab5","ff6897","ff9867","ffb04f","ff30cf","ff18e7","ff7a85","ff10ef","ff38c7","ff5aa5","ff52ad","ff42bd","ff629d","ff22dd","ff02fd","ffc23d","ffa857"};

struct _Object IR1key0, IR1key1, IR1key2, IR1key3, IR1key4, IR1key5, IR1key6, IR1key7, IR1key8, IR1key9, IR1key10;

struct _Object IR1key11, IR1key12, IR1key13, IR1key14, IR1key15, IR1key16, IR1key17, IR1key18, IR1key19, IR1key20, IR1key21;

void checkIRcode( ) {

if(ir_receiv.decode(&ir_results))

{

String keycode = String(ir_results.value, HEX);

Serial.print("keycode=");

Serial.println(keycode);

if(keycode == IR1keycode[0])

IR1key0.functionPointer();

else if(keycode == IR1keycode[1])

IR1key1.functionPointer();

else if(keycode == IR1keycode[2])

IR1key2.functionPointer();

else if(keycode == IR1keycode[3])

IR1key3.functionPointer();

else if(keycode == IR1keycode[4])

IR1key4.functionPointer();

else if(keycode == IR1keycode[5])

IR1key5.functionPointer();

else if(keycode == IR1keycode[6])

IR1key6.functionPointer();

else if(keycode == IR1keycode[7])

IR1key7.functionPointer();

else if(keycode == IR1keycode[8])

IR1key8.functionPointer();

else if(keycode == IR1keycode[9])

IR1key9.functionPointer();

else if(keycode == IR1keycode[10])

IR1key10.functionPointer();

else if(keycode == IR1keycode[11])

IR1key11.functionPointer();

else if(keycode == IR1keycode[12])

IR1key12.functionPointer();

else if(keycode == IR1keycode[13])

IR1key13.functionPointer();

else if(keycode == IR1keycode[14])

IR1key14.functionPointer();

else if(keycode == IR1keycode[15])

IR1key15.functionPointer();

else if(keycode == IR1keycode[16])

IR1key16.functionPointer();

ir_receiv.resume();

}

}

void IR1key12Function( ) {

Otto.walk(1,1000,1);//前進 //此行改成要按向上鍵時要執行的指令

}

void IR1key16Function( ) {

Otto.walk(1,1000,-1);//後退 //此行改成要按向下鍵時要執行的指令

}

void IR1key13Function( ) {

Otto.turn(1,1000,1);//左轉 //此行改成要按向左鍵時要執行的指令

}

void IR1key15Function( ) {

Otto.turn(1,1000,-1);//右轉 //此行改成要按向右鍵時要執行的指令

}

void IR1key14Function( ) {

Otto.home();//歸位 //此行改成要按OK鍵時要執行的指令

}

void IR1key1Function( ) {

Otto.updown(1,1000,30);//大上升 //此行改成要按1鍵時要執行的指令

}

void IR1key2Function( ) {

Otto.moonwalker(1,1000,30,1); //月球漫步向左走 //此行改成要按2鍵時要執行的指令

}

void IR1key3Function( ) {

Otto.moonwalker(1,1000,30,-1); //月球漫步向右走 //此行改成要按3鍵時要執行的指令

}

void IR1key4Function( ) {

Otto.swing(1,1000,30);//搖擺 //此行改成要按4鍵時要執行的指令

}

void IR1key5Function( ) {

Otto.flapping(1,1000,30,1); //左撲 //此行改成要按5鍵時要執行的指令

}

void IR1key6Function( ) {

Otto.flapping(1,1000,30,-1); //此行改成要按6鍵時要執行的指令

}

void IR1key7Function( ) {

Otto.tiptoeSwing(1,1000,30); //墊腳尖 //此行改成要按7鍵時要執行的指令

}

void IR1key8Function( ) {

Otto.bend(1,1000,1); //向左彎曲 //此行改成要按8鍵時要執行的指令

}

void IR1key9Function( ) {

Otto.bend(1,1000,-1); //向右彎曲 //此行改成要按9鍵時要執行的指令

}

void IR1key0Function( ) {

Otto.shakeLeg(1,1000,1); //搖右腳 //此行改成要按0鍵時要執行的指令

}

void IR1key10Function( ) {

Otto.shakeLeg(1,1000,-1); //搖左腳 //此行改成要按*鍵時要執行的指令

}

void IR1key11Function( ) {

Otto.jitter(1,1000,30); //雙腳抖動 //此行改成要按#鍵時要執行的指令

預定的運動函式

//-- Predetermined Motion Functions

void jump(float steps=1, int T = 2000);

void walk(float steps=4, int T=1000, int dir = FORWARD);

void turn(float steps=4, int T=2000, int dir = LEFT);

void bend (int steps=1, int T=1400, int dir=LEFT);

void shakeLeg (int steps=1, int T = 2000, int dir=RIGHT);

void updown(float steps=1, int T=1000, int h = 20);

void swing(float steps=1, int T=1000, int h=20);

void tiptoeSwing(float steps=1, int T=900, int h=20);

void jitter(float steps=1, int T=500, int h=20);

void ascendingTurn(float steps=1, int T=900, int h=20);

void moonwalker(float steps=1, int T=900, int h=20, int dir=LEFT);

void crusaito(float steps=1, int T=900, int h=20, int dir=FORWARD);

void flapping(float steps=1, int T=1000, int h=20, int dir=FORWARD);

音效指令:(所發出的聲音於附件)(註:上面程式只要用到聲音的指令,遙控器就會失靈,這部分有空再來解決!!)

官方提供的動作與聲音的組合:

  • Otto.playGesture(OttoHappy); //好開心

  • Otto.playGesture(OttoSuperHappy); //超開心

  • Otto.playGesture(OttoSad); //傷心

  • Otto.playGesture(OttoSleeping); //睡覺

  • Otto.playGesture(OttoFart); //放屁

  • Otto.playGesture(OttoConfused); //迷惑

  • Otto.playGesture(OttoLove); //愛

  • Otto.playGesture(OttoAngry); //生氣

  • Otto.playGesture(OttoFretful); //煩躁

    • Otto.playGesture(OttoMagic); //神奇

  • Otto.playGesture(OttoWave); //波動

  • Otto.playGesture(OttoVictory); //勝利

  • Otto.playGesture(OttoFail); //失敗

(註:上面動作只要用到聲音的指令,遙控器就會失靈,這部分有空再來解決!!)