整体思路
功能描述
1.对应经纬度为路线标记中的路口时,根据高德API的指示显示左转,右转或直行的指示灯提示
2.当有物体以速度较快且逐渐增加的运动趋势接近用户时,发出警示和蜂鸣,提醒用户避障
3.当用户不慎跌倒时,按下手杖按钮可以伸缩,助力用户起身
实物图片
步进电机部分
步进电机供电要24v,说是12v也行,但是我没推动,换24v就好了。
需要配套的驱动器(小黑盒子)一般来说商家会有适配的,直接一起拍下就行
COM接地
DR表示方向(正转反转)
PU接单片机PWM波
VCC接24v电源正极
GND接地
A和B接步进电机的四根线,接法要问商家,这个可能各不一样
(MF接啥实在忘记了,有的驱动器好像没有这个,反而多了一个使能ENA,ENB,具体还是问客服吧)
雷达测速+蜂鸣 警示
用的是北醒的TFmini Plus激光雷达,有详细教程北醒雷达模组 资料汇总_北醒tf-minis激光模块-CSDN博客
距离到12m。最开始用的是普通超声测距,但是量程范围太短,不满足要求,就换成(高价的)激光雷达了。
要计算速度逐渐变快,也就是说相同时间间隔内,距离减小的值在逐渐变大。
同时要把没有物体(超量程)和启动阶段(爆0)都处理掉,不然蜂鸣器一直响,很头疼。
经纬度计算
队友调用的高德API,给的是像语音播报一样的一串结构体,有很多信息。
可以通过app inventor洗掉无用的字符串,只留下经纬度和左右转信息。把这些路线信息提前存入单片机里,方便后续与实时经纬度进行比较。
然后接收手机定位传过来的实时经纬度信息,注意,蓝牙透传很难用,app inventor只能传有限个字符(好像是20?忘记了),一个完整的实时经纬度都传不过来,就需要分几次传输,然后在单片机这边接收后拼接。
我这里采用的是最原始的拼接方式,单片机延时等待,手机端在发的时候,在经度开头和结尾都加标识符,收到开头标识符开始拼接,结尾标识符结束拼接,经度纬度都接收完成后再进行比较,看是否为路口范围。如果是就发送对应的左右转指令,亮灯指示。
这样就是又慢又麻烦,手机端发送很快,但单片机位置刷新相对较慢,大概三秒一更新(估测)碰到手机端乱码抽风的也会断掉更新。而且时序很难梳理,基本上单片机这边一打中断就会乱套(所以最后我偷懒用的两个单片机,一个只负责接收经纬度和左右转,一个负责其他和中断有关的功能)
最坑的是,这个手机定位会飘,每次重启应用经纬度都会变,站在原地重启三次,三次经纬度不一样,很令人抓狂。精度误差也难以恭维,需要很长的路线才能大概完成导航功能,一公里以内的路线经常抽风。
如此想来还不如用GPS模块来的方便,一星差评,再也不用。
说明:写这个帖子距离做这个项目已经有了大半年,有些细节实在记不清,源码也七零八落的,只能简单记录一下思路和作品功能。(下次我再也不偷懒了,红豆泥斯米马赛)
源码(的一部分)
#include <afstandssensor.h> // AfstandsSensor(triggerPin, echoPin);
#include <MsTimer2.h>
#include <SoftwareSerial.h>
#include <Arduino.h>
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
#define CLK 2
// Pin10为RX,接HC05的TXD
// Pin11为TX,接HC05的RXD(已弃用)
SoftwareSerial BT(10, 11);
SoftwareSerial Serial1(A2,A3);
AfstandsSensor afstandssensor(13, 12); // Starter afstandssensoren på ben 13 og 12.
U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);
// 定义定时器2中断服务例程的标记
volatile boolean timerFlag = false;
char val;
int state=0;//state>10脱离状态
float road[][3]={
{121528607,31239822,0},
{121529067,31239961,2},
{121529653,31240082,2}
// 121.530113,31.239397
};
int forwardled, leftled,rightled=0;
String EW="";
String NS="";
// String TST="1201123456";
int prt = 0;
float ew=0.0;
float ns=0.0;
char flag;
int loud=0;
// #define u8g2_logo_97x51_width 40
// #define u8g2_logo_97x51_height 40
// static const unsigned char u8g2_logo_97x51_bits[] U8X8_PROGMEM =
// {
// 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x30,0x80,0x01,0x00,0x00,0xF8,0xC0,0x03,0x00,0x00,0xF8,
// 0xE1,0x03,0x00,0x00,0xF8,0xF3,0x03,0x00,0x00,0xF8,0xFF,0x03,0x00,0x00,0xF8,0xFF,
// 0x03,0x00,0x00,0xF8,0xFF,0x03,0x00,0x00,0xF8,0xFF,0x03,0x00,0x00,0xF0,0xFF,0x01,
// 0x00,0x00,0xF0,0xFF,0x01,0x00,0x00,0xF0,0xFF,0x01,0x00,0x00,0xF0,0xFF,0x01,0x00,
// 0x00,0xF0,0xFF,0x01,0x00,0x00,0xF0,0xFF,0x01,0x00,0x00,0xF0,0xFF,0x01,0x00,0x00,
// 0xF0,0xFF,0x01,0x00,0x00,0xF0,0xFF,0x01,0x00,0x00,0xFF,0xFF,0x1F,0x00,0x80,0xFF,
// 0xFF,0x3F,0x00,0xC0,0xFF,0xFF,0x7F,0x00,0xC0,0xFF,0xFF,0x7F,0x00,0x80,0xFF,0xFF,
// 0x3F,0x00,0x00,0xFF,0xFF,0x1F,0x00,0x00,0xFE,0xFF,0x0F,0x00,0x00,0xFE,0xFF,0x07,
// 0x00,0x00,0xFC,0xFF,0x07,0x00,0x00,0xF8,0xFF,0x03,0x00,0x00,0xF0,0xFF,0x01,0x00,
// 0x00,0xE0,0xFF,0x00,0x00,0x00,0xE0,0x7F,0x00,0x00,0x00,0xC0,0x3F,0x00,0x00,0x00,
// 0x80,0x1F,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"D:\LC matrix\desktop\图片1.bmp",0*/
// };
int dist;/* 雷达实测距离值 */
int strength;/* 雷达信号强度 */
int check;/* 校验数值存放 */
int i;
int uart[9];/* 存放雷达测量的数据 */
const int HEADER=0x59;/* 数据包帧头 */
void setup() {
Serial.begin(38400);
pinMode(2,OUTPUT);
pinMode(8,OUTPUT);
pinMode(3,OUTPUT);
pinMode(6,OUTPUT);//fore
pinMode(4,OUTPUT);//left
pinMode(5,OUTPUT);//right
pinMode(13,INPUT);
pinMode(A5,INPUT);
pinMode(A0,OUTPUT);//servo
Serial.println("BT is ready!");
attachInterrupt(1, move, FALLING);//pin 3
// HC-05默认,38400
BT.begin(9600);
// TCCR2A = 0;
// TCCR2B = 0x07;
// TIMSK2 |= (1 << TOIE2); // 启用定时器中断
// sei(); // 开启全局中断
MsTimer2::set(50, sr04back); //每隔500ms运行一次flash函数里面的内容
// 第一个参数是定时时间,单位ms,第二个参数为中断函数名,可以任意更改
MsTimer2::start();
digitalWrite(A0,LOW);
// u8g2.begin();
}
void loop() {
if(forwardled==1){
digitalWrite(6,HIGH);
forwardled=0;
delay(10);
}
if(leftled==1){
digitalWrite(5,HIGH);
leftled=0;
delay(10);
}
if(rightled==1){
digitalWrite(4,HIGH);
rightled=0;
delay(10);
}
if(loud==1){
tone(8,440);
delay(300);
noTone(8);
delay(100);
tone(8,440);
delay(300);
noTone(8);
loud=0;
Serial.print("LOUD");
}
// u8g2.firstPage();
// do {
// u8g2.setFont(u8g2_font_ncenB14_tr);
// // u8g2.drawXBMP(0,0, 40, 40, logo);
// u8g2.drawXBMP(0,0, u8g2_logo_97x51_width, u8g2_logo_97x51_height, u8g2_logo_97x51_bits);
// u8g2.setCursor(70,16);
// // u8g2.print(a);
// u8g2.print(EW);
// u8g2.drawStr(30,50,"forward");
// } while ( u8g2.nextPage() );
// delay(100);
while (BT.available()) {
val = BT.read();
// Serial.print(val);
// vall=(int)val-'0';
if(val==' '||val=='.'||val<'0'){
continue;
}
if(val=='E'){//E
flag=0;//EW
continue;
}
if(val=='N'){//N
flag=1;//NS
continue;
}
///有点麻烦
if(!flag&&val!=' '){
if(val=='W'){//
flag=1;//EW end
continue;
}
EW+=val;
// ew=ew*10+vall;
}
else if(flag&&val!=' '){
if(val=='S'){//
flag=0;//NS end
prt=1;
continue;
}
NS+=val;
// ns=ns*10+vall;
}
// for(int i=0;i<10;){
// if(vall>0){
// EW=vall*10^(2-i);
// i++;
// }
// //Serial.println(vall);
// }
//============================
// Serial.println(val);
// Serial.print("prt=");
// Serial.println(prt);
}
delay(10);
if(prt==1){
prt=0;
if(EW.length()<=10){
ew = EW.toFloat();
ns = NS.toFloat();
if(ew>=90000000&&ew<180000000&&ns>=10000000&&ns<=50000000){
// Serial.print("EW=");
// Serial.println(EW);
// Serial.print("NS=");r
// Serial.println(NS);
Serial.print("ew=");
Serial.print(ew);
Serial.print(" ");
Serial.print("ns=");
Serial.println(ns);
// Serial.println(NS.length());
prt=0;}
}
EW="";
NS="";
//
if (ew >= 121524200 && ew <= 121530300 && ns >= 31237400 && ns <= 31242500){
Serial.println("直行");
// digitalWrite(6,HIGH);
// delay(50);
// digitalWrite(6,LOW);
// delay(50);
forwardled=1;
}
// else if(ew >= 121529320 && ew <= 121529360 && ns >= 31240430 && ns <= 31240520){
// Serial.println("右转");
// // digitalWrite(4,HIGH);
// rightled=1;
// }
// else if(ew >= 121530000 && ew <= 121530100 && ns >= 31239200 && ns <= 31239600){
// Serial.println("右转");
// // digitalWrite(5,HIGH);
// rightled=1;
// }
else{
// Serial.println("STOP");
digitalWrite(6,LOW);
digitalWrite(4,LOW);
digitalWrite(5,LOW);
}
/
// ew=0;
// ns=0;
}
// Serial.println();
digitalWrite(6,LOW);
digitalWrite(5,LOW);
digitalWrite(4,LOW);
}
// 定时器2中断服务例程
// ISR(TIMER2_OVF_vect) {
// timerFlag = true; // 设置中断标记
// TCNT2 = 0; // 重置计数器以防溢出
// // sr04back();
// }
void sr04back(){
// if (Serial1.available())/* 查看串口是否有数据输入 */
// {
// if(Serial1.read()==HEADER)/* 判断数据包帧头0x59 */
// {
// uart[0]=HEADER;
// if(Serial1.read()==HEADER)/* 判断数据包帧头0x59 */
// {
// uart[1]=HEADER;
// for(i=2;i<9;i++)/* 存储数据到数组 */
// {
// uart[i]=Serial1.read();
// }
// check=uart[0]+uart[1]+uart[2]+uart[3]+uart[4]+uart[5]+uart[6]+uart[7];
// if(uart[8]==(check&0xff))/* 按照协议对收到的数据进行校验 */
// {
// dist=uart[2]+uart[3]*256;/* 计算距离值 */
// strength=uart[4]+uart[5]*256;/* 计算信号强度值 */
// Serial.print("dist = ");
// Serial.print(dist);/* 输出雷达测试距离值 */
// Serial.print('\t');
// Serial.print("strength = ");
// Serial.print(strength);//输出信号强度值 */
// Serial.print('\n');
// }
// }
// }
// }
// float sr1 =afstandssensor.afstandCM();
// // Serial.println(sr1);
// delay(200);
// float sr2 = afstandssensor.afstandCM();
// // Serial.println(sr2);
// float diff = sr1-sr2;
if(digitalRead(A5)){
// tone(8,440);
// delay(100);
// noTone(8);
loud=1;
Serial.println("hhhhhhhhhhhhhhhhh");
// digitalWrite(3,LOW);
// digitalWrite(4,LOW);
// digitalWrite(5,LOW);
// }else{
// delay(100);
}
}
void move(){
for(int h=0;h<11;h++){
for(int i=0;i<10000;i++){
digitalWrite(CLK,HIGH);
// digitalWrite(CLK2,LOW);
delayMicroseconds(30);//延迟1毫秒
digitalWrite(CLK,LOW);
// digitalWrite(CLK2,HIGH);
delayMicroseconds(30);
// Serial.println(i);
// if(i>40000){
// digitalWrite(CLK,LOW);
// Serial.print(">>>>>>>>>>>");
// }
}
}
digitalWrite(A0,!digitalRead(A0));
Serial.println("movvvvvvvvvvvve");
}