如何使用 Arduino 构建自己的遥控车 - ArduCar
电子学和编程并没有那么可怕。
咱们玩得开心点吧!
步骤 1:底盘组装
步骤二:接线
步骤 3:编程
步骤 4:Arduino 代码讲解和蓝牙模块配置(可选)
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
电子学和编程并没有那么可怕。
我们大多数人都在编写大量的代码,却很少真正接触运行我们代码的电子设备。另一个常见的误解是,电子设备很难理解,至少需要电子工程师的资格才能入门。作为一名技术员、汽车爱好者和编程爱好者,Arduino 一直是我关注的焦点。我小时候就有一辆遥控车,长大后一直想再买一辆,所以现在我开始学习编程,入手了一套 Arduino 套件,正是实现儿时梦想的最佳时机。
在继续阅读下一部分之前,我想补充几点。首先,这篇文章是我之前在一些微控制器相关的技术网站上发表过的,所以你可以把它看作是一个重新整理的版本。本教程主要基于技术解释,不过在第二部分,我会讲解用 Arduino IDE 编写的代码。最后,虽然 ArduCar 是我用 Java 编写的应用程序,但我并没有在本教程中提供它的源代码或相关解释。
咱们玩得开心点吧!
本教程将教你如何从零开始制作一辆基于 Arduino 的遥控车。无需任何编程、Arduino 或电子方面的经验。虽然具备一些相关经验会有所帮助,但任何人都能轻松完成这个项目。你可能会问,为什么要用移动电源?如今,移动电源的价格越来越亲民,在某些情况下甚至比电池还便宜。我们很多人家里都有移动电源,可以重复使用,随时充电。本项目涵盖了制作遥控车的基本原理,采用极简的材料方案,并详细解释了代码。此外,本教程的说明也适用于其他项目,那么,让我们开始吧!
作为一名业余爱好者,我没有电烙铁之类的工具。所以我尝试利用一些旧电子产品,比如USB数据线或移动电源,这些东西你们大多数人家里可能都有。你可以按照我的步骤操作,但也可以随意更换一些零件,发挥你的创意。以下是所需材料清单:
-
Arduino UNO
-
汽车底盘,带车轮和电机,套件
-
公对公和母对公跳线
-
电工绝缘胶带
-
蓝牙模块(HC-06 或 HC-05)
-
直流电机控制器(L298N)
-
带 2 个 USB 输出端口的移动电源
-
压电蜂鸣器
-
安卓手机
-
安装了 Arduino IDE 的 PC
步骤 1:底盘组装
首先,我们需要组装汽车底盘。如果您购买的是套件,很可能套件里也附带了说明书,但以防万一,步骤如下:
-
准备底盘主体部分、4 个用于将电机安装到底盘框架上的小型塑料支架(每个支架 2 个)、螺丝、黄铜垫片、螺母、电机、废弃的 USB 电缆和 4 根电缆/跳线。
-
将一根电线连接到电机的每个引脚上,你可以焊接它们,但如果你没有电烙铁,只需尝试将电线“打结”连接到每个引脚上即可。
-
现在拿出你的旧/备用 USB 数据线,剪掉大约 20 厘米长的线。
-
剥去几厘米的线缆外皮,露出里面的线芯;里面应该有四五根线,但我们只需要两根:接地线(黑色)和正极线(红色)。分别剥去红色和黑色线缆2-4厘米的外皮。你可以就这么放着,或者为了更牢固,可以打个结,或者用更长更粗的线缆/跳线焊接连接,确保连接足够牢固。
- 取出电机,用螺丝和螺母将其固定到底盘框架上,并用塑料支架(每个底盘框架两个)固定。请注意,每个电机的一侧都有一个小“点”,该点应朝内,这样当两个电机安装到位时,这两个点才能彼此相对。
-
电机安装到位后,就可以安装第三个尼龙支撑轮了。观察框架末端,应该有四个并排的小孔,呈正方形排列。用螺丝将黄铜垫片固定到这些孔上,确保黄铜垫片与电机位于框架的同一侧。
-
用螺丝将尼龙支撑轮固定到黄铜垫片上。
-
将轮子安装到每个电机上。注意,轮毂内部有凹槽,务必将其安装到正确的位置。安装时可能会遇到很大的阻力,但您必须轻柔操作,同时施加一定的力。
-
小车组装基本完成,现在可以将Arduino模块和直流电机控制器安装到车架上了。我用了套件里剩下的3颗螺丝和螺母,并在需要的地方用绝缘胶带包裹了电线。
步骤二:接线
当我们把Arduino和直流电机控制器都安装到车上并组装好后,就可以开始接线了。准备好跳线,包括公对公和母对公的跳线。
- 将连接电机的电缆连接到直流电机控制器上。假设靠近地线的下部引脚为正极,靠近机架的引脚为负极(GND)。电路图应如下所示:
OUT1 - 左侧电机 (-) GND 电缆
OUT2 - 左侧电机(+)电缆
OUT3 - 右电机 (+) 电缆
OUT4 - 右电机 (-) 接地线
- 现在我们来把Arduino连接到直流电机控制器。为此,我们将使用引脚IN1、IN2、IN3和IN4。之前OUT1、2、3、4接口负责给电机供电,而IN1、2、3、4引脚则用于从Arduino向控制器发送指令。这次你可能需要用到公母跳线,如果没有,可以尝试改造公公跳线,或者直接将导线焊接到引脚上。
IN1 - 数字 5
IN2 - 数字 6
IN3 - 数字 10
IN4 - 数字 11
- 蓝牙模块是我们转向系统所需的最后一个关键部件。蓝牙模块有4个引脚,每个引脚的标识如下:VCC - 电源,GND - 接地(-),TXD - 数据传输,RXD - 数据接收。这次可能还需要用到母对公的跳线。
VCC - 电源 5V
GND - 电源地
TXD - 数字 0 RXD
RXD - 数字 1 TXD
如您所见,Arduino 和我们的蓝牙模块之间将交换数据,这就是为什么数据线以相反的方式连接的原因。
- 压电蜂鸣器有两个引脚,较长的引脚为阳极 (+),较短的引脚为阴极 (-)。由于压电蜂鸣器非常灵敏且体积小,建议在压电蜂鸣器和阳极之间串联一个 330 欧姆的电阻,但我没有使用电阻,因为电阻会使我的压电蜂鸣器非常安静。注意:使用母头-公头跳线可能再次有所帮助。
阳极(+)长脚 - 数字3
阴极(-)短脚 - 电源地
- 我们快完成了!现在我们需要给Arduino开发板和直流电机控制器供电。拿出之前准备好的USB连接线,将红黑两根线连接到直流电机控制器上。
红色电缆(+)- 12 伏
黑色电缆(-)- 接地
- 最后一步是连接两根USB线,一根连接移动电源和Arduino开发板,另一根连接直流电机控制器,也连接到移动电源。最后一步是将移动电源固定在框架上,我用的是电工绝缘胶带,但还有很多其他的固定方法。注意:有些移动电源可能带有开关或按钮,所以你可能需要打开电源开关才能给电路供电。
- 所有零件和线路都已安装到位,但 Arduino 中仍然没有代码,手机上也没有控制汽车的应用程序。
步骤 3:编程
现在我们的遥控车已经准备就绪,最后一步是将代码上传到 Arduino 开发板,并在安卓手机上下载应用程序。这一步需要您在电脑上安装 Arduino IDE 程序,您可以从 Arduino 官方网站下载。安装完成后,需要设置两个选项。打开 Arduino IDE 程序,您会在顶部菜单栏看到一些选项,选择“工具”,然后您应该会看到一个列表,找到名为“开发板”的选项,并从列表中选择您的 Arduino 开发板(通常是 Arduino UNO)。接下来,在“开发板”选项下方,点击“端口”选项。如果您的电脑上没有连接任何 USB 设备,该选项可能会显示为灰色/禁用状态。当您使用 USB 数据线连接 Arduino 开发板后,该选项应该会变为可用状态。您可能需要选择一个端口,例如,在我的电脑上是端口 5。虽然我的笔记本电脑有 3 个 USB 端口,但只有一个端口可以用作端口。您可以尝试使用电脑上不同的 USB 接口,直到成功为止。
在将代码上传到 Arduino 之前,您有两种选择:
-
只需下载附件文件,用 Arduino IDE 程序打开,然后上传即可。
-
打开 Arduino IDE 程序,点击“文件”->“新建”,复制此处的代码,然后点击“上传”图标。请记住,上传代码时,Arduino 开发板必须通过正确的 USB 接口连接到电脑,并且端口必须已正确设置。
注意:在将代码上传到 Arduino 时,应拔下 DIGITAL 0 RX 和 DIGITAL 1 TX 插座。如果这些插座连接到蓝牙模块,Arduino 可能无法接受来自 PC 的传入数据,并且程序可能会在“上传”状态冻结。
下面附有代码及解释。
- 将代码上传到 Arduino 板后,就可以将 DIGITAL 0 RX 和 DIGITAL 1 TX 引脚重新连接到蓝牙模块,并将 USB 电缆(Arduino - 移动电源)重新连接到移动电源。
4. 让你的遥控车正常工作的最后一步,是从 Google Play 商店下载安卓应用程序,然后就可以开始玩啦!你也可以下载其他应用程序,只要它们发送匹配的序列号即可,甚至可以自己创建手机应用程序。
感谢您的关注,祝您玩得开心!如有任何疑问或建议,请在下方评论区留言。
#define in1 5
#define in2 6
#define in3 10
#define in4 11
int state;
int piezo = 3;
void setup() {
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);
pinMode(piezo,OUTPUT);
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) {
state = Serial.read();
Stop();
switch (state) {
case 'F':
forward();
soundFX(3000.0,30+400*(1+sin(millis()/5000)));
break;
case 'G':
forwardleft();
soundFX(3000.0,60);
break;
case 'D':
forwardright();
soundFX(3000.0,60);
break;
case 'N':
backright();
soundFX(3000.0,30+100*(1+sin(millis()/2500)));
break;
case 'C':
backleft();
soundFX(3000.0,30+100*(1+sin(millis()/2500)));
soundFX(3000.0,30+100*(1+sin(millis()/2500)));
soundFX(3000.0,30+100*(1+sin(millis()/2500)));
soundFX(3000.0,30+100*(1+sin(millis()/2500)));
break;
case 'B':
back();
soundFX(3000.0,30+200*(1+sin(millis()/2500)));
soundFX(3000.0,30+200*(1+sin(millis()/2500)));
soundFX(3000.0,30+200*(1+sin(millis()/2500)));
soundFX(3000.0,30+200*(1+sin(millis()/2500)));
break;
case 'L':
left();
soundFX(3000.0,60);
soundFX(3000.0,60);
soundFX(3000.0,60);
soundFX(3000.0,60);
break;
case 'R':
right();
soundFX(3000.0,60);
soundFX(3000.0,60);
soundFX(3000.0,60);
soundFX(3000.0,60);
break;
case 'H':
soundFX(3000.0,30+200*(1+sin(millis()/2500)));
soundFX(3000.0,60);
soundFX(3000.0,30+200*(1+sin(millis()/2500)));
soundFX(3000.0,60);
}
}
}
void forward() {
analogWrite(in1, 255);
analogWrite(in3, 255);
}
void forwardleft() {
analogWrite(in1, 50);
analogWrite(in3, 255);
}
void forwardright() {
analogWrite(in1, 255);
analogWrite(in3, 50);
}
void back() {
analogWrite(in2, 255);
analogWrite(in4, 255);
}
void backright() {
analogWrite(in2, 50);
analogWrite(in4, 255);
}
void backleft() {
analogWrite(in2, 255);
analogWrite(in4, 50);
}
void left() {
analogWrite(in4, 255);
analogWrite(in1, 255);
}
void right() {
analogWrite(in3, 255);
analogWrite(in2, 255);
}
void Stop() {
analogWrite(in1, 0);
analogWrite(in2, 0);
analogWrite(in3, 0);
analogWrite(in4, 0);
}
void soundFX(float amplitude,float period){
int uDelay=2+amplitude+amplitude*sin(millis()/period);
for(int i=0;i<5;i++){
digitalWrite(piezo,HIGH);
delayMicroseconds(uDelay);
digitalWrite(piezo,LOW);
delayMicroseconds(uDelay);
}
}
步骤 4:Arduino 代码讲解和蓝牙模块配置(可选)
为了满足大家的好奇心,我决定添加一段 Arduino 代码的解释,希望能帮助大家更好地理解这辆遥控车的机械原理和逻辑。另外需要说明的是,这段代码并非完全由我编写,它与一些项目中已有的代码非常相似,我只是简化了一些部分,并添加了压电蜂鸣器发出声音的代码块。
Arduino IDE 程序使用了一种简化的 C 和 C++ 混合编程语言,如果您熟悉这两种语言,可能会觉得似曾相识;即使不熟悉也没关系。代码将被分成几个部分,以帮助您更好地理解。
每个 Arduino 程序都由两个基本部分组成:
void setup() { }- 在这里,我们为 Arduino 的每个引脚设置一个函数。Arduino 只需读取一次该函数,获取信息并将其存储起来,供程序的其余部分使用。
在我们的案例中,情况是这样的:
void setup() {pinMode(in1, OUTPUT);`pinMode` 参数用于设置指定引脚的模式。括号内有两个值:第一个值 `in1` 是引脚名称,第二个值 `OUTPUT` 表示 Arduino 将向目标设备发送数据。如果设置为 `INPUT`,则表示该引脚将接收来自传感器等设备的数据。
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);
pinMode(piezo, OUTPUT);
Serial.begin(9600);串口是用于发送和接收数据的端口。您还记得我们之前连接蓝牙模块的 DIGITAL 0 RX 和 DIGITAL 1 TX 引脚吗?这里要讲的是它们的设置。这意味着我们将打开一个用于数据交换的通道。方括号内的数字 (9600) 表示每秒最多可以发送 9600 个字符。这是最常用的波特率,因为它最稳定。波特率越高,传输速度越快,但也更容易受到噪声干扰。因此,只需将其设置为 9600 即可。注意:蓝牙模块通常默认波特率为 9600,但有时您可能需要事先进行配置——请查看蓝牙配置部分。
-
void loop() { }正如其名,循环是程序中所有花括号内代码的重复执行部分。这就是任何 Arduino 程序运行所需的全部内容。其余部分就看你的想象力了。在深入讲解循环和函数之前,还有一部分位于代码开头,紧接着……void setup() { } -
在前面的
void setup() { }章节中,我们将 Arduino 引脚命名为 in 和 piezo,但这些并非它们的真实名称,只是我们赋予它们的名称。程序在执行过程中始终会使用这些名称。因此,在每个 Arduino 程序的开头,我们可以初始化引脚和变量的名称。让我们来看一个例子:
#define in1 5当你想为 Arduino 板上的某个引脚定义名称时,可以使用#define`#define` 语句,然后在空格后输入名称。在本例中,引脚名称为 `in1`,因为它是我们要控制的直流电机控制器引脚的名称。下一个空格后跟引脚编号。在本例中,引脚编号为 5,因为 `in1` 引脚连接到 Arduino 板上的 5 号插座。`#define in2 6`
#define in3 10
#define in4 11
int state; // We can also initialize names of the pin as variables int (integer), and variables itself.
int piezo = 3;
- 现在我们回到循环部分。
void loop() {if (Serial.available() > 0) {循环中的第一个语句以 if 开头,在括号内我们可以看到一个条件,它表示Serial.available() > 0)——简单来说,就是如果串口(在本例中是蓝牙模块)可用,且大于 0(记住二进制代码 1 为真,0 为假),则执行以下 { }——花括号内的所有内容都将被执行。
state = Serial.read();还记得代码开头那个状态变量吗?现在我们给这个变量赋值(=),所以我们的状态变量现在等于Serial.read(),这意味着该变量会根据从蓝牙模块读取的数据而变化。
Stop();名称后面的两个括号 () 表示这是一个函数,需要在代码的某个地方加以解释。同样,这段代码中第一个要执行的函数是名为 Stop 的函数,它会切断车轮的动力,使我们的遥控车停止。
switch (state)在 Stop 函数之后,紧接着是另一个函数,这次是全局函数,几乎所有编程语言中都有这种函数,叫做 switch 函数——字面意思是它内部包含几个函数,我们可以在它们之间切换。这次可以看到,在括号 () 内我们有一个条件,这个条件是一个名为 state 的变量,它的值被赋给了从蓝牙模块接收到的所有数据。
case 'F':如您所见,开关内部的每个可能功能都标记为“case”,单引号内显示的是状态变量的可能值。在本例中,如果状态等于“F”(即通过移动应用程序向蓝牙模块发送的字符),则会执行某些功能。
forward();要执行的第一个函数
soundFX(3000.0, 30+400*(1+sin(millis()/5000)));第二个要执行的函数,这次括号内有一些条件。
break;break 表示停止执行当前用例,必须始终使用break;语句结束每个用例。
case 'G':
forwardleft();
soundFX(3000.0, 60);
break;
- 现在几乎所有内容都已解释清楚,但代码中存在一些函数,例如 forward()、soundFX() 等,这些函数在 void setup() { } 和 void loop() { } 部分都没有解释。如果代码中包含此类函数,则应在代码末尾进行解释。以下是一个示例。
void forward()同样,要调用函数,首先要写上 `void`,然后在空格后写上函数名,例如 `forward()`。在花括号内,我们可以看到函数的说明。`analogWrite(in1, 255);` `analogWrite` 表示发送信号,如果是接收信号,则应写成 `analogRead`。括号内有两个值:`in1` 是引脚名称,`255` 是电波频率值,取值范围为 0 到 255,0 表示 0%,255 表示 100%。也可以写成 `LOW - 0`、`HIGH - 255`。如您所见,这里可以更改每个电机的转速。
analogWrite(in3, 255);这样,我们就可以说,通过改变引脚 1、2、3、4 及其数值,我们可以控制电流进入电机的一侧、电压,从而控制电机的速度和方向。
void soundFX(float amplitude, float period)这是我在 Arduino 官方论坛上找到的关于压电蜂鸣器科幻音效的部分。你可以在上一篇文章中找到这段代码,更多解释请点击下方链接。
https://forum.arduino.cc/index.php?topic=118757.0
int uDelay=2+amplitude+amplitude*sin(millis()/period);
for(int i=0;i<5;i++){
digitalWrite(piezo, HIGH);
delayMicroseconds(uDelay);
digitalWrite(piezo, LOW);
delayMicroseconds(uDelay);
} }
- 就是这样。从现在开始,希望你也能为代码做出贡献,修改一些内容,添加一些新功能,或者用你自己的方式重写它。
蓝牙配置
最后,还有一件重要的事情需要说明。HC-05 和 HC-06 蓝牙模块通常都带有默认设置,例如波特率、名称、密码等。如果您想配置蓝牙模块,可以使用 Arduino IDE 程序。不过,您可能需要更改蓝牙模块连接的引脚,并修改 Arduino 代码以进行配置。此外,建议使用电阻来保护蓝牙模块,因为数据引脚的工作电压为 3.3V,而 Arduino 的默认输出电压为 5V。请记住以上所有事项,这里我就不赘述整个过程了,网上有很多教程,您可以自行搜索。如果您有任何建议或疑问,请在下方评论区留言。
再次感谢您的关注,也别忘了在下方分享您自己的项目!
文章来源:https://dev.to/pawel/how-to-build-your-own-rc-car-with-arduino-arducar-12ei










