风筝
发表于: 2018-9-5 15:07:19 | 显示全部楼层

在需要速度、准确性和安全性的许多应用中,机械臂已被证明是有用的并且更高效。但对我来说,更重要的是这些东西在工作时看起来很酷。我一直希望有一个机械臂可以帮助我完成我的日常工作,就像Tony stark在他的实验室中使用的Dum-E和Dum-U一样。可以看到这两个机器人帮助他建造钢铁侠套装或使用摄像机拍摄他的作品。实际上Dum-E也曾经挽救过他的生命......除了虚构的世界,还有许多由Fanuc、Kuka、Denso、ABB、Yaskawa等制造的酷炫的现实世界机械臂。这些机械臂用于汽车、采矿厂、化学工业和许多其他地方的生产线。


因此,在本教程中,我们将使用Arduino和MG995伺服电机制作我们自己的机器人手臂。除了抓手之外,机器人总共有4个自由度(DOF),可以通过电位计进行控制。除此之外,我们还将其编程为具有录制和播放功能,以便我们可以记录动作并让机器人手臂重复多次,如我们所要求的那样。听起来很酷!!!所以让我们开始制作......


所需的材料

●     Arduino Nano开发板

●     MG-995伺服电机

●     电位器

●     螺母和螺丝


注意:机械臂的主体完全是由3D打印的。如果您有打印机,则可以使用给定的设计文件进行打印。否则,使用提供的3D模型并使用木材或丙烯酸加工零件。如果你没有任何东西,那么你可以使用纸板来构建简单的机械臂。


3D打印和组装机械臂

构建这个机械臂最耗时的部分是制作它的身体。最初我开始使用Solidworks设计车身身体,但后来意识到Thingiverse上有很多很棒的设计,而且没有必要重新发明车轮。所以我经历了设计,发现Ashing Robotic Arm V2.0将与我们的MG995伺服电机完美配合,完全符合我们的目的。


因此,请访问他的Thingiverse页面(上面给出的链接)并下载模型文件。共有14个部分需要打印,所有这些部分的STL文件都可以从Thingiverse页面下载。我使用Ultimaker的Cura 3.2.1软件切割STL文件和TEVO塔兰图拉3D打印机进行打印。

3D-printing-parts-of-Robotic-arm-using-Cura.png


幸运的是,没有任何部件具有悬挂结构,因此不需要支撑。设计非常简单,因此可以通过任何基本的3D打印机轻松处理。大约4.5小时的印刷后,所有零件都准备好组装。 Ashing巧妙地解释了装配说明,因此我不打算介绍它。

3D-printed-parts-of-Robotic-arm.jpg


一个小小的提示就是你需要对部件的边缘进行打磨/锉削以使电机适应。所有的电机都可以通过一点点机械力适合安装。如果它们看起来有点紧,请耐心并使用锉刀为电机创造空间。您需要20个3mm螺栓来组装机械臂。


一旦安装好电机,确保它可以旋转并到达所需位置,然后永久拧紧。组装后,您可以继续扩展前三个伺服电机的电线。我已经使用公对母线将它们延伸并将其带到电路板上。确保正确使用电线,以便在手臂工作时它们不会挡住。组装后,机械臂如下图所示。

Assembeled-all-3D-printed-parts-of-Robotic-arm.jpg


电路原理图

MG995伺服电机工作在5V电压,Arduino开发板内部有一个5V稳压器。所以创建电路非常容易。我们必须将5个伺服电机连接到Arduino的PWM引脚,将5个电位器连接到Arduino模拟引脚,以控制伺服电机。下面给出了相关的电路图。

Circuit-Diagram-for-Record-and-Play-3D-Printed-Robotic-Arm-using-Arduino.png


对于这个电路,我没有使用任何外部电源。 Arduino通过USB端口供电,电路板上的+ 5v引脚用于向电位器和伺服电机供电。在我们的机械臂中,在任何、时间内,只有一个伺服电机会运动,因此消耗的电流将小于150mA,这可以由Arduino开发板的板载电压调节器提供。


