哪位大神能帮我写一个arduino 控制两个直流电机正反转,加减速和拐弯的程序啊?arduino程序,非常感谢。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了哪位大神能帮我写一个arduino 控制两个直流电机正反转,加减速和拐弯的程序啊?arduino程序,非常感谢。相关的知识,希望对你有一定的参考价值。

我正在做遥控小车,这个程序编写还不太会,谢谢了。

       假设您使用无线串口控制小车,那么你需要设计一个串口指令协议,一般来说,通信协议的数据帧包括3部分,一是指令头,又叫做帧同步字;二是指令内容,也叫帧内容;三是校验码。

       同步字是为了便于程序分析连续传输的数据中,帧与帧之间的间隔,帧内容包含了所有经过16进制编码的各种控制指令和数据,校验码通常采用累加和与异或算法,为了计算本数据帧是否正确。(工业环境中,所有数据传输系统都存在一定的误码干扰,校验字能有效判别数据传输是否正确,进而通过错误处理机制,有效避免错误动作)。

       刚好前段时间写了个小车的控制程序,使用的是双路H桥来驱动电机的,不过不是控制履带式的,稍微改动了下。

    (注意,本程序仅适用于履带式小车,即左右电机正反转实现前后及转向,程序支持前后左右混控)


//********************************

// 遥控帧协议和结构

// FB|80|51|AA|FF|BB|FF|BY|BY|BY|BY|BY|BY|CR

// 00|01|02|03|04|05|06|07|08|09|10|11|12|13

// 14 byte

//FB 80 51 遥控帧同步字                 00-02

//AA 前后控制量 128为中立位             03

//FF 恒定为0xFF                         04

//BB 左右控制量 128为中立位             05

//FF 恒定为0xFF                         06

//BY 备用控制指令 本程序为空            07-12

//CR 校验码,从00至12字节逐字节位异或   13

//********************************

// 遥测帧协议结构

// FB|80|61|AA|FF|BB|FF|BY|BY|BY|BY|BY|BY|CR

// 00|01|02|03|04|05|06|07|08|09|10|11|12|13

// 14 byte

// 重复遥控指令,除帧头外,其定义与遥控指令相同


#define BR 9600       //定义串口波特率

//遥控指令接收处理相关定义

#define TCDL 14       //定义遥控数据帧长度字节数

#define BUFF_LONG 30  //定义串口接收缓存的长度

byte BUFF[BUFF_LONG]; //定义串口数据接收存储缓存

int BUFF_IDX = 0;     //定义串口数据接收存储缓存的指针


//遥测指令发送处理相关定义

#define TMFQ 80         //定义遥测数据帧发送间隔为80ms

#define TMDL 14         //定义遥测数据帧长度字节数

byte TM_Data[TMDL];     //定义遥测数据缓存

int TM_Index = 0;       //定义遥测数据指针

unsigned long Time = 0; //定义遥测发送计时器为0


//定义左、右电机与Arduino的驱动信号接口

//注意,这里用了4个PWM输出,部分Arduino板可能不支持,请查看手册

int Moto_Right_A = 3;

int Moto_Right_B = 5;

int Moto_Left_A = 6;

int Moto_Left_B = 9;


//数据接收指示灯相关定义

boolean IS_Blink = false;     //定义是否闪烁LED灯的变量

int LED = 13;         //定义LED灯接口为13


//指令变量定义

byte RunPWM = 128;   //定义前进、后退控制PWM指令变量

byte TurnPWM = 128;  //定义左转、右转控制PWM指令变量


void setup()

  pinMode(Moto_Right_A, OUTPUT); //定义输出

  pinMode(Moto_Right_B, OUTPUT); //定义输出

  pinMode(Moto_Left_A, OUTPUT); //定义输出

  pinMode(Moto_Left_B, OUTPUT); //定义输出

  pinMode(LED, OUTPUT); //定义LED管脚为数字输出


  Port_Init();  //初始化串口

  Blink_LED(false); //关闭指示灯

void loop()

  byte c;

  if (Serial.available() > 0)  //如果接收到串口数据

 

    c = Serial.read();   //读一个字节

    Buff_AddChar(c);     //塞进缓存进行存储、校验和解码

 

  TM_Freq();             //尝试按要求逐字节发送遥测数据

  Driver_CAR(RunPWM, TurnPWM); //驱动左右电机正反转,实现运动控制


