查看: 3507|回复: 9

【chocho精选】报告!前方发现mega2560超声波雷达

[复制链接]
本帖最后由 Chocho2017 于 2018-4-27 16:03 编辑

9.jpg


1.jpg


小时候看美国电影,那里面经常出现一个黑黑的屏幕上一根绿色的线来回扫描的机器,后来才知道那叫雷达。在那个年代,雷达简直就是我跟小伙伴们心中唯一的“黑科技”。看见网上很多大神都制作了属于自己的超声波雷达,看得我心痒难耐。今天,我不能再压抑天性了——我也要做一台属于自己的超声波雷达,圆童年的梦,哈哈。
3.jpg

实现原理
Arduino mega2560作为主控板,控制舵机转动,同时通过超声波采集距离数据,mega2560把这些信息处理后,显示在3.5寸 TFT屏幕上。

所需材料
TowerPro SG90舵机 x1  购买地址
URM07-UART低功耗超声波测距模块x1  购买地址
Bluno Mega2560控制器x1  购买地址
3.5 TFT Mega 触摸显示屏x1  购买地址

制作
在制作之前,请先下载代码到Bluno Mega2560开发板上,点击下载程序源码,源码如下:
[AppleScript] 纯文本查看 复制代码
#include<Servo.h>
#include "MultiLCD.h"
#include <SPI.h>
#include <Arduino.h>
#include <FlexiTimer2.h>
#define header_H    0x55 //帧头
#define header_L    0xAA //帧头
#define device_Addr 0x11 //模块地址
#define data_Length 0x00 //数据长度
#define get_Dis_CMD 0x02 //距离测量命令
#define checksum    (header_H+header_L+device_Addr+data_Length+get_Dis_CMD) //校验和
unsigned char Rx_DATA[8];
unsigned char CMD[6]={header_H,header_L,device_Addr,data_Length,get_Dis_CMD,checksum};

bool clockwise1=false,clockwise2=false,sendFlag=true,angleFlag=true,Serial1Flag=false,dataFlag=false,drawFlag=false,clearFlag=false;
int degree_L=30,degree_S=1,angle=1;
int x[181],y[181],Dis[181],num=0,Plflag=0;
int x0=239,y0=0,r=239,r1=5;
int flag=0;
Servo myServo;
LCD_R61581 lcd;

void flash()
{
    if(Serial1.available())
    {
       Serial1Flag=true;
      }
     else
     {
         Serial1Flag=false;
      }
     /* if(flag>0)
      {
          myServo.write(degree_S);
          Sjudge();
        }*/
      // moveFan(degree_L,1);
      // Tjudge();
  }

void setup() {
  // put your setup code here, to run once:
     memset(Dis,0,sizeof(Dis));
     Serial.begin(19200);
     Serial1.begin(19200);
     lcd.begin();
     myServo.attach(9);
     //计算圆心为(239,0),半径为239的半圆每度对应圆周上的坐标
      for(int i=0;i<181;i++)
    {
         double d=(3.14/180)*i;
         x[i]=int(x0-r*cos(d));
         y[i]=int(r*sin(d));
      }
       for(int i=0;i<180;i++)
       {
         lcd.setFontSize(FONT_SIZE_MEDIUM);  //set font size
         lcd.setColor(RGB16_GREEN);
         lcd.drawLine(x[i],y[i],x[i+1],y[i+1]);
       }
      //drawMap();
      drawFan(31);
      FlexiTimer2::set(50,flash);
      FlexiTimer2::start();
}
void drawMap()
{
       lcd.setColor(RGB16_GREEN);
       lcd.drawCircle(x0,y0,50);
       lcd.drawCircle(x0,y0,100);
       lcd.drawCircle(x0,y0,150);
       lcd.drawCircle(x0,y0,200);
       for(int i=299;i<319;i++)
       {
          lcd.clearLine(i);
        }
       for(int i=0;i<=180;i+=30)
       {
           lcd.setColor(RGB16_GREEN);
          lcd.drawLine(x0,y0,x[i],y[i]);
        }
  }
  void clearMap()
{
       lcd.setColor(0);
       lcd.drawCircle(x0,y0,50);
       lcd.drawCircle(x0,y0,100);
       lcd.drawCircle(x0,y0,150);
       lcd.drawCircle(x0,y0,200);
       for(int i=0;i<=180;i+=30)
       {
           lcd.setColor(RGB16_GREEN);
          lcd.drawLine(x0,y0,x[i],y[i]);
        }
  }
 void clearFan(int i)
 {
      if(i<30||i>150)
       return;
     for(int j=i+30;j>=i-30;j--)
     {
          lcd.setColor(0);
          lcd.drawLine(x0,y0,x[j],y[j]);
      }
  }