我们有5个伺服电机和5个电位器来分别控制它们。 这5个电位器连接到Arduino板的5个模拟引脚A0到A4。 伺服电机由PWM信号控制,因此我们必须将它们连接到Arduino的PWM引脚。 在Arduino Nano上,引脚D3、D5、D6、D9和D11仅支持PWM,因此我们使用前5个引脚用于伺服电机。 完成后电路板如下所示。 如果需要,我还添加了一个插孔,通过电池为设备供电。

5-potentiometers-to-control-5-Servo-Motors.jpg


编程Arduino机械臂

现在,有趣的部分是对Arduino开发板进行编程,以允许用户记录使用电位器进行的移动,然后在需要时播放。要做到这一点,我们必须为两种模式编程Arduino。一次是录制模式,另一种是播放模式。用户可以使用串口监视器在两种模式之间切换。接下来,我们将讲解程序的小片段,以便理解。


和平常一样,我们通过添加所需的头文件来开始该程序。这里Servo.h头文件用于控制伺服电机。我们有5个伺服电机,因此声明了5个对象,每个电机都有一个名称。我们还初始化了将在程序中使用的变量。我已将它们全部声明为全局,但如果您对优化程序感兴趣,可以更改其范围。我们还声明了一个名为saved_data的数组,其名称将保存机器人ARM的所有记录移动。

  1. #include <Servo.h> //Servo header file

  2. //Declare object for 5 Servo Motors
  3. Servo Servo_0;
  4. Servo Servo_1;
  5. Servo Servo_2;
  6. Servo Servo_3;
  7. Servo Gripper;

  8. //Global Variable Declaration
  9. int S0_pos, S1_pos, S2_pos, S3_pos, G_pos;
  10. int P_S0_pos, P_S1_pos, P_S2_pos, P_S3_pos, P_G_pos;
  11. int C_S0_pos, C_S1_pos, C_S2_pos, C_S3_pos, C_G_pos;
  12. int POT_0,POT_1,POT_2,POT_3,POT_4;

  13. int saved_data[700]; //Array for saving recorded data

  14. int array_index=0;
  15. char incoming = 0;

  16. int action_pos;
  17. int action_servo;
复制代码

void setup()函数中,我们以9600波特率开始串行通信。 我们还指定了伺服电机所连接的引脚。 在我们的例子中,我们使用了使用attach函数指定的引脚3、5、6、9和10。 由于setup函数在启动期间运行,我们可以使用它将机器人手臂设置在起始位置。 所以我已经硬编码了所有五个电机的位置值。 这些硬编码值可以在以后根据您的偏好进行更改。 在setup函数结束时,我们打印一行代码,要求用户按R或P执行相应的操作。

  1. void setup() {
  2. Serial.begin(9600); //Serial Monitor for Debugging

  3. //Decalre the pins to which the Servo Motors are connected to
  4. Servo_0.attach(3);
  5. Servo_1.attach(5);
  6. Servo_2.attach(6);
  7. Servo_3.attach(9);
  8. Gripper.attach(10);

  9. //Write the servo motors to intial position
  10. Servo_0.write(70);
  11. Servo_1.write(100);
  12. Servo_2.write(110);
  13. Servo_3.write(10);
  14. Gripper.write(10);

  15. Serial.println("Press 'R' to Record and 'P' to play"); //Instrust the user
  16. }
复制代码

