超声波声呐是一种设备,它通过发出频率高于人类听觉上限(通常超过20千赫兹)的声波来测量与物体的距离。其工作原理是发出声波,然后测量声波撞击物体后反弹回来的时间。通过计算发送和接收声波之间的时间差,并利用空气中的声速,就可以确定与物体的距离。在我之前的一些视频中,你可以看到几种具有特殊功能的此类设备的不同构建方式。它们都是通过 Processing 应用程序编写的额外程序将结果显示在电脑显示器上。
这次,我将向你介绍一种简单的方法来制作一个独立的声呐设备,该设备的结果直接在一个 TFT 彩色显示屏上以雷达图像的形式显示,因此它经常被误称为雷达而不是声呐。
https://www.bilibili.com/video/BV1v142127et/ (下方视频如无法显示请点此链接查看)
radar-code.c
[7763 Bytes at 2024-06-06, 8 次下载]
烙铁
无铅焊锡丝
伺服电机和超声波传感器被安装在一个我从先前项目中保留的盒子里,并通过扁平电缆连接到主箱体上。
这个想法是我在网络上偶然看到的一张图片时产生的,随后,经过一些研究,我在 Github 上找到了相关的项目。原项目是在一个 1.8 英寸的显示屏上制作的,对于这个目的来说,那确实是一个非常小的展示空间。因此,我重新编写了代码,使其适用于一个更大的 3.2 英寸 TFT 显示屏,这样图像显示会更加清晰。
现在,让我们深入探究这款设备在真实应用场景下的卓越表现:
首先,为了确保测量精度的准确无误,我精心地将超声波传感器与伺服电机分离,对图形显示与物体实际距离之间的对应关系进行了细致校准。你会发现,屏幕上显示的距离与实际测量的距离达到了惊人的吻合。
随后,我们将传感器稳稳地安装在伺服电机上,并放置了一个待检测的障碍物。开机后,伺服电机首先进行了流畅的测试,紧接着,显示屏上便呈现出一个类似雷达的扫描界面,并开始了精准的扫描工作。
障碍物在屏幕上以醒目的红点标识。屏幕的左下角清晰地展示了当前的扫描区域,而右侧则实时更新着传感器与障碍物之间的距离,单位精确到厘米。为了更加直观地呈现距离信息,我们特别设计了三条绿色的弧线,它们随着距离的变化而动态调整,使得用户能够一目了然地掌握实际距离。而当最近的障碍物距离超过 1 米时,最后一个弧线上会出现黄色的警示点,提醒用户已超出扫描范围。扫描过程从 180度开始,逐渐缩小至 0 度,随后再从0 度扩展到 180 度,实现了全方位的覆盖。
为了确保设备的稳定运行,我们推荐使用外部电源供电,但为了方便用户,也提供了通过 Arduino 的 USB 接口供电的选项。此外,用户还可以根据个人喜好,在代码中轻松调整所有的显示颜色,以满足不同的视觉需求。
最后,我要对这款设备做一个简要的总结。与大多数同类产品相比,它无需依赖电脑显示器来展示扫描结果,省去了额外的应用程序和代码的繁琐。它简单易制,视觉效果出色,且完全独立运行,无论是对于初学者还是资深的 DIY 爱好者来说,都是一个理想的选择。但为了更好的用户体验,建议将所有部件集成到一个紧凑的外壳中,并配备一个倾斜的前置显示屏,以模拟真实的雷达系统,为用户带来更加逼真的体验。
#include <Servo.h>
#include <SPI.h>
#include "Ucglib.h"
#define trigPin 6
#define echoPin 5
#define ServoPin 3
int Ymax = 240;
int Xmax = 320;
int Xcent = Xmax / 2;
int base = 210;
int scanline = 185;
Servo baseServo;
//Ucglib_ILI9341_18x240x320_SWSPI ucg(/*sclk=*/ 13, /*data=*/ 11, /*cd=*/ 9, /*cs=*/ 10, /*reset=*/ 8);
Ucglib_ILI9341_18x240x320_HWSPI ucg(/*cd=*/ 9, /*cs=*/ 10, /*reset=*/ 8);
void setup(void)
{
ucg.begin(UCG_FONT_MODE_SOLID);
ucg.setRotate90();
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
Serial.begin(115200);
baseServo.attach(ServoPin);
ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT);
ucg.setColor(0, 0, 100, 0);
ucg.setColor(1, 0, 100, 0);
ucg.setColor(2, 20, 20,20);
ucg.setColor(3, 20, 20, 20);
ucg.drawGradientBox(0, 0, 320, 240);
ucg.setPrintDir(0);
ucg.setColor(0, 5, 0);
ucg.setPrintPos(70,120);
ucg.setFont(ucg_font_logisoso32_tf);
ucg.print("Mini Radar");
ucg.setColor(0, 255, 0);
ucg.setPrintPos(70,120);
ucg.print("Mini Radar");
ucg.setFont(ucg_font_courB14_tf);
ucg.setColor(20, 255, 20);
ucg.setPrintPos(90,200);
ucg.print("Testing...");
baseServo.write(90);
for(int x=0;x<180;x+=5)
{ baseServo.write(x);
delay(50);
}
ucg.print("OK!");
delay(500);
ucg.setColor(0,0, 0, 0);
ucg.setColor(1,0, 0, 0);
ucg.setColor(2,0, 0, 0);
ucg.setColor(3,0, 0, 0);
ucg.drawGradientBox(0, 0, 320, 240);
delay(10);
//ucg.clearScreen();
cls();
ucg.setFontMode(UCG_FONT_MODE_SOLID);
ucg.setFont(ucg_font_helvR08_hr); // or freedoomr10_tr
}
void cls()
{
ucg.setColor(0, 0, 0, 0);
for(int s=0;s<240;s++)
{
ucg.drawHLine(0,s,320);
delay(1);
}
//ucg.drawBox(0, 0, 160, 60);
}
int calculateDistance()
{
long duration;
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
return duration*0.034/2;
}
void fix_font()
{
ucg.setColor(0, 180, 0);
ucg.setPrintPos(144,44);
ucg.print("1.00");
ucg.setPrintPos(144,100);
ucg.print("0.60");
ucg.setPrintPos(144,165);
ucg.print("0.30");
}
void fix()
{
ucg.setColor(0, 180, 0);
ucg.drawDisc(Xcent, base+1, 3, UCG_DRAW_ALL);
ucg.drawCircle(Xcent, base+1, 210, UCG_DRAW_UPPER_LEFT);
ucg.drawCircle(Xcent, base+1, 210, UCG_DRAW_UPPER_RIGHT);
ucg.drawCircle(Xcent, base+1, 135, UCG_DRAW_UPPER_LEFT);
ucg.drawCircle(Xcent, base+1, 135, UCG_DRAW_UPPER_RIGHT);
ucg.drawCircle(Xcent, base+1, 70, UCG_DRAW_UPPER_LEFT);
ucg.drawCircle(Xcent, base+1, 70, UCG_DRAW_UPPER_RIGHT);
ucg.drawLine(0, base+1, Xmax,base+1);
ucg.setColor(0, 180, 0);
for(int i= 40;i < 300; i+=2)
{
if (i % 10 == 0)
ucg.drawLine(185*cos(radians(i))+Xcent,base - 185*sin(radians(i)) , 205*cos(radians(i))+Xcent,base - 205*sin(radians(i)));
else
ucg.drawLine(195*cos(radians(i))+Xcent,base - 195*sin(radians(i)) , 205*cos(radians(i))+Xcent,base - 205*sin(radians(i)));
}
ucg.setColor(0,200,0);
ucg.drawLine(0,0,0,36);
for(int i= 0;i < 5; i++)
{
ucg.setColor(0,random(200)+50,0);
ucg.drawBox(2,i*8,random(28)+3,6);
}
ucg.setColor(0,180,0);
ucg.drawFrame(292,0,28,28);
ucg.setColor(0,60,0);
ucg.drawHLine(296,0,20);
ucg.drawVLine(292,4,20);
ucg.drawHLine(296,52,20);
ucg.drawVLine(318,4,20);
ucg.setColor(0,220,0);
ucg.drawBox(296,4,8,8);
ucg.drawBox(296,16,8,8);
ucg.drawBox(308,16,8,8);
ucg.setColor(0,100,0);
ucg.drawBox(308,4,8,8);
ucg.setColor(0,90,0);
ucg.drawTetragon(124,220,116,230,196,230,204,220);
ucg.setColor(0,160,0);
ucg.drawTetragon(134,220,126,230,186,230,194,220);
ucg.setColor(0,210,0);
ucg.drawTetragon(144,220,136,230,176,230,184,220);
}
void loop(void)
{
int distance;
fix();
fix_font();
for (int x=180; x > 4; x-=2){
baseServo.write(x);
int f = x - 4;
ucg.setColor(0, 255, 0);
ucg.drawLine(Xcent, base, scanline*cos(radians(f))+Xcent,base - scanline*sin(radians(f)));
f+=2;
ucg.setColor(0, 128, 0);
ucg.drawLine(Xcent, base, scanline*cos(radians(f))+Xcent,base - scanline*sin(radians(f)));
f+=2;
ucg.setColor(0, 0, 0);
ucg.drawLine(Xcent, base, scanline*cos(radians(f))+Xcent,base - scanline*sin(radians(f)));
ucg.setColor(0,200, 0);
distance = calculateDistance();
if (distance < 100)
{
ucg.setColor(255,0,0);
ucg.drawDisc(2.2*distance*cos(radians(x))+ Xcent,-2.2*distance*sin(radians(x))+base, 1, UCG_DRAW_ALL);
}
else
{
ucg.setColor(255,255,0);
ucg.drawDisc(208*cos(radians(x))+Xcent,-208*sin(radians(x))+base, 1, UCG_DRAW_ALL);
}
Serial.print(x);
Serial.print(" , ");
Serial.println(distance);
if (x > 70 and x < 110) fix_font();
ucg.setColor(255,255, 0);
ucg.setPrintPos(20,230);
ucg.print("DEG: ");
ucg.setPrintPos(54,230);
ucg.print(x);
ucg.print(" ");
ucg.setPrintPos(240,230);
ucg.print(" ");
ucg.print(distance);
ucg.print(" cm ");
}
//ucg.clearScreen();
delay(50);
cls();
fix();
fix_font();
for (int x=1; x < 176; x+=2){
baseServo.write(x);
int f = x + 4;
ucg.setColor(0, 255, 0);
ucg.drawLine(Xcent, base, scanline*cos(radians(f))+Xcent,base - scanline*sin(radians(f)));
f-=2;
ucg.setColor(0, 128, 0);
ucg.drawLine(Xcent, base, scanline*cos(radians(f))+Xcent,base - scanline*sin(radians(f)));
f-=2;
ucg.setColor(0, 0, 0);
ucg.drawLine(Xcent, base, scanline*cos(radians(f))+Xcent,base - scanline*sin(radians(f)));
ucg.setColor(0, 200, 0);
distance = calculateDistance();
if (distance < 100)
{
ucg.setColor(255,0,0);
ucg.drawDisc(2.2*distance*cos(radians(x))+Xcent,-2.2*distance*sin(radians(x))+base, 1, UCG_DRAW_ALL);
}
else
{
ucg.setColor(255,255,0);
ucg.drawDisc(208*cos(radians(x))+Xcent,-208*sin(radians(x))+base, 1, UCG_DRAW_ALL);
}
Serial.print(x);
Serial.print(" , ");
Serial.println(distance);
if (x > 70 and x < 110) fix_font();
ucg.setColor(255,255, 0);
ucg.setPrintPos(20,230);
ucg.print("DEG: ");
ucg.setPrintPos(54,230);
ucg.print(x);
ucg.print(" ");
ucg.setPrintPos(240,230);
ucg.print(" ");
ucg.print(distance);
ucg.print(" cm ");
}
//ucg.clearScreen(); //
delay(50);
cls();
}