void drawFan(int i)
{
     if(i<30||i>150)
       return;
     for(int j=i-30;j<=i+30;j++)
     {
          lcd.setColor(RGB16_GREEN);
          lcd.drawLine(x0,y0,x[j],y[j]);
      }
  }
  void moveFan(int d)
  {
       if((d<30)||(d>150))
         return;
       if(clockwise2)
       {
                 lcd.setColor(RGB16_GREEN);
                 lcd.drawLine(x0,y0,x[d-30],y[d-30]);
                 lcd.setColor(0);
                 lcd.drawLine(x0,y0,x[d+30],y[d+30]);             
        }
        else
        {
                 lcd.setColor(RGB16_GREEN);
                 lcd.drawLine(x0,y0,x[d+30],y[d+30]);
                 lcd.setColor(0);
                 lcd.drawLine(x0,y0,x[d-30],y[d-30]);
          }
        /*   lcd.setColor(RGB16_GREEN);
           lcd.drawCircle(x0,y0,50);
           lcd.drawCircle(x0,y0,100);
           lcd.drawCircle(x0,y0,150);
           lcd.drawCircle(x0,y0,200);*/
         
    }
 void drawPoint(int d)//取值范围d:[1,180]
  {
            if(Dis[d]==0)
                return;
            unsigned int dis=Dis[d];
            double dd=(3.14/180)*d;
            double d1=(3.14/180)*(d-1);
            int xd1=int(x0-dis*cos(dd));
            int yd1=int(dis*sin(dd));
            int xd2=int(x0-dis*cos(d1));
            int yd2=int(dis*sin(d1));
             
            int xxx=int((xd1+xd2)/2);
            int yyy=int((yd1+yd2)/2);
            lcd.setColor(RGB16_RED);
            lcd.fillCircle(xxx,yyy,r1);
    }
   void clearPoint(int d)//d:[1,180]
{
    if(Dis[d]!=0)
    {
            int dis=Dis[d];
            double dd=(3.14/180)*d;
            double d1=(3.14/180)*(d-1);
            int xd1=int(x0-dis*cos(dd));
            int yd1=int(dis*sin(d));
            int xd2=int(x0-dis*cos(d1));
            int yd2=int(dis*sin(d1));
             
            int xxx=int((xd1+xd2)/2);
            int yyy=int((yd1+yd2)/2);
            lcd.setColor(0);
            lcd.fillCircle(xxx,yyy,r1);
      }
  }
 void sendCmd()
 {
          for(int i=0;i<6;i++)
          {
             Serial1.write(CMD[i]);
           }
  }   
void angleParse()
{
     if(angle>180)
     {
         angle=180;
         angleFlag=false;
      }
      if(angle<1)
      {
          angle=1;
          sendFlag=false;
          angleFlag=true;
          dataFlag=true;
        }
  }
 void Anglechange(unsigned int dis)
 {
       if(angleFlag)
       {
           Dis[angle]=dis;
           angle+=2;
           angleParse();
        }
        else
        {
           Dis[angle]=dis;
           angle-=2;
           angleParse();
       }
  }
void dataGet()
{
    if(dataFlag==true)
    {
         return;
      }
     while(Serial1.available())
   {
         Rx_DATA[num++]=Serial1.read();
         if(num==1&&Rx_DATA[num-1]!=0x55)
         {
             num=0;
             Plflag++;
         }
         if(num==2&&Rx_DATA[num-1]!=0xAA)
         {
             num=0;
             Plflag++;
         }
         if(num==2&&Rx_DATA[num-1]==0xAA&&Rx_DATA[num-2]==0x55)
         {
             int v=((Plflag%8>0)?1:0);
             v+=Plflag/8;
             for(int j=0;j<v;j++)
             {
                 Anglechange(0);
             }
        
         }
              if(num==8)
              {
                  num=0;
                  unsigned char t=Rx_DATA[0]+Rx_DATA[1]+Rx_DATA[2]+Rx_DATA[3]+Rx_DATA[4]+Rx_DATA[5]+Rx_DATA[6];
                  if(t==Rx_DATA[7])
                  {
                         unsigned int dis=((Rx_DATA[5]<<8)|Rx_DATA[6]);
                         if(dis>220||dis<0)
                            dis=0;
                         Anglechange(dis);
                    }
                    else
                    {
                        Anglechange(0);
                      }
                }
     }
  }

  void Sjudge()
  {
      if(clockwise1)
      {
          degree_S-=2;
          if(degree_S<1)
          {
             degree_S=1;
             clockwise1=false;
            }
        }
       else
       {
           degree_S+=2;
           if(degree_S>180)
           {
              degree_S=180;
              clockwise1=true;
            }
        }
    }