我定义了一个名为Read_POT的函数,它读取所有5个电位计的模拟值并将其映射到伺服位置值。 我们知道Arduino有一个8位的ADC,它给出了0-1023的输出,但伺服电机的位置值范围仅为0-180。 此外,由于这些伺服电机不是非常精确,因此将它们驱动到极端的0或180是不安全的,因此我们将10-170设置为我们的极限值。 我们使用map函数将所有五个电机的0-1023转换为10-170,如下所示。

  1. void Read_POT() //Function to read the Analog value form POT and map it to Servo value
  2. {
  3.    POT_0 = analogRead(A0); POT_1 = analogRead(A1); POT_2 = analogRead(A2); POT_3 = analogRead(A3); POT_4 = analogRead(A4); //Read the Analog values form all five POT
  4.    S0_pos = map(POT_0,0,1024,10,170); //Map it for 1st Servo (Base motor)
  5.    S1_pos = map(POT_1,0,1024,10,170); //Map it for 2nd Servo (Hip motor)
  6.    S2_pos = map(POT_2,0,1024,10,170); //Map it for 3rd Servo (Shoulder motor)
  7.    S3_pos = map(POT_3,0,1024,10,170); //Map it for 4th Servo (Neck motor)
  8.    G_pos  = map(POT_4,0,1024,10,170);  //Map it for 5th Servo (Gripper motor)
  9. }
复制代码

跳转到指定楼层
风筝
发表于: 2018-9-5 15:30:49 | 显示全部楼层

录制模式代码

在录制模式下,用户必须使用电位计控制机器人。每个电位器对应一个单独的电机,因为电位器是变化的,我们应该保存电机的位置和saved_data数组内的电机号。让我们看看如何使用Record函数实现这一点。


使用这些伺服电机时,每个人都可能遇到的一个常见问题是电机在工作时可能会抖动。对于这个问题有很多解决方案,首先你要解决问题是电机的控制电路还是写入伺服电机的位置值。在我的情况下,我使用串口监视器,发现servo_pos的值不会保持不变,有时会随机向上/向下抖动。


所以我编写了Arduino来读取两次POT值并比较两个值。仅当两个值相同时,该值才会被视为有效,否则将丢弃该值。谢天谢地,这解决了我的抖动问题。还要确保电位器牢固地安装到Arduino的模拟引脚。变量P_x_pos用于保存旧值,然后使用上面讨论的Read_POT函数再次读取和映射x_pos值。

  1. Read_POT(); //Read the POT values  for 1st time
  2. //Save it in a varibale to compare it later
  3.    P_S0_pos = S0_pos;
  4.    P_S1_pos = S1_pos;
  5.    P_S2_pos = S2_pos;
  6.    P_S3_pos = S3_pos;
  7.    P_G_pos  = G_pos;
  8. Read_POT(); //Read the POT value for 2nd time
复制代码

现在,如果值有效,我们必须控制伺服电机的位置。控制后我们还要保存数组中的电机编号和电机位置。我们可以使用两个不同的数组一个用于电机编号而另一个用于它的位置,但是为了节省内存和复杂性,我通过在将值保存到数组之前向pos值添加微分器值来组合它们。

  1.    if (P_S0_pos == S0_pos) //If 1st and 2nd value are same
  2.    {
  3.     Servo_0.write(S0_pos); //Control the servo
  4.    
  5.     if (C_S0_pos != S0_pos) //If the POT has been turned
  6.     {
  7.       saved_data[array_index] = S0_pos + 0; //Save the new position to the array. Zero is added for zeroth motor (for understading purpose)
  8.       array_index++; //Increase the array index
  9.     }
  10.    
  11.     C_S0_pos = S0_pos; //Saved the previous value to check if the POT has been turned
  12.    }
复制代码

Sero_0的微分器值为0,Servo_1的微分器值为1000,类似于Servo_3,它是3000;对于Gripper,它是4000。微分器被添加到位置值并保存到数组的代码行如下所示。

  1. saved_data[array_index] = S0_pos + 0; //Save the new position to the array. Zero is added for zeroth motor (for understading purpose)
  2. saved_data[array_index] = S1_pos + 1000; //1000 is added for 1st servo motor as differentiater
  3. saved_data[array_index] = S2_pos + 2000; //2000 is added for 2nd servo motor as differentiater
  4. saved_data[array_index] = S3_pos + 3000; //3000 is added for 3rd servo motor as differentiater
  5. saved_data[array_index] = G_pos + 4000; //4000 is added for 4th servo motor as differentiater
复制代码

播放模式代码

