GR-ADZUKIでカムロボをリモコンで動かしてみよう


GR-ADZUKIをIRリモコンを動かしてみましょう。

GR-CITRUSとロボット覚醒プロジェクト第一弾
http://gadget.renesas.com/ja/product/cotton_sp9.html
http://gadget.renesas.com/ja/project/robot_s2/
を組み合わせています。

リモコンと受光部はAliexpressで100円以下（送料込み）で買えます。

まずは、Cottonのコードで入れてリモコンのコードを調べてみましょう
http://gadget.renesas.com/ja/product/cotton_sp9.html
・リモコンのボタンに応じてLEDを光らせる。
のプログラムをそのまま使用します。
赤外線受光部は、2番ピンにさします。

今回リモコンのコードを調べたところ以下の通りでした。

```
↑：46
←：44
→：43
OK：40
下：15

1:16
2:19
3:D
4:C
5:18
6:5E
7:8
8:1C
9:5A
0:42
*:52
#:4A
```

下記のコードは手持ちのリモコンを基にしていますので、ご自身のリモコンに合わせて書き換えます。
今回は、リモコンのボタンを押すと前進したり、後退したりさせようと思います。
サンプルコードから

```
      case 0xD8: // POWER BUTTON
        digitalWrite(22, LOW);
        delay(100);
        digitalWrite(22, HIGH);
        break;
```
とあるところを書き換えます。
例えば

```
前進:
        analogWrite(6, data);
        analogWrite(11, 0);
        analogWrite(9, data);
        analogWrite(10, 0);
```
dataに数値を入れれば指定速度で前進します。
これは、モータードライバーから各ピンに電気を出力するプログラムになります。
dataの数値を変えることでスピードが変わるので試してみてください。
さらに、この（6,11）（9,10）の組み合わせで前進、旋回、後退が可能になります。
まずは、ここを変えて動かしてみましょう。

次にCottonのサンプルをもとに

```
      case 0x46: // UP_Button
        analogWrite(6, 200);
        analogWrite(11, 0);
        analogWrite(9, 200);
        analogWrite(10, 0);
        break;
```
とします。
case xx;とは、xxと入力があった際に、次のことをしなさいとなります。
今回は、↑ボタンである0x46が入力されたら、前進しなさいとなります。
なお、case文は「break;」を入れないと次の入力を受け付けませんので必ず入れてください。

今回は、これをさらに、関数化します。

```
void xxx()｛
プログラム
｝
```

入れてみると

```
void up_move()  //UP
{
    digitalWrite(LED4, LOW);
    digitalWrite(LED5, LOW);
    analogWrite(9, 200);
    analogWrite(10, 0);
    analogWrite(6, 200);
    analogWrite(11, 0);
  }
```
となります。

up_move();と入れると、前進するプログラムを呼び出すようになります
これをさらに弄ると一定回前進して、後退するというプログラムも書くことが可能です。