//驱动左右电机调速运行,实现左右正反转组合,实现控制

//前后、左右混控

void Driver_CAR(byte Run, byte Turn)

  byte Run_L, Run_R;  //定义左右前进混合值

  byte PWM_R_A, PWM_R_B, PWM_L_A, PWM_L_B; // 定义4个信号的独立PWM


  Run_L = Run - (128 - Turn);  //将转向PWM混合到左路

  Run_R = Run - (Turn - 128);  //将转向PWM混合到右路


  PWM_L_A = (255 / 128) * Run_L - 255;         //左路混合值结算为左路A信号PWM

  PWM_L_B = (-1 * 255 / 128) * Run_L + 255;    //左路混合值结算为左路B信号PWM

  PWM_R_A = (255 / 128) * Run_R - 255;         //右路混合值结算为右路A信号PWM

  PWM_R_B = (-1 * 255 / 128) * Run_R + 255;    //右路混合值结算为右路B信号PWM


  analogWrite(Moto_Right_A, PWM_R_A);    //输出右路A信号

  analogWrite(Moto_Right_B, PWM_R_B);    //输出右路B信号

  analogWrite(Moto_Left_A, PWM_L_A);     //输出左路A信号

  analogWrite(Moto_Left_B, PWM_L_B);     //输出左路B信号


//********************************

//子程序 Port_Init()

//功能:初始化串口通信

void Port_Init()

  BUFF_IDX = 0;  //初始化串口缓存指针为0

  TM_Data[0] = 0xFB;  //初始化遥测数据帧头

  TM_Data[1] = 0x80;  //初始化遥测数据帧头

  TM_Data[2] = 0x61;  //初始化遥测数据帧头

  Serial.begin(BR);  //定义波特率并启动串口


//********************************

// 子程序 Buff_AddChar(byte b)

// 功能:串口接收字节加入缓存

// 1、加入字节到缓存;

// 2、检测到帧头则尝试检测遥控帧;

// 3、管理缓存指针

void Buff_AddChar(byte b)

  BUFF[BUFF_IDX] = b;  //  缓存[缓存指针] = 接收字节

  if (BUFF_IDX >= 2)

 

    if (BUFF[BUFF_IDX] == 0x51 && BUFF[BUFF_IDX - 1] == 0x80 && BUFF[BUFF_IDX - 2] == 0xFB) //  检测遥控帧头

   

      if (BUFF_IDX == (TCDL - 1))

     

        Buff_DCHK();  //  检测校验码

     

      BUFF_IDX = 0;  //  缓存指针归零

      return;

   

 

  BUFF_IDX++;

  if (BUFF_IDX > (BUFF_LONG - 1)) //  缓存指针越界

 

    BUFF_IDX = 0;  //  缓存指针归零

 


//********************************

//子程序 Buff_DCHK()

//功能:校验遥控帧校验字是否正确

void Buff_DCHK()

  byte DCHK = 0x00;

  // 0xFB XOR 0x80 XOR 0x51

  DCHK = BUFF[0];

  DCHK = DCHK ^ BUFF[1];

  DCHK = DCHK ^ BUFF[2];

  int i;

  for (i = 0; i < (TCDL - 4); i++)

 

    DCHK = DCHK ^ BUFF[i];

 

  if (DCHK == BUFF[TCDL - 4])

 

    //校验字正确

    Blink_LED(true); //闪烁LED

    Get_CMD();       //解码指令

 

//********************************

// 子程序 Get_CMD()

// 功能:解码遥控指令

void Get_CMD()

  RunPWM = BUFF[0];

  TurnPWM = BUFF[2];


  //后面可以自己添加关于BY指令的解码处理


//********************************

//子程序 TM_Freq()

//功能:遥测数据发送帧率控制

void TM_Freq()

  unsigned long t;

  if (TM_Index < TMDL) //如果一帧数据还没有发完

 

    Serial.write(TM_Data[TM_Index]); //继续发数据

    TM_Index++;  //指针累加

 

  else  //如果发完

 

    if (Time == 0)  //检测计时器是否为0

   

      Time = millis(); //是则赋予计时器初始值

   

    else  //不是

   

      t = millis();

      if (t - Time >= TMFQ) //检测计时器是否到达帧率控制的时间

     

        Time = t;

        TM_Make_Data();    //到达发送时间,则组一帧遥测数据,并开始发送

     

   

 

