智能导航防摔助老拐杖

整体思路

功能描述

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");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值