```
#include <Arduino.h>

#define IR_PIN 2
#define IR_INTERRUPT 0
#define LED1 22
#define LED2 23
#define LED3 24
#define LED4 12
#define LED5 13

#define FORWARD   0
#define BACKWARD  1
#define RIGHT_MOTOR 200
#define LEFT_MOTOR  250
#define RIGHT_TH  1500
#define LEFT_TH   1500

uint8_t g_ir_data = 0;
bool    g_ir_available = false;

void ir_receive_interrupt();
void ir_receive_start();
uint8_t ir_getData();
bool ir_available();
double IRread ;

void motor1_init(){
  analogWrite(9, 0);
  analogWrite(10, 0);
}

void motor2_init(){
  analogWrite(6, 0);
  analogWrite(11, 0);
}

void up_move()  //UP
{
 // if (IRread<400)
 // {  
    digitalWrite(LED4, LOW);
    digitalWrite(LED5, LOW);
    analogWrite(9, 200);
    analogWrite(10, 0);
    analogWrite(6, 200);
    analogWrite(11, 0);
/*  }
  else
  {  
    digitalWrite(LED4, LOW);
    digitalWrite(LED5, LOW);
    analogWrite(9, 0);
    analogWrite(10, 0);
    analogWrite(6, 0);
    analogWrite(11, 0);
  }
*/
}
void left_move()  //left
{
  digitalWrite(LED4, LOW);
  digitalWrite(LED5, HIGH);
  analogWrite(9, 200);
  analogWrite(10, 0);
  analogWrite(6, 0);
  analogWrite(11, 0);
} 

void right_move()  //right
{
  digitalWrite(LED4, HIGH);
  digitalWrite(LED5, LOW);

  analogWrite(9, 0);
  analogWrite(10, 0);
  analogWrite(6, 200);
  analogWrite(11, 0);
} 

void back_move()  //back
{
  digitalWrite(LED4, HIGH);
  digitalWrite(LED5, LOW);
  analogWrite(9, 0);
  analogWrite(10, 200);
  analogWrite(6, 0);
  analogWrite(11, 200);
} 

void stop_move()  //back
{
  digitalWrite(LED4, HIGH);
  digitalWrite(LED5, LOW);
  analogWrite(9, 0);
  analogWrite(10, 0);
  analogWrite(6, 0);
  analogWrite(11, 0);
} 

void setup() {
  setPowerManagementMode(PM_STOP_MODE);
  Serial.begin(9600);
  pinMode(IR_PIN, INPUT_PULLUP);
  ir_receive_start();
  digitalWrite(LED1, HIGH);
  digitalWrite(LED2, HIGH);
  digitalWrite(LED3, HIGH);
  digitalWrite(LED4, LOW);
  digitalWrite(LED5, LOW);
  motor1_init();
  motor2_init();
  IRread=0;
}

void loop() {
  ir_receive_start();
  delay(0xFFFFFFFF); // hold STOP mode until receiving IR signal.

  if(ir_available()){
    IRread = analogRead(A0);
    Serial.println(IRread) ;       // 距離(ln有りで改行、無しで改行なし)
    Serial.println(ir_getData(), HEX);
    Serial.flush();
    int i;
    switch (ir_getData()) {
    case 0x46: // UP BUTTON   
      up_move();
      break;
    case 0x44: // Left BUTTON
      left_move();
      break;
    case 0x43: // Right BUTTON
      right_move();
      break;
    case 0x15: // BACK BUTTON
      back_move();
      break;
    case 0x40: // STOP
      motor1_init();
      motor2_init();

    default:
      break;
    }
  }   
}

/************ IR utility function ***************/
void ir_receive_interrupt(){

  unsigned long last_time;

  detachInterrupt(IR_INTERRUPT);
  last_time = micros();

  // confirm if reader code is correct
  uint8_t err = 0;
  while(!digitalRead(IR_PIN)){ // until change from low to high
    if((micros() - last_time) > 10000){ // interval low should be 9ms or less 
      err = true;
      break;
    }
  }
  while(digitalRead(IR_PIN)){ // until change from high to low
    if((micros() - last_time) > 15000){ // interval of reader code should be 13.5ms or less
      err = true;
      break;
    }
  }
  if(((micros() - last_time) < 13000) || (err == true)){ // Unknown code
    attachInterrupt(0, ir_receive_interrupt, FALLING);
    g_ir_available = false;
    return; // not available remote controller
  }

  // get data
  uint8_t receive_count = 0;
  uint8_t temp_ir_data[4] = {
    0                        };
  g_ir_data = 0;
  last_time = micros();
  while((32 > receive_count) && ((micros() - last_time) < 80000)){
    // interval of a frame data should be 76.5ms or less
    last_time = micros();
    while(!digitalRead(IR_PIN) && ((micros() - last_time) < 1000)){
      // interval of low state is about 0.56ms. 
    }
    while(digitalRead(IR_PIN) && ((micros() - last_time) < 2500)){
      // interval of a bit is between 1.125ms and 2.25ms
    }
    if((micros() - last_time) > 1500){
      bitSet(temp_ir_data[receive_count / 8], receive_count % 8);
    }
    receive_count++;
  }

  if(temp_ir_data[2] == (uint8_t)~temp_ir_data[3]){
    g_ir_data = temp_ir_data[2]; // set actual data
    g_ir_available = true;
  }

}

void ir_receive_start(){
  attachInterrupt(IR_INTERRUPT, ir_receive_interrupt, FALLING);
}

uint8_t ir_getData(){
  g_ir_available = false;
  return g_ir_data;
}

bool ir_available(){
  return g_ir_available;
}
```

カムロボットに入れたものです。
![cumrobot-GR-Adzuki-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/e55c1310-2104-6493-ea48-7c7bff08fd5f.jpeg)
![cumrobot-GR-Adzuki-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/8a2b1028-fd99-cf9d-e915-adc3d2e4c4df.jpeg)

サヌキテックネットさんの「9-2.カムプログラムロボットの制御 - (2)組み立てる前に」を参考にしてください。
https://sanuki-tech.net/micro-bit/tamiya/before-assembly-cam-program-robot/
私は、読まないでやったために余計な部品を取り付けており、正直失敗しました。
カムロボットとして使わない場合は、この通りに組むことをお勧めします。

近接センサーと、赤外線受光部は、両面テープで取り付けています。