画了11个小时,可以去B站看制做过程 搜索“立创EDA开源” 电路实现的功能可以搭配程序完成: PID五路自动循迹、寻光、寻火功能。 通过蓝牙模块可以实现蓝牙遥控功能(变速控制加上转向控制),板子的驱动使用的是RZ7899贴片驱动,4路寻光是需要和淘宝上的4路循迹模块搭配使用,其实也可以把小板打出来自己弄,因为有成品我就没自己做循迹头了。(改进建议就是自己做一个头,然后用排线连接,这样车显得更漂亮了!!) 连续肝了11小时的EDA制板过程(压缩成了三分钟 超急爽):https://www.bilibili.com/video/BV1E741177mW/ 小车最终实测视频片段(越野趣味遥控性能极佳):https://www.bilibili.com/video/BV15E411g78h/ 没有用EDA之前的智能小车视频,可以看到好多好多线密密麻麻的,还是打电路板好!!!https://www.bilibili.com/video/BV1E7411f7Cf/
https://www.jianshu.com/p/1a8262492619 蓝牙调试器使用说明
最近做了一个高速蓝牙遥控车,速度预计在40km/h以上,欢迎来立创开源社区关注我veryshunshine 里边有好多好玩的工程哦
在哔哩哔哩里有很多关于电子制作的视频,大多是通过立创完成的,欢迎关注我的ID:“漫步在宇宙的边缘”
要是小车点赞或者需要的人多的话我有时间出一期视频,把程序讲一遍,咱们一起学习进步!
小生大二邯郸学院(全校最长专业名!)机电学院机械设计制造及其自动化智能制造专业 在校生,爱好电子制作,为啥选了机械呢(因为机械动手肯定多,电子还得算,哈哈哈,结构机械也要计算好多好多东西。。。)欢迎一起交流鸭!@立创 冲鸭!!!
设计思路:
最先采用arduino进制控制,其功能丰富,代码简单移动,操控简单可行,配置双路电压输出模块,电带年纪驱动采用RZ7899进行控制,搭载车前灯以及超声波模块,拥有寻光寻火烟等拓展模块。
电路组成:
由电源模块、电机驱动模块、传感器模块、主控板模块、循迹分析模块等组成
实现功能:
最基本的功能有差速转向、变速控制、寻光、寻火焰、避障、跟随、等等并具有非常重要的循迹功能。
//////////////////////////////////////////////////////////////////////////////////////////////
//// Communication protocol start
//// ----the only thing you need to do is modifying the numbers of variables according to your demand
//
//****define what to send to cell phone*******************
#define NUM_TX_BOOL 0
#define NUM_TX_BYTE 2
#define NUM_TX_SHORT 0
#define NUM_TX_INT 0
#define NUM_TX_FLOAT 0
//*******************************************************
//****define what we want to get from cell phone********
#define NUM_RX_BOOL 1
#define NUM_RX_BYTE 2
#define NUM_RX_SHORT 0
#define NUM_RX_INT 0
#define NUM_RX_FLOAT 0
//*******************************************************
// size of Loop Buffer is editable depending on the data packet transmission rate and memory space
#define LOOP_BUFFER_SIZE 512
#define SIZE_RECV_PERTIME 64 // fixed
/////////////////////////////////////////////////////
//Do not change the code below+++++++++++++++++++++++
/////////////////////////////////////////////////////
// data structure to send to phone
struct {
bool bools [NUM_TX_BOOL];
int8_t bytes [NUM_TX_BYTE];
int16_t shorts [NUM_TX_SHORT];
int32_t integers [NUM_TX_INT];
float floats [NUM_TX_FLOAT];
}txPack;
// data structure to recv from phone
struct {
bool bools [NUM_RX_BOOL];
int8_t bytes [NUM_RX_BYTE];
int16_t shorts [NUM_RX_SHORT];
int32_t integers [NUM_RX_INT];
float floats [NUM_RX_FLOAT];
} rxPack;
byte loopBuffer[LOOP_BUFFER_SIZE];
byte rxPacketBuffer[((NUM_RX_BOOL+7)>>3)+NUM_RX_BYTE+(NUM_RX_SHORT<<1)+(NUM_RX_INT<<2)+(NUM_RX_FLOAT<<2)+3];
byte txPacketBuffer[((NUM_TX_BOOL+7)>>3)+NUM_TX_BYTE+(NUM_TX_SHORT<<1)+(NUM_TX_INT<<2)+(NUM_TX_FLOAT<<2)+3];
int16_t RXPACK_SIZE = sizeof(rxPacketBuffer);
int16_t TXPACK_SIZE = sizeof(txPacketBuffer);
int32_t INDEX_RANGE = LOOP_BUFFER_SIZE*2;
HardwareSerial *pSerial;
void initPack(HardwareSerial &serial, int32_t baudRate)
{
serial.begin(baudRate);
serial.setTimeout(0);
pSerial = &serial;
}
void getVariables(void)
{
unsigned char byte_pos=0,bit_pos=0;
#if (NUM_RX_BOOL>0)
for(int i=0;i<NUM_RX_BOOL;i++)
{
rxPack.bools[i] = (0x01<<bit_pos)&rxPacketBuffer[byte_pos];
bit_pos++;
if(bit_pos>=8)
{
byte_pos++;
bit_pos=0;
}
}
if(bit_pos!=0)
byte_pos++;
#endif
#if (NUM_RX_BYTE>0)
for(int i=0;i<NUM_RX_BYTE;i++)
{
rxPack.bytes[i] = rxPacketBuffer[byte_pos];
byte_pos++;
}
#endif
#if (NUM_RX_SHORT>0)
for(int i=0;i<NUM_RX_SHORT;i++)
{
rxPack.shorts[i] = (rxPacketBuffer[byte_pos+1]<<8)|rxPacketBuffer[byte_pos];
byte_pos+=2;
}
#endif
#if (NUM_RX_INT>0)
for(int i=0;i<NUM_RX_INT;i++)
{
rxPack.integers[i] = (rxPacketBuffer[byte_pos+3]<<24)| (rxPacketBuffer[byte_pos+2]<<16)| (rxPacketBuffer[byte_pos+1]<<8)|rxPacketBuffer[byte_pos];
byte_pos+=4;
}
#endif
#if (NUM_RX_FLOAT>0)
float f;
byte *p = (byte *) &f;
int pp=0;
for(int i=0;i<NUM_RX_FLOAT;i++)
{
p[0+pp] = rxPacketBuffer[byte_pos];
p[1+pp] = rxPacketBuffer[byte_pos+1];
p[2+pp] = rxPacketBuffer[byte_pos+2];
p[3+pp] = rxPacketBuffer[byte_pos+3];
pp+=4;
byte_pos+=4;
rxPack.floats[i] = f;
}
#endif
}
int32_t rxIndex=0;
int32_t rdIndex=0;
int32_t err=0;
int32_t sum;
bool recvPack(void)
{
int start_index;
int tail_index;
int cut_size;
int rx_length;
bool isOK = 0;
int rx_pack_index;
// read bytes to loop buffer
start_index = rxIndex%LOOP_BUFFER_SIZE;
if(start_index+SIZE_RECV_PERTIME<=LOOP_BUFFER_SIZE)
{
rx_length+=pSerial->readBytes(loopBuffer+start_index,SIZE_RECV_PERTIME);
rxIndex+=rx_length;
}else
{
cut_size = LOOP_BUFFER_SIZE-start_index;
rx_length=pSerial->readBytes(loopBuffer+start_index,cut_size);
rxIndex+=rx_length;
if(rx_length==cut_size)
{
cut_size = SIZE_RECV_PERTIME-cut_size;
rx_length=pSerial->readBytes(loopBuffer,cut_size);
rxIndex+=rx_length;
}
}
// extract a complete packet
while(rdIndex<(rxIndex-2*RXPACK_SIZE))
rdIndex+=RXPACK_SIZE;
while(rdIndex<=rxIndex-RXPACK_SIZE)
{
start_index = rdIndex%LOOP_BUFFER_SIZE;
isOK = 0;
if(loopBuffer[start_index]==0xA5)
{
tail_index = (start_index+RXPACK_SIZE-1)%LOOP_BUFFER_SIZE;
if(loopBuffer[tail_index]==0x5A) // Head and Tail match
{
rx_pack_index = 0;
// Check Summing
sum = 0;
// if data packet is divided into two segments
if(tail_index<start_index)
{
for(int i = start_index+1;i<LOOP_BUFFER_SIZE;i++)
{
rxPacketBuffer[rx_pack_index] = loopBuffer[i];
rx_pack_index++;
sum+=loopBuffer[i];
}
for(int i = 0;i<tail_index-1;i++)
{
rxPacketBuffer[rx_pack_index] = loopBuffer[i];
rx_pack_index++;
sum+=loopBuffer[i];
}
tail_index--;
if(tail_index<0)
tail_index+=LOOP_BUFFER_SIZE;
if(loopBuffer[tail_index]==(sum&0xff))
isOK = 1;
}else // data packet is contiguous
{
for(int i = start_index+1;i<tail_index-1;i++)
{
rxPacketBuffer[rx_pack_index] = loopBuffer[i];
rx_pack_index++;
sum+=loopBuffer[i];
}
if(loopBuffer[tail_index-1]==(sum&0xff))
isOK = 1;
}
if(isOK) // parse the data to rxPack
{
getVariables();
rdIndex+=RXPACK_SIZE;
}
}
}
if(!isOK)
{
rdIndex++;
err++;
}
}
// limit the range of read index and recv index
if(rxIndex>INDEX_RANGE&&rdIndex>INDEX_RANGE)
{
rxIndex-=INDEX_RANGE;
rdIndex-=INDEX_RANGE;
}
return isOK;
}
void sendPack(void)
{
short byte_pos=0,bit_pos=0;
int32_t sum=0;
txPacketBuffer[byte_pos++] = 0xA5;
#if (NUM_TX_BOOL>0)
for(int i=0;i<NUM_TX_BOOL;i++)
{
if(txPack.bools[i])
txPacketBuffer[byte_pos] |= 0x01<<bit_pos;
else
txPacketBuffer[byte_pos] &= ~(0x01<<bit_pos);
bit_pos++;
if(bit_pos>=8)
{
byte_pos++;
bit_pos=0;
}
}
if(bit_pos!=0)
byte_pos++;
#endif
#if (NUM_TX_BYTE>0)
for(int i=0;i<NUM_TX_BYTE;i++)
txPacketBuffer[byte_pos++] = txPack.bytes[i];
#endif
#if (NUM_TX_SHORT>0)
for(int i=0;i<NUM_TX_SHORT;i++)
{
txPacketBuffer[byte_pos++] = txPack.shorts[i]&0xff;
txPacketBuffer[byte_pos++] = (txPack.shorts[i]>>8)&0xff;
}
#endif
#if (NUM_TX_INT>0)
for(int i=0;i<NUM_TX_INT;i++)
{
txPacketBuffer[byte_pos++] = txPack.integers[i]&0xff;
txPacketBuffer[byte_pos++] = (txPack.integers[i]>>8)&0xff;
txPacketBuffer[byte_pos++] = (txPack.integers[i]>>16)&0xff;
txPacketBuffer[byte_pos++] = (txPack.integers[i]>>24)&0xff;
}
#endif
#if (NUM_TX_FLOAT>0)
float f;
byte *add;
for(int i=0;i<NUM_TX_FLOAT;i++)
{
f = txPack.floats[i];
add = (byte *)&f;
txPacketBuffer[byte_pos++] = add[0];
txPacketBuffer[byte_pos++] = add[1];
txPacketBuffer[byte_pos++] = add[2];
txPacketBuffer[byte_pos++] = add[3];
}
#endif
for(int i=1;i<TXPACK_SIZE-2;i++)
sum+=txPacketBuffer[i];
txPacketBuffer[byte_pos++] = sum&0xff;
txPacketBuffer[byte_pos] = 0x5a;
pSerial->write(txPacketBuffer,TXPACK_SIZE);
}
/////////////////////////////////////////////////////
//Do not change the code above-----------------------
/////////////////////////////////////////////////////
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@//
//// Communication protocol end//////////////////////
/////////////////////////////////////////////////////
#define leftA_PIN 6
#define leftB_PIN 5
#define righA_PIN 9
#define righB_PIN 10
void motor_pinint();
void motorcontrol();
void sdcl();
unsigned long SDA2;//定义duration变量为无符号长整数型变量
unsigned long SDA3;//定义duration变量为无符号长整数型变量
unsigned long A=0.0;//定义duration变量为无符号长整数型变量
unsigned long B=0.0;//定义duration变量为无符号长整数型变量
int i=0;
int Y=0;
int X=0;
int CD=0;
/*电机引脚初始化*/
void motor_pinint()
{
pinMode (leftA_PIN, OUTPUT); //设置引脚为输出引脚
pinMode (leftB_PIN, OUTPUT); //设置引脚为输出引脚
pinMode (righA_PIN, OUTPUT); //设置引脚为输出引脚
pinMode (righB_PIN, OUTPUT); //设置引脚为输出引脚
}
void motorcontrol()
{
if (Y>0)
{
if(X>0||X==0)
{
analogWrite(righA_PIN, Y-X);
analogWrite(righB_PIN, 0);
analogWrite(leftA_PIN, Y);
analogWrite(leftB_PIN, 0);
}
else
{
analogWrite(righA_PIN, Y);
analogWrite(righB_PIN, 0);
analogWrite(leftA_PIN, Y+X);
analogWrite(leftB_PIN, 0);
}
}
else if(Y<0)
{
if(X>0)
{
analogWrite(righA_PIN, 0);
analogWrite(righB_PIN, -Y-X);
analogWrite(leftA_PIN, 0);
analogWrite(leftB_PIN, -Y);
}
else
{
analogWrite(righA_PIN, 0);
analogWrite(righB_PIN, -Y);
analogWrite(leftA_PIN, 0);
analogWrite(leftB_PIN, -Y+X);
}
}
else
{
analogWrite(righA_PIN, 0);
analogWrite(righB_PIN, 0);
analogWrite(leftA_PIN, 0);
analogWrite(leftB_PIN, 0);
}
}
void setup()
{
motor_pinint();
Serial.begin(9600); //串口波特率9600(PC端使用)
initPack(Serial,9600);
}
void loop()
{
if(recvPack()) // if recved
{
Y=rxPack.bytes[0]2;
* X=rxPack.bytes[1]2;*
** CD=rxPack.bools[0];*
* digitalWrite(A4,CD);*
* }*
* motorcontrol();*
* sdcl();*
* sendPack();*
* /*
// delay(1000);
// Serial.print("Y:");
// Serial.print(rxPack.bytes[0]*2);
//Serial.print(" ");
// Serial.print("X:");
// Serial.println(rxPack.bytes[1]*2);
if (X > 0) {
analogWrite(leftA_PIN, X);
analogWrite(leftB_PIN, 0);
} else {
analogWrite(leftA_PIN, 0);
analogWrite(leftB_PIN, -X);
}/
//速度设定范围(-100,100)
/void motorsWritePct(int speedLpct, int Xpct) {**
** //speedLpct, speedRpct ranges from -100 to 100*
* motorsWrite(speedLpct * 2.55, speedRpct * 2.55);*
}/
}
void sdcl()
{
A=0.0;
B=0.0;
for(i=0;i<4;i++)//三次平均值
{
SDA3 = pulseIn(A3,0,100000); //读取引脚上的高电平脉冲
SDA2 = pulseIn(A2,0,100000); //读取引脚上的高电平脉冲
A=A+(357500.0/SDA3);
B=B+(357500.0/SDA2);
}
txPack.bytes[1] =(B/4);
txPack.bytes[0] =(A/4);
// Serial.print(B/3);
// Serial.println(A/3);
// delay(1);
}
!注意:请使用浏览器自带下载,迅雷等下载软件可能无法下载到有效资源。
欢迎加入EEWorld参考设计群,也许能碰到搞同一个设计的小伙伴,群聊设计经验和难点。 入群方式:微信搜索“helloeeworld”或者扫描二维码,备注:参考设计,即可被拉入群。 另外,如您在下载此设计遇到问题,也可以微信添加“helloeeworld”及时沟通。
EEWorld Datasheet 技术支持