2015年11月21日 星期六

ROSA 系統開發 14 ─ Control meArm by IR

https://4rdp.blogspot.com/2015/11/rosa-14-control-mearm-by-ir.html

紅外線遙控能用於 meArm 嗎?答案是可以的,考量許多玩家沒有 mBot 紅外線遙控器,因此另外準備一隻遙控器以及能與 Arduino 相接的紅外線接收器,如上圖所示。

// (C) 2015, Bridan Wang, CC BY-NC-SA 3.0 TW
// http://4rdp.blogspot.tw/search/label/ROSA%20(Arduino)

const byte IR_CODE[][18] PROGMEM = {
//  X, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, *, #,up,dn,rt,lf,ok
    0,22,25,13,12,24,94, 8,28,90,82,66,74,70,21,67,68,64,
    0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1,
};

void (*FUNC_JUMP[])(void) = {
  FUNC_N,            // none
  FUNC_1,            // 1
  FUNC_N, // FUNC_2, // 2
  FUNC_3,            // 3
  FUNC_4,            // 4
  FUNC_N, // FUNC_5, // 5
  FUNC_6,            // 6
  FUNC_N, // FUNC_7, // 7
  FUNC_N, // FUNC_8, // 8
  FUNC_N, // FUNC_9, // 9
  FUNC_N, // FUNC_0, // 0
  FUNC_S,            // *
  FUNC_P,            // #
  FUNC_N, // FUNC_U, // up
  FUNC_N, // FUNC_D, // down
  FUNC_R,            // right
  FUNC_L,            // left
  FUNC_N, // FUNC_K  // ok
};

void PROCESS_10ms(void){
  IR_CHECK();

  if (A_IN(A4) < 200){   // right X
    if (servo_set[2] > 120) servo_set[2]--;
  }
  else if (A_IN(A4) >= 800){
    if (servo_set[2] < 160) servo_set[2]++;
    else servo_hold[2] = 255;
  }
  else
    servo_hold[2] = 0;

  if (A_IN(A0) < 200){   // left Y
    if (servo_set[4] > 60) servo_set[4]--;
  }
  else if (A_IN(A0) >= 800) {
    if (servo_set[4] < 150) servo_set[4]++;
  }
  if (A_IN(A1) < 200){   // left X
    if (servo_set[1] != 0) servo_set[1]--;
  }
  else if (A_IN(A1) >= 800){
    if (servo_set[1] < 180) servo_set[1]++;
  }
  if (A_IN(A3) < 200){   // right Y
    if (servo_set[3] > 60) servo_set[3]--;
  }
  else if (A_IN(A3) >= 800) {
    if (servo_set[3] < 150) servo_set[3]++;
  }
}

byte pre_ir;
byte ir_code;
byte step_no = 0;

void IR_CHECK() {   // for KEYES IR
  byte i;
  byte j;
  j = ir.key();
  // Serial.print("IR - ");
  // Serial.println(j);
  for (i = 17; i != 0; i--) {
    if (j == pgm_read_byte(&IR_CODE[0][i])) {
      if (pgm_read_byte(&IR_CODE[1][i])==0 || pre_ir!=j) {
        pre_ir = ir_code;
        ir_code = i;
        step_no = 0;
        (*FUNC_JUMP[i])();
break;
      }
    }
  }
  ir.loop();
}

void FUNC_N(void)  // none
{
}

void FUNC_1(void)  // left Y
{
  if (servo_set[4] < 150) servo_set[4]++;
}

void FUNC_4(void)
{
  if (servo_set[4] > 60) servo_set[4]--;
}

void FUNC_3(void)  // right Y
{
  if (servo_set[3] < 150) servo_set[3]++;
}

void FUNC_6(void)
{
  if (servo_set[3] > 60) servo_set[3]--;
}

void FUNC_S(void)  // right X
{
  if (servo_set[2] < 160) servo_set[2]++;
  else servo_hold[2] = 255;
}

void FUNC_P(void)
{
  if (servo_set[2] > 120) servo_set[2]--;
}

void FUNC_R(void)  // left X
{
  if (servo_set[1] != 0) servo_set[1]--;
}

void FUNC_L(void)
{
  if (servo_set[1] < 180) servo_set[1]++;
}


除了參考前文 ROSA 系統開發 12 ─ SERVO 驅動及 ROSA 系統開發 13 ─ SERVO 多工同步控制程式碼外,紅外線接收器模組建議使用 pin D2,並把 IR_CHECK() 安插在 PROCESS_10ms(),如果把 IR_CHECK() 放在 PROCESS_100ms(),會感覺馬達轉動頓頓的,那是因為 100 ms 時間間隔太長轉動不連順,IR_CHECK()運用函數指標陣列 (Array of Function Pointers)技巧可直接跳至副程式執行,少了 switch case 判別式,程式碼看起來清爽許多。IR_CODE 陣列第一行儲存紅外線遙控碼,第二行儲存遙控碼是否被禁止連續發射,0 並未被禁止。

外,PROCESS_10ms()有些與 FUNC_X()重複程式碼,在此先不整合,因為下一章節還會有程式改作。最後,引用 ROSA 系統開發 10 ─ 蜂鳴器 (Buzzer) 程式,將 mBot 紅外線遙控碼改成 KEYES 遙控器碼,然後定義遙控器按鍵功能,


KEY
FUNCTION
CODE
1
左側馬達前進
22
4
左側馬達後退
12
左旋
68
右轉
67
3
右側馬達前進
13
6
右側馬達後退
94
#
夾子開
74
*
夾子閉
66

pre_ir、ir_code 與 step_no 三變數是預留給程序控制使用的。

沒有留言:

張貼留言