//********************************

// 子程序 TM_Make_Data()

// 功能:发送遥测数据

void TM_Make_Data()

  // 遥测帧协议结构

  //FB|80|61|AA|FF|BB|FF|BY|BY|BY|BY|BY|BY|CR

  //00|01|02|03|04|05|06|07|08|09|10|11|12|13

  byte CHK = 0xFB;  //赋值帧头

  CHK = CHK ^ 0x80; //赋值帧头

  CHK = CHK ^ 0x61; //赋值帧头


  TM_Data[3] = RunPWM;    //回写前后指令

  TM_Data[4] = 0xFF;

  CHK = CHK ^ TM_Data[3]; //计算校验码

  CHK = CHK ^ TM_Data[4]; //计算校验码


  TM_Data[5] = TurnPWM;   //回写转向指令

  TM_Data[6] = 0xFF;

  CHK = CHK ^ TM_Data[5]; //计算校验码

  CHK = CHK ^ TM_Data[6]; //计算校验码


  CHK = CHK ^ TM_Data[7]; //计算校验码

  CHK = CHK ^ TM_Data[8]; //计算校验码

  CHK = CHK ^ TM_Data[9]; //计算校验码

  CHK = CHK ^ TM_Data[10]; //计算校验码

  CHK = CHK ^ TM_Data[11]; //计算校验码

  CHK = CHK ^ TM_Data[12]; //计算校验码


  TM_Data[13] = CHK; //计算校验码

  TM_Index = 0; //清除遥测发送指针位置

//********************************

//子程序 Blink_LED()

//功能:闪烁内置LED灯

void Blink_LED(boolean Blink)

  if (Blink == false)

 

    IS_Blink = false;

 

  else

 

    IS_Blink = !IS_Blink;

 

  digitalWrite(LED, IS_Blink);


参考技术A #includetemplatevoidinsertion_sort(biIterbegin,biIterend)typedeftypenamestd::iterator_traits::value_typevalue_type;biIterbond=begin;std::advance(bond,1);for(;bond!=end;std::advance(bond,1))value_typekey=*bond;biIterins=bond;biIterpre=ins;std::advance(pre,-1);while(ins!=begin&&*pre>key)*ins=*pre;std::advance(ins,-1);std::advance(pre,-1);*ins=key; 参考技术B 我做电子设计的

使用 H-Bridge 和 neopixel 以及 Arduino UNO 控制直流电机

【中文标题】使用 H-Bridge 和 neopixel 以及 Arduino UNO 控制直流电机【英文标题】:Control dc-motor using H-Bridge and neopixel together with Arduino UNO 【发布时间】:2018-06-19 11:35:16 【问题描述】:

我正在做一个项目,用 H 桥控制直流电机的前后旋转。并在电路开启的同时点亮一个adafruit neopixel。

我让这两件事分开工作。现在我合并了代码,但它不能正常工作。它的工作原理就像直流电机执行一个正向和反向循环并停止。然后新像素环亮起。在新像素代码完成一段时间后,直流电机执行相同的一个循环并继续此循环。

我需要帮助以使此代码同时启动直流电机工作和新像素照明。

代码如下:

#include <Adafruit_NeoPixel.h>

#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);


//DC motor
const int pwm = 3;  //initializing pin 2 as pwm
const int in_1 = 8 ;
const int in_2 = 7 ;

//For providing logic to L298 IC to choose the direction of the DC motor

void setup()

pinMode(pwm,OUTPUT) ;   //we have to set PWM pin as output
pinMode(in_1,OUTPUT) ;  //Logic pins are also set as output
pinMode(in_2,OUTPUT) ;

//Neopixel Ring
// This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket
#if defined (__AVR_ATtiny85__)
  if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif
  // End of trinket special code

strip.begin();
strip.show(); // Initialize all pixels to 'off'




void loop()

//For Clock wise motion , in_1 = High , in_2 = Low

digitalWrite(in_1,HIGH) ;
digitalWrite(in_2,LOW) ;
analogWrite(pwm,255) ;

/*setting pwm of the motor to 255
we can change the speed of rotaion
by chaning pwm input but we are only
using arduino so we are using higest
value to driver the motor  */

//Clockwise for 3 secs
delay(1000) ;    

