在本教程中,我们将学习如何制作一个Arduino机械臂,它可以使用自定构建的Android应用程序进行无线控制和编程。我将向您展示构建它的整个过程,从设计和3D打印机器人部件,连接电子组件和编程Arduino,到开发我们自己的Android应用程序来控制机械臂。
使用应用程序中的滑块,我们可以手动控制机械臂的每个伺服或轴的运动。同样使用“保存”按钮,我们可以记录每个位置或步骤,然后机械臂可以自动运行并重复这些步骤。使用相同的按钮,我们可以暂停自动操作以及重置或删除所有步骤,以便我们可以记录新的步骤。
Arduino Robot Arm 3D模型
首先,我使用Solidworks 3D建模软件设计了机械臂。手臂有5个自由度。
对于前3轴,腰部,肩部和肘部,我使用了MG996R伺服系统,而对于另外2轴,腕部滚动和腕部间距,以及夹具我使用了较小的SG90微型伺服系统。
您可以下载和下面的3D模型。
3D打印机械臂
使用我的新3D打印机,Creality CR-10,我3D打印了Arduino机械臂的所有部件。
为了完成组装,我们只需使用一些螺栓和支架连接上部和下部框架,然后使用提供的电缆将电子组件与控制箱连接。
在尝试之前,建议检查滚轮是否足够紧,如果没有,可以简单地使用偏心螺母将它们拧紧。就是这样,在调平3D打印床之后,您就可以将3D创作变为现实。
我在几个小时内准备好Arduino Robot Arm的所有部件。
组装机械臂
好的,我们准备组装机械臂。我从基座开始,我使用其包装中的螺丝连接了第一台伺服电机。然后在伺服的输出轴上我固定了一个圆角螺栓。
在它的顶部,我放置上部并用两个螺丝固定。
这里再次首先进入伺服,然后将圆形喇叭放到下一个部件上,然后使用输出轴上的螺栓将它们固定在一起。
我们在这里可以注意到,在肩轴上最好包括某种弹簧,或者在我的情况下,我使用橡皮筋为伺服提供一些帮助,因为这种伺服也承载了其余部分的整个重量。作为有效载荷。
以类似的方式,我继续组装机械臂的其余部分。至于夹具机构,我使用了大约4毫米的螺栓和螺母来组装它。
最后,我将夹具机构安装到最后一个伺服机构上,完成了Arduino机械臂。
Arduino机械臂电路图
下一阶段是连接电子产品。该项目的电路图实际上非常简单。我们只需要一个Arduino板和一个HC-05蓝牙模块与智能手机进行通信。六个伺服电机的控制引脚连接到Arduino板的六个数字引脚。
为了给伺服电机供电,我们需要5V,但这必须来自外部电源,因为Arduino无法处理所有电流都可以吸收的电流量。电源必须能够处理至少2A的电流。因此,一旦我们将所有内容连接在一起,我们就可以继续编写Arduino并制作Android应用程序。
Arduino机械臂代码
由于代码有点长,为了更好地理解,我将在每个部分的描述部分发布程序的源代码。在本文的最后,我将发布完整的源代码。
首先,我们需要包含SoftwareSerial库,用于蓝牙模块和伺服库的串行通信。这两个库都包含在Arduino IDE中,因此您无需在外部安装它们。然后我们需要定义六个伺服器,HC-05蓝牙模块和一些用于存储伺服器当前和先前位置的变量,以及用于存储自动模式的位置或步骤的阵列。
#include <SoftwareSerial.h>
#include <Servo.h>
Servo servo01;
Servo servo02;
Servo servo03;
Servo servo04;
Servo servo05;
Servo servo06;
SoftwareSerial Bluetooth(3, 4); // Arduino(RX, TX) - HC-05 Bluetooth (TX, RX)
int servo1Pos, servo2Pos, servo3Pos, servo4Pos, servo5Pos, servo6Pos; // current position
int servo1PPos, servo2PPos, servo3PPos, servo4PPos, servo5PPos, servo6PPos; // previous position
int servo01SP[50], servo02SP[50], servo03SP[50], servo04SP[50], servo05SP[50], servo06SP[50]; // for storing positions/steps
int speedDelay = 20;
int index = 0;
String dataIn = "";
在设置部分,我们需要初始化伺服器和蓝牙模块,并将机械臂移动到其初始位置。我们使用write()函数来做到这一点,它只是将伺服器移动到0到180度的任何位置。
void setup() {
servo01.attach(5);
servo02.attach(6);
servo03.attach(7);
servo04.attach(8);
servo05.attach(9);
servo06.attach(10);
Bluetooth.begin(38400); // Default baud rate of the Bluetooth module
Bluetooth.setTimeout(1);
delay(20);
// Robot arm initial position
servo1PPos = 90;
servo01.write(servo1PPos);
servo2PPos = 150;
servo02.write(servo2PPos);
servo3PPos = 35;
servo03.write(servo3PPos);
servo4PPos = 140;
servo04.write(servo4PPos);
servo5PPos = 85;
servo05.write(servo5PPos);
servo6PPos = 80;
servo06.write(servo6PPos);
}
接下来,在循环部分,使用Bluetooth.available()函数,我们不断检查智能手机是否有任何传入数据。如果为true,则使用readString()函数将数据读取为字符串并将其存储到dataIn变量中。根据到达的数据,我们将告诉机械臂该做什么。
// Check for incoming data
if (Bluetooth.available() > 0) {
dataIn = Bluetooth.readString(); // Read the data as string
Arduino机械臂控制Android应用程序
我们现在来看看Android应用程序,看看它实际发送给Arduino的数据类型。
我使用MIT App Inventor在线应用程序制作了应用程序,以及它的工作原理。在顶部,我们有两个按钮,用于将智能手机连接到HC-05蓝牙模块。然后在左侧我们有一个机械臂的图像,在右侧我们有六个用于控制伺服器的滑块和一个用于速度控制的滑块。
每个滑块都有不同的初始值,最小值和最大值,适合机械臂关节。在应用程序的底部,我们有三个按钮,SAVE,RUN和RESET,通过它我们可以编程机械臂自动运行。下面还有一个标签,显示我们保存的步骤数。然而,有关如何使用MIT App Inventor构建此类应用程序的更多详细信息,您可以查看我的其他详细教程。
好的,现在让我们看看应用程序背后的程序或块。首先,在左侧,我们有用于将智能手机连接到蓝牙模块的模块。
然后我们有用于伺服位置控制的滑块和用于编程机械臂的按钮块。因此,如果我们使用蓝牙功能.SendText更改滑块的位置,我们会向Arduino发送文本。此文本包含一个前缀,指示哪个滑块已更改,以及滑块的当前值。
这是上述MIT App Inventor项目的下载文件,以及准备安装在智能手机上的Android App:
因此,在Arduino中,使用startsWith()函数,我们检查每个传入数据的前缀,因此我们知道接下来要做什么。例如,如果前缀是“s1”,我们知道我们需要移动伺服编号1。使用substring()函数我们得到剩余的文本,或者是位置值,我们将其转换为整数并使用该值将伺服移动到该位置。
// If "Waist" slider has changed value - Move Servo 1 to position
if (dataIn.startsWith("s1")) {
String dataInS = dataIn.substring(2, dataIn.length()); // Extract only the number. E.g. from "s1120" to "120"
servo1Pos = dataInS.toInt(); // Convert the string into integer
在这里我们可以简单地调用write()函数并且伺服将转到该位置,但是以这种方式伺服将以其最大速度运行,这对于机械臂来说太快了。相反,我们需要控制伺服的速度,因此我使用了一些FOR循环,以便通过在每次迭代之间实现延迟时间来逐渐将伺服从前一个位置移动到当前位置。通过更改延迟时间,您可以更改伺服的速度。
// We use for loops so we can control the speed of the servo
// If previous position is bigger then current position
if (servo1PPos > servo1Pos) {
for ( int j = servo1PPos; j >= servo1Pos; j--) { // Run servo down
servo01.write(j);
delay(20); // defines the speed at which the servo rotates
}
}
// If previous position is smaller then current position
if (servo1PPos < servo1Pos) {
for ( int j = servo1PPos; j <= servo1Pos; j++) { // Run servo up
servo01.write(j);
delay(20);
}
}
servo1PPos = servo1Pos; // set current position as previous position
}
相同的方法用于驱动机器人臂的每个轴。
在它们下面是SAVE按钮。如果我们按下SAVE按钮,每个伺服电机的位置将存储在一个阵列中。随着每次按压,索引增加,因此阵列逐步填充。
// If button "SAVE" is pressed
if (dataIn.startsWith("SAVE")) {
servo01SP[index] = servo1PPos; // save position into the array
servo02SP[index] = servo2PPos;
servo03SP[index] = servo3PPos;
servo04SP[index] = servo4PPos;
servo05SP[index] = servo5PPos;
servo06SP[index] = servo6PPos;
index++; // Increase the array index
}
然后,如果我们按下RUN按钮,我们调用runservo()自定义函数,该函数运行存储的步骤。我们来看看这个功能。所以这里我们一遍又一遍地运行存储的步骤,直到我们按下RESET按钮。使用FOR循环,我们遍历存储在阵列中的所有位置,同时我们检查是否有来自智能手机的任何传入数据。此数据可以是RUN / PAUSE按钮,用于暂停机器人,如果再次单击则继续自动运动。此外,如果我们改变速度滑块位置,我们将使用该值来改变下面FOR循环中每次迭代之间的延迟时间,这将控制伺服电机的速度。
// Automatic mode custom function - run the saved steps
void runservo() {
while (dataIn != "RESET") { // Run the steps over and over again until "RESET" button is pressed
for (int i = 0; i <= index - 2; i++) { // Run through all steps(index)
if (Bluetooth.available() > 0) { // Check for incomding data
dataIn = Bluetooth.readString();
if ( dataIn == "PAUSE") { // If button "PAUSE" is pressed
while (dataIn != "RUN") { // Wait until "RUN" is pressed again
if (Bluetooth.available() > 0) {
dataIn = Bluetooth.readString();
if ( dataIn == "RESET") {
break;
}
}
}
}
// If SPEED slider is changed
if (dataIn.startsWith("ss")) {
String dataInS = dataIn.substring(2, dataIn.length());
speedDelay = dataInS.toInt(); // Change servo speed (delay time)
}
}
// Servo 1
if (servo01SP[i] == servo01SP[i + 1]) {
}
if (servo01SP[i] > servo01SP[i + 1]) {
for ( int j = servo01SP[i]; j >= servo01SP[i + 1]; j--) {
servo01.write(j);
delay(speedDelay);
}
}
if (servo01SP[i] < servo01SP[i + 1]) {
for ( int j = servo01SP[i]; j <= servo01SP[i + 1]; j++) {
servo01.write(j);
delay(speedDelay);
}
}
以前面用这些IF语句和FOR循环解释的方式,我们将伺服器移动到下一个位置。最后,如果我们按下RESET按钮,我们将清除阵列中的所有数据为零,并将索引重置为零,这样我们就可以用新的动作重新编程机械臂。
// If button "RESET" is pressed
if ( dataIn == "RESET") {
memset(servo01SP, 0, sizeof(servo01SP)); // Clear the array data to 0
memset(servo02SP, 0, sizeof(servo02SP));
memset(servo03SP, 0, sizeof(servo03SP));
memset(servo04SP, 0, sizeof(servo04SP));
memset(servo05SP, 0, sizeof(servo05SP));
memset(servo06SP, 0, sizeof(servo06SP));
index = 0; // Index to 0
}
就是这样,现在我们可以享受机械臂带来的乐趣。