概述

在第二课中介绍了如何控制电机,这一课中我们会简介如何用红外遥控器控制坦克小车运动。

工作原理

坦克小车上有一个红外接收器,当遥控器按下按键,红外接收器会接收红外信号,arduino会把这个红外信号解码这个红外信号,每个按键对应一个不同的红外信号,当arduino接收到不同的红外信号后执行不同的操作,实现不同的功能。例如,arduino接收到遥控器上“1”对应的红外信号后坦克小车前进;接收到“2”对应的红外信号小车后退。

软件

下载https://osoyoo.com/driver/tank_robot_lesson3.zip并解压文件,用arduino IDE打开tank_robot_lesson3.ino文件,下面对代码做简要说明。

将要用到按键的红外编码在软件中做如下定义,每个按键的红外编码可以烧录第一课中的代码,对着红外接收器按遥控器,Serial Monitor就会打印出对应按键的红外编码。

#define IR_ADVANCE       0x00FF18E7       //code from IR controller "▲" button
#define IR_BACK          0x00FF4AB5       //code from IR controller "▼" button
#define IR_RIGHT         0x00FF5AA5       //code from IR controller ">" button
#define IR_LEFT          0x00FF10EF       //code from IR controller "<" button
#define IR_SERVO         0x00FF38C7       //code from IR controller "OK" button
#define IR_OPENLED       0x00FFB04F       //code from IR controller "#" button
#define IR_CLOSELED      0x00FF6897       //code from IR controller "*" button
#define IR_BEEP          0x00FF9867       //code from IR controller "0" button

在本课中我们用到的按键和对应的功能如下表所示

按键名 对应功能
前进
后退
> 右转
< 左转
OK 旋转舵机
# 打开LED
* 关闭LED
0 蜂鸣器响

通过枚举类型定义上表中各个功能对应代码

enum DN
{ 
  GO_ADVANCE, //go ahead
  GO_LEFT, //left turn
  GO_RIGHT,//right turn
  GO_BACK,//go back
  MOVE_SERVO,//move servo
  OPEN_LED,//open led
  CLOSE_LED,//close led
  BEEP,//control buzzer
  DEF
}Drive_Num=DEF;

解码红外信号

void do_IR_Tick()
{
  if(IR.decode(&IRresults))
  {
    if(IRresults.value==IR_ADVANCE)
    {
      Drive_Num=GO_ADVANCE;
    }
    else if(IRresults.value==IR_RIGHT)
    {
       Drive_Num=GO_RIGHT;
    }
    else if(IRresults.value==IR_LEFT)
    {
       Drive_Num=GO_LEFT;
    }
    else if(IRresults.value==IR_BACK)
    {
        Drive_Num=GO_BACK;
    }
    else if(IRresults.value==IR_SERVO)
    {
        Drive_Num=MOVE_SERVO;
    }
    else if(IRresults.value==IR_OPENLED)
    {
      Drive_Num=OPEN_LED;
    }
    else if(IRresults.value==IR_CLOSELED)
    {
      Drive_Num=CLOSE_LED;
    }
    else if(IRresults.value==IR_BEEP)
    {
      Drive_Num=BEEP;
    }
    IRresults.value = 0;
    IR.resume();
  }
}

通过调用IR.decode(&IRresults)将红外信号解码结果存储在IRresults.value变量中,将IRresults.value变量与预定义的按键红外编码比较,如果相等,就把对应的功能代码赋值给枚举变量Drive_Num。

void do_Drive_Tick()
{
    switch (Drive_Num) 
    {
      case GO_ADVANCE:
            go_ahead(10);JogFlag = true;JogTimeCnt = 1;JogTime=millis();break;//if GO_ADVANCE code is detected, then go advance
      case GO_LEFT:
            turn_left(10);JogFlag = true;JogTimeCnt = 1;JogTime=millis();break;//if GO_LEFT code is detected, then turn left
      case GO_RIGHT:
            turn_right(10);JogFlag = true;JogTimeCnt = 1;JogTime=millis();break;//if GO_RIGHT code is detected, then turn right
      case GO_BACK:
            go_back(10);JogFlag = true;JogTimeCnt = 1;JogTime=millis();break;//if GO_BACK code is detected, then backward
      case MOVE_SERVO:
            move_servo();JogFlag = true;JogTimeCnt = 1;JogTime=millis();break;//move servo
      case OPEN_LED:
            open_led(1),open_led(2);JogTime = 0;break;//open led
      case CLOSE_LED:
            close_led(1),close_led(2);JogTime = 0;break;//close led
      case BEEP:
            control_beep();JogTime = 0;break;//control beep
      default:break;
    }
    Drive_Num=DEF;
   //keep current moving mode for  200 millis seconds
    if(millis()-JogTime>=200)
    {
      JogTime=millis();
      if(JogFlag == true) 
      {
        stopFlag = false;
        if(JogTimeCnt <= 0) 
        {
          JogFlag = false; stopFlag = true;
        }
        JogTimeCnt--;
      }
      if(stopFlag == true) 
      {
        JogTimeCnt=0;
        go_stop();
      }
    }
}

在do_Drive_Tick()函数中,判断Drive_Num变量的值并执行对应的功能函数。

void open_led(int led_num)
{
  if (led_num == 1)  digitalWrite(LED1,LOW);
  else digitalWrite(LED2,LOW);
}
void close_led(int led_num)
{
   if (led_num == 1)  digitalWrite(LED1,HIGH);
   else digitalWrite(LED2,HIGH);
}
/*******control buzzer*******/
void control_beep()
{
  digitalWrite(BUZZER,LOW),delay(100);
  digitalWrite(BUZZER,HIGH),delay(100);
}
/***move servo***/
void move_servo()
{
  int i;
   for(i = 0;i<180;i++){ head.write(i); delay(5); } for(i = 180;i>=0;i--){
     head.write(i);
     delay(5);
  }
  head.write(90);
}

上面的4个函数分别用于控制LED的打开、关闭、控制蜂鸣器响以及让舵机从0度转到180度,再从180度转到0度,最后回到90度。

用usb线把坦克下车与pc连接起来,选择正确的板子型号和端口号,将程序烧录到arduino中,打开电池盒电源,将遥控器对着红外接收器按按键,如果所按按键是程序预先定义好的,小车将执行相应的功能函数;如果所按按键是程序未定义的,小车不做任何操作。