//For brake
digitalWrite(in_1,HIGH) ;
digitalWrite(in_2,HIGH) ;
delay(50) ;

//For Anti Clock-wise motion - IN_1 = LOW , IN_2 = HIGH
digitalWrite(in_1,LOW) ;
digitalWrite(in_2,HIGH) ;
delay(1000) ;

//For brake
digitalWrite(in_1,HIGH) ;
digitalWrite(in_2,HIGH) ;
delay(50) ;

//Neopixel Ring

// Some example procedures showing how to display to the pixels:
  colorWipe(strip.Color(255, 0, 0), 50); // Red
  colorWipe(strip.Color(0, 255, 0), 50); // Green
  colorWipe(strip.Color(0, 0, 255), 50); // Blue
//colorWipe(strip.Color(0, 0, 0, 255), 50); // White RGBW
  // Send a theater pixel chase in...
  theaterChase(strip.Color(127, 127, 127), 50); // White
  theaterChase(strip.Color(127, 0, 0), 50); // Red
  theaterChase(strip.Color(0, 0, 127), 50); // Blue

  rainbow(20);
  rainbowCycle(20);
  theaterChaseRainbow(50);


// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) 
  for(uint16_t i=0; i<strip.numPixels(); i++) 
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  


void rainbow(uint8_t wait) 
  uint16_t i, j;

  for(j=0; j<256; j++) 
    for(i=0; i<strip.numPixels(); i++) 
      strip.setPixelColor(i, Wheel((i+j) & 255));
    
    strip.show();
    delay(wait);
  


// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) 
  uint16_t i, j;

  for(j=0; j<256*5; j++)  // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) 
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    
    strip.show();
    delay(wait);
  


//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) 
  for (int j=0; j<10; j++)   //do 10 cycles of chasing
    for (int q=0; q < 3; q++) 
      for (uint16_t i=0; i < strip.numPixels(); i=i+3) 
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      
      strip.show();

      delay(wait);

      for (uint16_t i=0; i < strip.numPixels(); i=i+3) 
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      
    
  


//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) 
  for (int j=0; j < 256; j++)      // cycle all 256 colors in the wheel
    for (int q=0; q < 3; q++) 
      for (uint16_t i=0; i < strip.numPixels(); i=i+3) 
        strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
      
      strip.show();

      delay(wait);

      for (uint16_t i=0; i < strip.numPixels(); i=i+3) 
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      
    
  


// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) 
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) 
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  
  if(WheelPos < 170) 
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);



【问题讨论】:

【参考方案1】:

基本上每次您调用延迟时,arduino 都无法执行任何其他操作。因此,您需要将控制权切换到您想做的任何其他事情上。

有几种方法:

计时器 - 使用计时器来更新您的两个任务之一的状态。这样做的好处是你的任务不依赖另一个任务来产生,但不会超过几个任务。

软件状态机 - 为每个任务创建一个状态机,并在循环中依次递增每个状态机。您需要创建一个结构来跟踪任务的状态,每次调用延迟时,您都会更新结构并返回。通常你会为每个任务创建一个类,就像在this Adafruit tutorial 中所做的那样。这可能需要大量工作,因此有一些库可以为您完成。

协程 - 这些使用库来为您构建状态机。例如http://forum.arduino.cc/index.php?topic=256256.0

【讨论】:

非常感谢您的回答。我基本上正在阅读您放置的adafruit链接,仍然可以理解。由于我的代码中有两个并行任务,请您编辑我的代码,以便直流电机和新像素同时工作。它将帮助我更多地了解它在未来的工作中是如何工作的。

以上是关于哪位大神能帮我写一个arduino 控制两个直流电机正反转,加减速和拐弯的程序啊?arduino程序,非常感谢。的主要内容,如果未能解决你的问题,请参考以下文章

单片机中中断服务函数 有哪位大神能帮我解释一下下面这段程序啥意思,就算能让我清楚一点也成,谢谢了

《Arduino直流电机控制教程》

哪位好心人能帮我把这段DNA序列转变成蛋白质序列?

有哪位大虾能帮我解释一下系统中的常用系统文件功能啊?

win10系统磁盘占用率100%哪位打大神可以帮我解决一下度娘上的试了,不管用,哪位大神可远程解决

一个Arduino最多能同时控制多少个直流电机