用 Arduino DIY 超声波雷达

超声波声呐是一种设备,它通过发出频率高于人类听觉上限(通常超过 20KHz)的声波来测量与物体的距离。其工作原理是发出声波,然后测量声波撞击物体后反弹回来的时间。通过计算发送和接收声波之间的时间差,并利用空气中的声速,就可以确定与物体的距离。在我之前的一些视频中,你可以看到几种具有特殊功能的此类设备的不同构建方式。它们都是通过 Processing 应用程序编写的额外程序将结果显示在电脑显示器上。

这次,我将向你介绍一种简单的方法来制作一个独立的声呐设备,该设备的结果直接在一个 TFT 彩色显示屏上以雷达图像的形式显示,因此它经常被误称为雷达而不是声呐。

组件清单

– Arduino Nano R3 × 1
– 分辨率为 240 x 320 像素、搭载 ILI9341 驱动芯片的TFT显示屏 × 1
– HC-SR04 型超声波传感器 × 1
– 小型9g伺服电机 × 1
– 2.2KM 电阻 × 5
– 3.3KM 电阻 × 5

所用工具:
– 烙铁
– 无铅焊锡丝

伺服电机和超声波传感器被安装在一个我从先前项目中保留的盒子里,并通过扁平电缆连接到主箱体上。

设计并组装

这个想法是我在网络上偶然看到的一张图片时产生的,随后,经过一些研究,我在 Github 上找到了相关的项目。原项目是在一个 1.8 英寸的显示屏上制作的,对于这个目的来说,那确实是一个非常小的展示空间。因此,我重新编写了代码,使其适用于一个更大的 3.2 英寸 TFT 显示屏,这样图像显示会更加清晰。

现在,让我们深入探究这款设备在真实应用场景下的卓越表现:

首先,为了确保测量精度的准确无误,我精心地将超声波传感器与伺服电机分离,对图形显示与物体实际距离之间的对应关系进行了细致校准。你会发现,屏幕上显示的距离与实际测量的距离达到了惊人的吻合。

随后,我们将传感器稳稳地安装在伺服电机上,并放置了一个待检测的障碍物。开机后,伺服电机首先进行了流畅的测试,紧接着,显示屏上便呈现出一个类似雷达的扫描界面,并开始了精准的扫描工作。

障碍物在屏幕上以醒目的红点标识。屏幕的左下角清晰地展示了当前的扫描区域,而右侧则实时更新着传感器与障碍物之间的距离,单位精确到厘米。为了更加直观地呈现距离信息,我们特别设计了三条绿色的弧线,它们随着距离的变化而动态调整,使得用户能够一目了然地掌握实际距离。而当最近的障碍物距离超过 1 米时,最后一个弧线上会出现黄色的警示点,提醒用户已超出扫描范围。扫描过程从 180度开始,逐渐缩小至 0 度,随后再从0 度扩展到 180 度,实现了全方位的覆盖。

为了确保设备的稳定运行,我们推荐使用外部电源供电,但为了方便用户,也提供了通过 Arduino 的 USB 接口供电的选项。此外,用户还可以根据个人喜好,在代码中轻松调整所有的显示颜色,以满足不同的视觉需求。

最后,我要对这款设备做一个简要的总结。与大多数同类产品相比,它无需依赖电脑显示器来展示扫描结果,省去了额外的应用程序和代码的繁琐。它简单易制,视觉效果出色,且完全独立运行,无论是对于初学者还是资深的 DIY 爱好者来说,都是一个理想的选择。但为了更好的用户体验,建议将所有部件集成到一个紧凑的外壳中,并配备一个倾斜的前置显示屏,以模拟真实的雷达系统,为用户带来更加逼真的体验。

接线图

代码

以下是完整源代码,也可以在项目文件库中下载代码文件:
https://make.quwj.com/project/521

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#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();
}

via



坐沙发

发表评论