void Tjudge()
{
     if(clockwise2)
      {
          degree_L--;
          if(degree_L<30)
          {
             degree_L=30;
             clockwise2=false;
            }
        }
       else
       {
           degree_L++;
           if(degree_L>150)
           {
              degree_L=150;
              clockwise2=true;
            }
        }
  }
void loop() {
  // put your main code here, to run repeatedly:
       switch(flag)
       {
          case 0:
                 sendCmd();
                 myServo.write(degree_S);
                 Sjudge();
                 moveFan(degree_L);
                 Tjudge();
                 break;
          case 1:
                if(degree_S!=1)
                {
                     myServo.write(degree_S);
                     Sjudge();
                  }
                 moveFan(degree_L);
                 Tjudge();
                 break;
          case 2:
                 clearFan(30);
                 drawMap();
                 for(int i=1;i<181;i++)
                 {
                    drawPoint(i);
                  }
                  delay(1000);
                  drawFlag=true;
                 break;
          case 3:
                  for(int i=1;i<181;i++)
                  {
                       Dis[i]=0;
                    }
                  lcd.clear(0,0,479,319);
                   for(int i=0;i<180;i++)
                   {
                        lcd.setColor(RGB16_GREEN);
                        lcd.drawLine(x[i],y[i],x[i+1],y[i+1]);
                      }
                  drawFan(30);
                  clearFlag=true;
                 /*moveFan(degree_L,1)
                 clearPoint(degree_L-30+1)
                 clearPoint(degree_L+30)
                  Tjudge();*/
                  
                 break;
          default:
                 break;
        
        }
       if(sendFlag==false)
       {
           flag=1;
        }
        if(degree_S==1&°ree_L==30&&clockwise2==false&&dataFlag==true)
        {
              flag=2;
         }
         if(drawFlag==true)
         {
             flag=3;
          }
          if(clearFlag)
          {
              sendFlag=true;
              drawFlag=false;
              dataFlag=false;
              clearFlag=false;
              flag=0;
            }
            if(Serial1Flag)
            {
                dataGet();
              }
}
将Mega2560控制板的VCC、GND、D9引脚用导线引出,并打上热熔胶,并将SG90舵机固定在Mega2560控制板的背面。
10.jpg

将超声波模块的引脚用杜邦线连接到3.5寸屏的UART1串口(这里要注意超声波的正负极哦~,不要连错了),连接好SG90舵机和Mega2560,SG90的橙、红、棕引线分别对应Mega2560的D9、VCC、GND引脚。
11.jpg

然后插上USB线,就可以测到数据啦,哈哈,已经可以从屏幕上看到障碍物了~
12.jpg 3.jpg

最后,为雷达制作一个外壳,起保护作用,那就用硬纸板加工吧。扫描的效果看着还是很炫酷哦,本人终于圆梦了啦,哈哈。
5.jpg 7.jpg 9.jpg



Forgotten  版主

发表于 2018-4-27 17:56:37

超炫酷的,用激光测距是不是能得到更高的精度和刷新率
回复 支持 反对

使用道具 举报

青夏  NPC

发表于 2018-4-28 16:18:16

Forgotten 发表于 2018-4-27 17:56
超炫酷的,用激光测距是不是能得到更高的精度和刷新率

我觉得是的,不过需要频率更高一些。
回复 支持 反对

使用道具 举报

Grey  中级技匠

发表于 2018-4-28 17:04:40

青夏 发表于 2018-4-28 16:18
我觉得是的,不过需要频率更高一些。

可以用这种低成本ToF方案  http://www.dfrobot.com.cn/goods-1643.html
回复 支持 反对

使用道具 举报

digi_cow  初级技匠

发表于 2018-4-29 19:07:28

满足儿时梦想!
回复 支持 反对

使用道具 举报

gray6666  中级技匠

发表于 2018-5-3 08:49:46

炫酷的科技。。。。。。。。。。。。。。
回复 支持 反对

使用道具 举报

Chocho2017  版主
 楼主|

发表于 2018-5-4 10:49:44

Forgotten 发表于 2018-4-27 17:56
超炫酷的,用激光测距是不是能得到更高的精度和刷新率

对的,但是激光的贵一些。
回复 支持 反对

使用道具 举报

安卓机器人  初级技神

发表于 2018-5-14 21:38:20

碉 碉 碉
回复 支持 反对

使用道具 举报

Chocho2017  版主
 楼主|

发表于 2018-5-15 11:02:36

回复 支持 反对

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies |上传

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
wifi气象站

硬件清单

btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2016 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail