基于android手机的3G+GPS远程控制模型车工程-arduino单片机编程

        最近被CSDN的密码泄露整的很郁闷,人人账号google账号豆瓣……各种账号被锁了一大片(居然网店用泄露锁账号邮件做广告的……),幸好没有用QQ的邮箱来注册,要不然连QQ都要被锁了……话说联通也真够气人的,我是才发现原来联通各种收不到验证短信,解锁账号着实是大费周折。郁闷之余还是很淡定的回CSDN继续写博客了……毕竟这里的帖代码模板不错,最主要对搜索引擎的支持让人觉得非常舒服,气愤归气愤,但还是继续在CSDN上写吧……

      在开始介绍arduino和程序之前还是先谈一下单片机和手机、车模的接口吧。接口这个概念做软件的都理解的很透彻而且也深知它的重要性,但是做硬件的哥哥们就不同了,我见过的“校园派”单片机达人们都是以实现作为目标的,即如何达到功能的要求,而从来不去着重考虑对外层提供的接口,往往是实现了就完事儿,几乎没有可扩展性和可重用性。

      首先说说相对简单的对车模的接口,模型的控制(精密模型,不是玩具的那些)习惯是用低频的PWM实现的,这也是我之前选用用舵机和电调的车模的原因。这样最基础的接口只要可以提供两路PWM的输出就可以了(注意,传感器应该是属于单片机部分的,而不属于车模)。

      接下来是与手机的接口,手机与单片机最适用的通讯接口就是蓝牙串口了,鉴于常用的蓝牙串口模块是用9600bit/s的串口与单片机通信的,所以单片机所有的控制和反馈信号都需要通过串口用串行数据发送。在我们的设计中,单片机和车是作为一个整体的,外界对他的控制只有前进转向等基本的控制,具体PWM的占空比是多杀,控制哪个IO口为输出口这些是不用上层的手机来考虑的,该车可以过滤不符合要求的控制指令。所以我们提供两种类型的控制接口(两套控制指令),一种是只有左右转和前进后退,另一种是对转向的程度和行进的速度进行分级(目前是分为7级),另外还要提供一个用于测试连接稳定性的反馈响应和一个基本没有用的help……(后期的程序还有电量测量和遥控器控制),为了保证在出现连接意外断开之类的危险情况出现时可以迅速停车(同时考虑到异步串口不能持续的发送控制命令占用信道),每一条控制命令都有一个控制时限,超过时限时没有新的命令到达就需要及时停车防止碰撞。同时作为实时性要求相对较高的控制,我们的任务队列也是采用抢占式的,即后面来的命令(可用命令)无条件的覆盖前一条命令,不会等到上一条命令执行完成。

      至于命令的格式,为了调试的方便都是使用asic2词组作为命令的,我们这里模仿了一下霍夫曼编码,对于常用的和要求响应非常快的命令使用较短的编码,这样来提高响应的速度,减少浪费在龟速的串口通信上浪费的各种时间,例如最常用的检测检测连通用的信号为"A" (后来很悲剧的没在用了……),电量检测为“B”,所有控制命令前缀为C(command),停车归位为“CR”(command reset),CTR、CTL、CT1~7为转向的命令,CMF、CMB、CM1~7为速度的控制命令。 

      有一个东西比较重要,就是商品电调的控制问题,它的启动需要特定的信号才行(有可能只是维持一段时间的电平),这个我是整了好久才整明白的,参见下面链接中的帖子:

      http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4931648&bbs_page_no=1&bbs_id=1025

      单片机的各种基础知识这里就不废话了,反正用到的单片机都是需要花大工夫去学的,下面就直接贴arduino的代码了,arduino的代码非常简单,用其他单片机的一看就知道该怎么改了。

      下面的两段代码第一段是最基础的实现,第二段是加上了电量检测和遥控器劫持控制的(第二段的原理就不做介绍了,反正用得着的肯定是可以自己弄明白的了……)

      咳咳,帖代码前再啰嗦一句……arduino的编译环境不支持中文,所以注释都是用英文写的,这个……英文学得不好,莫笑话,莫笑话……………………T^T


代码一:基础程序

// Controlling car using blue tooth 
// by lynx at sise.ynu.edu.cn QQ:84693469


/**
*  TODO List   1.We will add Anti-unconnect function but we can only let the car stop when 'long time no data'....
*/


#include  
 
Servo ServoRight;  // create servo object to control a servo ,The bigger is to turn right 
Servo ServoForward;  // create servo object to control a servo ,The bigger is to go forward
 
int valLR;    // variable to turn LEFT to RIGHT 
int valBF;    // variable to go BEHIND to FORWARD

int constMiddle = 90;      //The parameter to TURN middle
int constStop = 95;        //The paramater to STOP

int constTurnMAX = 20;   //The maximum number can add to constMiddle
int constSpeedMax = 40;  //The maximum number can add to constStop

int serialBuffer;  //Save one byte serial data

int timeOut = 1000;    //When counter flut out, stop
int timeOutCounter = 0;  //Count every loop to judge time out or not
 
void setup() 
{ 
  ServoRight.attach(9);  // attaches the servo on pin 9 to the servo object
  ServoForward.attach(10);  // attaches the servo on pin 10 to the servo object 
  Serial3.begin(9600);  //Using serial throught blue tooth
  Serial3.println("Initializing");
  
  delay(1500);  //Initializing the motor  DON'T REMOVE
  
  Serial3.println("Done. Let's rock!");
  
  ServoRight.write(constMiddle);                  // Keep stop
  ServoForward.write(constStop);
} 
 