用户在saved_data中记录了移动后,可以通过在串行监视器中输入“P”切换到播放模式。在播放模式中,我们可以访问数组中保存的每个元素,并分割该值以获取电机编号和电机位置并相应地控制它们的位置。


我们使用for循环来遍历数组中的每个元素,直到数组中保存的值。然后我们使用两个变量action_servo和action_pos来分别得到要控制的伺服电机的数量和位置。为了获得伺服电机的数量,我们必须将其除以1000并获得我们需要的最后三位数的位置,这可以通过取模数来获得。


例如,如果数组中保存的值为3125,则表示必须将第3个电机移动到125的位置。

  1. for (int Play_action=0; Play_action<array_index; Play_action++) //Navigate through every saved element in the array
  2.   {
  3.     action_servo = saved_data[Play_action] / 1000; //The fist charector of the array element is split for knowing the servo number
  4.     action_pos = saved_data[Play_action] % 1000; //The last three charectors of the array element is split to know the servo postion
复制代码

现在剩下的就是使用伺服编号并将其移动到获得的伺服位置值。我使用开关盒进入相应的伺服电机编号和写入功能,将伺服电机移动到该位置。switch case语句如下所示

  1. switch(action_servo){ //Check which servo motor should be controlled
  2.       case 0: //If zeroth motor
  3.         Servo_0.write(action_pos);
  4.       break;

  5.       case 1://If 1st motor
  6.         Servo_1.write(action_pos);
  7.       break;

  8.       case 2://If 2nd motor
  9.         Servo_2.write(action_pos);
  10.       break;

  11.       case 3://If 3rd motor
  12.         Servo_3.write(action_pos);
  13.       break;

  14.       case 4://If 4th motor
  15.         Gripper.write(action_pos);
  16.       break;
复制代码

在主loop函数中,我们只需要检查用户通过串行监视器输入的内容,并相应地执行播放模式的记录模式。变量incoming用于保存用户的值。如果输入'R',将激活录制模式,如果按下则为'P'如果条件语句将执行播放模式,如下所示。

  1. void loop() {

  2. if (Serial.available() > 1) //If something is recevied from serial monitor
  3. {
  4. incoming = Serial.read();
  5. if (incoming == 'R')
  6. Serial.println("Robotic Arm Recording Started......");
  7. if (incoming == 'P')
  8. Serial.println("Playing Recorded sequence");
  9. }

  10. if (incoming == 'R') //If user has selected Record mode
  11. Record();

  12. if (incoming == 'P') //If user has selected Play Mode
  13. Play();
  14. }
复制代码


录制和播放机械臂的工作过程

按照电路图所示进行连接,并上传下面给出的代码。通过计算机的USB端口为Arduino Nano供电并打开串行监视器,您将收到一条简介消息。

Send-R-to-record-the-motion-of-Robotic-Arm.png


现在在串行监视器中输入R并按Enter键。请注意,应在串行监视器的底部选择Newline。一旦进入,机器人将进入录制模式,您将进入以下屏幕。

Recording-Position-of-Servos-of-Robotic-Arm.png


此处显示的信息可用于调试。从69开始的数字是伺服电机0到电机5的当前位置。索引值是针对阵列大小的。请注意,我们使用的数组限制为700,因此我们在超出该限制之前完整记录了移动。录制结束后,我们可以在串口监视器中输入P并按回车键,我们将进入播放模式,串口监视器将显示以下内容。

Send-P-to-Play-the-motion-of-Robotic-Arm.png


在播放模式内,机器人将重复与录制模式中相同的动作。这些移动将一次又一次地执行,直到您通过串行监视器中断它。


如果您在使用它时遇到任何问题,可以在本帖下面进行回复。

回复

使用道具 举报

玉公子
发表于: 2019-7-8 22:39:38 | 显示全部楼层

楼主,你好!能说一下装配吗,我没找到ashing的
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 700 | 回复: 1479



手机版|

GMT+8, 2024-3-29 20:06 , Processed in 0.114773 second(s), 8 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表