void loop() 
{ 
  serialBuffer = Serial3.read();
  
  valLR = constMiddle;
  valBF = constStop;
  
  timeOutCounter++;
  delay(1);              //Make time out counter getting a milisconed counter
  if(timeOutCounter > timeOut)     //Time out then reset!
  {
    timeOutCounter = 0;
    
    valLR = constMiddle;
    valBF = constStop;
    ServoRight.write(valLR);                  // sets the servo position according to the scaled value
    ServoForward.write(valBF); 
    delay(50);                           // waits for the servo to get there
  }
  
  if (-1 != serialBuffer) {
    if ('A' == serialBuffer || 'a' == serialBuffer) 
    {          //This for response the upper MCU
      Serial3.println("A");
      timeOutCounter = 0;
    }
    if ('H' == serialBuffer || 'h' == serialBuffer) 
    {          //Help information
      Serial3.println("This is car contral system complied by Lynx@ynu");
      timeOutCounter = 0;
    }
    else if ('C' == serialBuffer || 'c' == serialBuffer)              //Here are the "Contral Commands"
    { 
      delay(2);                           // waits for read
      serialBuffer = Serial3.read();                                 //Read the next byte
      if ('R' == serialBuffer || 'r' == serialBuffer)          //Reset
      {
        valLR = constMiddle;
        valBF = constStop;
        ServoRight.write(valLR);                  // sets the servo position according to the scaled value
        ServoForward.write(valBF); 
        delay(50);                           // waits for the servo to get there
        timeOutCounter = 0;
      }
      else if ('S' == serialBuffer || 's' == serialBuffer)          //Stop
      {
        valBF = constStop;
        ServoForward.write(valBF); 
        delay(50);                           // waits for the servo to get there
        timeOutCounter = 0;
      }
      else if ('T' == serialBuffer || 't' == serialBuffer)          //Turn
      {
        delay(2);                           // waits for read
        serialBuffer = Serial3.read();                                 //Read the next byte
        if('L' == serialBuffer || 'l' == serialBuffer)     //Turn Left
        {
          valLR = constMiddle-constTurnMAX;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('R' == serialBuffer || 'r' == serialBuffer)     //Turn Right
        {
          valLR = constMiddle+constTurnMAX;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('M' == serialBuffer || 'm' == serialBuffer)     //Turn Middle
        {
          valLR = constMiddle;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('1' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle-constTurnMAX;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('2' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle-constTurnMAX*2/3;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('3' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle-constTurnMAX/3;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('4' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('5' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle+constTurnMAX/3;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('6' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle+constTurnMAX*2/3;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('7' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle+constTurnMAX;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
      }
      else if ('M' == serialBuffer || 'm' == serialBuffer)          //Move
      {
        delay(2);                           // waits for read
        serialBuffer = Serial3.read();                                 //Read the next byte
        if('F' == serialBuffer || 'f' == serialBuffer)     //Move forward
        {
          valBF = constStop+constSpeedMax/5;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('B' == serialBuffer || 'b' == serialBuffer)     //Move back
        {
          valBF = constStop-constSpeedMax/5;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('S' == serialBuffer || 's' == serialBuffer)     //Stop
        {
          valBF = constStop;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('1' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop-constSpeedMax;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('2' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop-constSpeedMax/3;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('3' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop-constSpeedMax/5;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('4' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('5' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop+constSpeedMax/5;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('6' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop+constSpeedMax/3;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('7' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop+constSpeedMax;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
      }
    }
  }
  
} 

代码二:带电量检测和遥控器劫持的代码

// Controlling car using blue tooth 
// by lynx at sise.ynu.edu.cn QQ:84693469 


/**
*  TODO List   1.We will add Anti-unconnect function but we can only let the car stop when 'long time no data'....
*/


#include  
 
Servo ServoRight;  // create servo object to control a servo ,The bigger is to turn right 
Servo ServoForward;  // create servo object to control a servo ,The bigger is to go forward
 
int valLR;    // variable to turn LEFT to RIGHT 
int valBF;    // variable to go BEHIND to FORWARD

int constMiddle = 90;      //The parameter to TURN middle
int constStop = 95;        //The paramater to STOP

int constTurnMAX = 20;   //The maximum number can add to constMiddle
int constSpeedMax = 40;  //The maximum number can add to constStop

int serialBuffer;  //Save one byte serial data

int timeOut = 1000;    //When counter flut out, stop
int timeOutCounter = 0;  //Count every loop to judge time out or not

int RadioTimeOut = 10000;  //About 0.1 second
int RadioTimeOutCounter = 10000;  //keep out at beginning

int BatteryV = 0;  //Battery valtage
int BatteryVMax = 1000;  //Battery filled
int BatteryVMin = 665;  //Battery empty
long BatteryVTmp = 0;  //Temp

int BatteryPin = 1;
int RadionPin1 = 6;
int RadionPin2 = 7;
int MotorPin1 = 9;
int MotorPin2 = 10;

int RadioHL = LOW;  //To save radio state
 
void setup() 
{ 
  pinMode(RadionPin1,INPUT);   //set digital pin 6 and 7 to read the radio signal
  pinMode(RadionPin2,INPUT);
  ServoRight.attach(MotorPin1);  // attaches the servo on pin 9 to the servo object
  ServoForward.attach(MotorPin2);  // attaches the servo on pin 10 to the servo object 
  Serial3.begin(9600);  //Using serial throught blue tooth
  Serial3.println("Initializing");
  
  delay(1500);  //Initializing the motor  DON'T REMOVE
  
  Serial3.println("Done. Let's rock!");
  
  ServoRight.write(constMiddle);                  // Keep stop
  ServoForward.write(constStop);
} 
 
void loop() 
{    
  /* Switch in Bluetooth and Radio */
  if(digitalRead(RadionPin1) != RadioHL)
  {
    RadioHL = digitalRead(RadionPin1);
    RadioTimeOutCounter = 0;
  }
  if(RadioTimeOutCounter < RadioTimeOut)
  {
    if(ServoRight.attached())
    {
      ServoRight.detach();
      ServoForward.detach();
    }
    digitalWrite(MotorPin1,digitalRead(RadionPin1));
    digitalWrite(MotorPin2,digitalRead(RadionPin2));
    RadioTimeOutCounter++;
    delayMicroseconds(10);
    return;  //When radio is active, unactive serial
  }
  if(!ServoRight.attached())
  {
    ServoRight.attach(MotorPin1);
    ServoForward.attach(MotorPin2);
  }
  
  /* Bluetooth contral */
  valLR = constMiddle;
  valBF = constStop;
  
  serialBuffer = Serial3.read();
  
  delay(1);              //Make time out counter getting a milisconed counter
  
  timeOutCounter++;
  if(timeOutCounter > timeOut)     //Time out then reset!
  {
    timeOutCounter = 0;
    
    valLR = constMiddle;
    valBF = constStop;
    ServoRight.write(valLR);                  // sets the servo position according to the scaled value
    ServoForward.write(valBF); 
    delay(50);                           // waits for the servo to get there
  }
  
  if (-1 != serialBuffer) {
    if ('A' == serialBuffer || 'a' == serialBuffer) 
    {          //This for response the upper MCU
      Serial3.println("A");
      timeOutCounter = 0;
    }
    else if ('B' == serialBuffer || 'b' == serialBuffer) 
    {          //Battery voltage
      BatteryV = analogRead(BatteryPin);
      delayMicroseconds(150);
      BatteryVTmp = BatteryV-BatteryVMin;
      BatteryVTmp = BatteryVTmp*100/(BatteryVMax-BatteryVMin);
      Serial3.println(BatteryVTmp);  //print the percentage
      timeOutCounter = 0;
    }
    else if ('H' == serialBuffer || 'h' == serialBuffer) 
    {          //Help information
      Serial3.println("This is car contral system complied by Lynx@ynu");
      timeOutCounter = 0;
    }
    else if ('C' == serialBuffer || 'c' == serialBuffer)              //Here are the "Contral Commands"
    { 
      delay(2);                           // waits for read
      serialBuffer = Serial3.read();                                 //Read the next byte
      if ('R' == serialBuffer || 'r' == serialBuffer)          //Reset
      {
        valLR = constMiddle;
        valBF = constStop;
        ServoRight.write(valLR);                  // sets the servo position according to the scaled value
        ServoForward.write(valBF); 
        delay(50);                           // waits for the servo to get there
        timeOutCounter = 0;
      }
      else if ('S' == serialBuffer || 's' == serialBuffer)          //Stop
      {
        valBF = constStop;
        ServoForward.write(valBF); 
        delay(50);                           // waits for the servo to get there
        timeOutCounter = 0;
      }
      else if ('T' == serialBuffer || 't' == serialBuffer)          //Turn
      {
        delay(2);                           // waits for read
        serialBuffer = Serial3.read();                                 //Read the next byte
        if('L' == serialBuffer || 'l' == serialBuffer)     //Turn Left
        {
          valLR = constMiddle-constTurnMAX;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('R' == serialBuffer || 'r' == serialBuffer)     //Turn Right
        {
          valLR = constMiddle+constTurnMAX;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('M' == serialBuffer || 'm' == serialBuffer)     //Turn Middle
        {
          valLR = constMiddle;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('1' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle-constTurnMAX;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('2' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle-constTurnMAX*2/3;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('3' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle-constTurnMAX/3;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('4' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('5' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle+constTurnMAX/3;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('6' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle+constTurnMAX*2/3;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('7' == serialBuffer)     //Turn Level(1~7 that 4 is the middle)
        {
          valLR = constMiddle+constTurnMAX;
          ServoRight.write(valLR);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
      }
      else if ('M' == serialBuffer || 'm' == serialBuffer)          //Move
      {
        delay(2);                           // waits for read
        serialBuffer = Serial3.read();                                 //Read the next byte
        if('F' == serialBuffer || 'f' == serialBuffer)     //Move forward
        {
          valBF = constStop+constSpeedMax/5;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('B' == serialBuffer || 'b' == serialBuffer)     //Move back
        {
          valBF = constStop-constSpeedMax/5;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('S' == serialBuffer || 's' == serialBuffer)     //Stop
        {
          valBF = constStop;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('1' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop-constSpeedMax;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('2' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop-constSpeedMax/3;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('3' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop-constSpeedMax/5;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('4' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('5' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop+constSpeedMax/5;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('6' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop+constSpeedMax/3;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
        else if('7' == serialBuffer)     //Move level(1~7 where 4 is the middle)
        {
          valBF = constStop+constSpeedMax;
          ServoForward.write(valBF);                  // sets the servo position according to the scaled value
          delay(50);                           // waits for the servo to get there
          timeOutCounter = 0;
        }
      }
    }
  }
  
} 


你可能感兴趣的:(玩具改装,单片机)