风筝
发表于: 2019-8-14 12:28:14 | 显示全部楼层

在本篇文章中,我们将学习如何构建一个能够向任何方向移动的Arduino麦克纳姆轮机器人。机器人的这种独特的移动性通过使用称为麦克纳姆轮(Mecanum Wheels)的特殊类型的轮子来实现。


概述

实际上,我设计并3D打印了这些轮子,因为它们可能有点贵。他们工作得很好,我必须说,驾驶这个机器人平台是如此有趣。我们可以使用NRF24L01无线电收发器模块无线控制机器人,也可以使用自制的RC发射器。

DIY-Mecanum-Wheels-Robot-Wireless-Control-with-RC-Transmitter.jpg

使用RC发射器作为DIY麦克纳姆轮机器人的无线控制器


我还可以通过蓝牙通信使用智能手机进行控制。我制作了一个自定义Android应用程序,通过它我们可以控制麦克纳姆轮机器人向任何方向移动。此外,使用应用程序中的滑块,我们可以控制移动的速度。

DIY-Arduino-All-direction-vehicle-robot-controlled-using-Android-App.jpg

使用Android App控制的DIY Arduino任意方向机器人


这个机器人平台的大脑是一个Arduino Mega开发板,可以单独控制每个车轮。每个车轮都安装在NEMA 17步进电机上,我在应用程序中添加了一个更酷的功能,通过它我们可以编程机器人自动移动。使用“保存”按钮,我们可以保存每个位置或步骤,然后机器人可以自动运行并重复这些步骤。使用相同的按钮,我们可以暂停自动操作以及重置或删除所有步骤,以便我们可以存储新的步骤。


麦克纳姆轮机器人的3D模型

首先,我使用3D建模软件设计了这个麦克纳姆轮机器人。这个机器人的基础平台是一个简单的盒子,我将用8mm刻度MDF板制作。

3D-Model-Mecanum-Wheels-Robot-Vehicle.jpg

3D模型麦克纳姆轮机器人


使用四个步进电机连接到该平台,麦克纳姆车轮连接到电机轴上。


麦克纳姆轮如何工作

麦克纳姆轮是一个车轮,其圆周上有滚轮。这些滚轮对角地定位或与轮子的旋转轴成45度角。这使得当向后移动时轮子沿对角线方向施加力。

Mecanum-Wheel-exerts-diagonal-force-resulting-in-specific-move.jpg

麦克纳姆轮施加对角线力,导致特定的移动


因此,通过以某些角度旋转车轮,我们利用这些对角线力,因此机器人可以向任何方向移动。

我们还应该注意到,我们需要两种类型的麦克纳姆轮,通常称为左手和右手麦克纳姆轮。它们之间的区别在于滚轮的方向,它们必须安装在机器人的特定位置。每个车轮上滚轮的旋转轴应指向机器人的中心。

Left-handed-and-Right-handed-Mecanum-Wheels.jpg

左手和右手麦克纳姆轮


以下是快速演示了如何根据车轮旋转方向移动机器人。


如果所有四个轮子向前移动,则机器人的最终移动将向前移动,反之亦然,如果所有轮子向后移动,则机器人将向后移动。为了向右移动,右轮需要在机器人内侧旋转,而左轮需要在机器人外侧旋转。由于对角定位的滚轮产生的力将使机器人向右移动。向左移动时会发生相同但相反的情况。通过这些车轮,我们还可以通过仅旋转两个车轮实现对角线方向的运动。


制作麦克纳姆轮机器人

现在让我告诉你我是如何构建这个机器人平台的。正如我所提到的,为了制作平台的基础,我使用8mm刻度MDF板。使用台锯,首先根据3D模型尺寸切割所有部件。

Cutting-the-MDF-board-for-the-robot-platform.jpg

接下来,使用3毫米钻头和25毫米Forstner钻头,我在侧板上做了开口,用于连接步进电机。一旦我准备好了,我继续组装它们。我用木胶和一些螺丝固定它们。这里最重要的是精确制造电机的开口,以便所有的车轮随后都能与表面接触。

Asembling-the-base-platform.jpg


当然,您也可以3D打印这个基础平台,而不是使用MDF。最后,我喷涂了底座,它的盖子是白色的。

Painting-the-robot-base-platform.jpg


接下来是Mecanum车轮。正如我之前所说的那样,购买这些轮子可能有点贵,所以这就是为什么我决定设计和3D打印自己的轮子。轮子由两部分组成,外侧和内侧,用一些M4螺栓和螺母固定在一起。它们各有10个滚轮,以及专门设计用于安装NEMA 17步进电机的联轴器。

Mecanum-Wheel-3D-Model-Exploaded-View.jpg

我使用Creality CR-10 3D打印机3D打印Mecanum车轮的所有零件。

3D-Printing-the-Mecanum-Wheels.jpg

3D-Printed-Mecanum-Wheels-Parts.jpg


因此,一旦准备好3D打印部件,我就继续制作滚轮的轴。为此,我使用了3毫米刻度钢丝。轴的长度需要约为40mm,因此使用旋转工具将线切割成该长度。

Making-the-shafts-for-the-mecanum-wheels-rollers-out-of-3mm-tich-steel-wire.jpg

用3mm tich钢丝制作mecanum轮子的轴


我开始使用四个M4螺栓和螺母固定两侧和轴连接器来组装麦克纳姆轮。螺栓的长度需要为45mm。

Aseembling-the-3D-Printed-Mecanum-Wheels.jpg

为了安装滚子,首先我们需要通过位于内侧圆周的孔轻轻插入轴。

Installing-the-Mecanum-Wheels-Rollers.jpg

安装Mecanum轮子滚轮


然后我们可以插入一个小型M3垫圈,插入滚轮并将轴一直推入车轮外侧的槽中。我使用了一个垫圈,因为我没有足够的空间在另一侧插入第二个垫圈。

Installing-the-roller.jpg

我为所有10个滚轮重复了这个过程。组装这些轮子实际上很简单,也很有趣。这里重要的是滚轮需要能够自由移动。

3D-Printed-Mecanum-Wheel-with-10-Rollers.jpg

最后,我在每个内孔中使用了几滴AC胶,以确保轴不会松动。

Securing-the-rollers-shafts-using-AC-glue.jpg


好吧,一旦车轮准备就绪,我们就可以继续组装整个机器人了。首先,我们需要将步进电机连接到基础平台。为了将它们固定到位,我使用了长度为12mm的M3螺栓。

Assembling-the-Mecanum-Wheels-Robot.jpg

接下来,我们需要将轮子连接到电机的轴上。我制造的联轴器有一个用于插入M3螺母的槽,M3螺栓可以穿过该螺母,因此我们可以将车轮固定在轴上。

3D-Printed-Shaft-Couple-for-NEMA-17-Stepper-Motor.jpg

用于NEMA 17步进电机的3D印刷轴对


接下来,为了将顶盖固定到底座上,我将螺纹杆连接在底座的两个角上。我在盖子上的相同位置上打孔,因此我能够轻松插入并将盖子固定到底座上。

Top-cover-for-the-robot-platform.jpg


在底座的背面,我制作了20mm的孔,用于稍后连接电源开关,以及用于连接LED的5mm孔。

跳转到指定楼层
风筝
发表于: 2019-8-14 13:53:22 | 显示全部楼层

电路原理图

现在我们开始介绍电路部分。以下是本文的完整电路图。

Arduino-Mecanum-Wheels-Robot-Circuit-Diagram.png

Arduino麦克纳姆轮机器人电路图


因此,我们将使用四个DRV8825步进驱动器控制四个NEMA 17步进电机,我们也可以使用A4988步进驱动器。为了给步进机和整个机器人供电,我们将使用12V电源,本文使用3S Li-Po电池,提供大约12V。我们使用的是NRF24L01模块进行无线通信,而对于蓝牙通信,我们使用的是HC-05蓝牙模块。我还包括一个简单的分压器,用于监控电池电压和一个LED连接,用于指示电池电压何时降至11V以下。

我还包括一个专用的5V电压调节器,可以提供大约3A的电流。


PCB电路板装配

当PCB电路板制作完成后,我们需要进行元器件装配。首先焊接较小的元件,电阻和电容。然后将插针焊接到PCB上,用于连接到Arduino开发板。

Soldering-pin-hearders-to-the-PCB.jpg


接下来,我将所有插座母头放置到位并焊接它们。至于步进电机连接和用于选择步进分辨率的引脚,我使用的是插座公头。这样我们就可以直接将电机连接到PCB,并使用跳线来选择步进分辨率。然后焊接接线端子和稳压器。

Assembling-the-PCB.jpg

这样,PCB已经准备就绪,我们可以继续插入驱动器并将电机连接到它上面。首先,我放置了用于选择步进分辨率的跳线。我通过将驱动器的MS3引脚连接到5V来选择16步分辨率。

Inserting-the-DRV8825-stepper-drivers-onto-the-PCB-sheild.jpg

然后在它们顶部放置了DRV8825驱动器,并连接了NRF24L01模块和HC-05蓝牙模块。现在我们可以简单地将PCB连接到Arduno板上。

Attaching-the-PCB-shield-to-the-Arduino-Mega-Board.jpg

接下来,我将电池连接到相应的接线盒并将它们放入基础平台。

Li-Po-battery-for-powering-the-Arduino-Mecanum-Wheels-Robot-Project.jpg

在这里,将电源开关插入到位并将其连接到另一个端子块。在电源开关正上方,我还插入了电池指示灯LED。

Battery-voltage-indicator-LED.jpg

现在剩下的就是将电机连接到PCB。我们应该注意到,当连接相对的电机时,我们也应该将它们的连接器连接在一起。因此,例如,向前命令,将两个马达沿相同方向移动,尽管它们实际上是翻转的,一个将顺时针旋转而另一个逆时针旋转。

Connecting-the-Stepper-Motors-to-the-PCB-Shield.jpg


最后,将盖子插入顶部,这样我们完成了这个麦克纳姆轮机器人的硬件组装部分。

Top-cover-for-the-robot-platform.jpg

回复

使用道具 举报

风筝
发表于: 2019-8-14 14:38:56 | 显示全部楼层

麦克纳姆轮机器人的Arduino代码

实际上,有两个单独的Arduino代码。 这一个用于使用NRF24L01模块控制机器人,另一个用于使用智能手机控制机器人。


使用NRF24L01模块控制机器人的Arduino代码:

  1. /*
  2.    === Arduino Mecanum Wheels Robot ===
  3.      Radio control with NRF24L01
  4.   by Dejan, www.HowToMechatronics.com
  5.   Libraries:
  6.   RF24, https://github.com/tmrh20/RF24/
  7.   AccelStepper by Mike McCauley: http://www.airspayce.com/mikem/arduino/AccelStepper/index.html
  8. */
  9. #include <SPI.h>
  10. #include <nRF24L01.h>
  11. #include <RF24.h>
  12. #include <AccelStepper.h>
  13. RF24 radio(48, 49);   // nRF24L01 (CE, CSN)
  14. const byte address[6] = "00001";
  15. unsigned long lastReceiveTime = 0;
  16. unsigned long currentTime = 0;
  17. // Define the stepper motors and the pins the will use
  18. AccelStepper LeftBackWheel(1, 42, 43);   // (Type:driver, STEP, DIR) - Stepper1
  19. AccelStepper LeftFrontWheel(1, 40, 41);  // Stepper2
  20. AccelStepper RightBackWheel(1, 44, 45);  // Stepper3
  21. AccelStepper RightFrontWheel(1, 46, 47); // Stepper4
  22. int wheelSpeed = 1500;
  23. // Max size of this struct is 32 bytes - NRF24L01 buffer limit
  24. struct Data_Package {
  25.   byte j1PotX;
  26.   byte j1PotY;
  27.   byte j1Button;
  28.   byte j2PotX;
  29.   byte j2PotY;
  30.   byte j2Button;
  31.   byte pot1;
  32.   byte pot2;
  33.   byte tSwitch1;
  34.   byte tSwitch2;
  35.   byte button1;
  36.   byte button2;
  37.   byte button3;
  38.   byte button4;
  39. };
  40. Data_Package data; //Create a variable with the above structure
  41. void setup() {
  42.   // Set initial seed values for the steppers
  43.   LeftFrontWheel.setMaxSpeed(3000);
  44.   LeftBackWheel.setMaxSpeed(3000);
  45.   RightFrontWheel.setMaxSpeed(3000);
  46.   RightBackWheel.setMaxSpeed(3000);
  47.   radio.begin();
  48.   radio.openReadingPipe(0, address);
  49.   radio.setAutoAck(false);
  50.   radio.setDataRate(RF24_250KBPS);
  51.   radio.setPALevel(RF24_PA_LOW);
  52.   radio.startListening(); //  Set the module as receiver
  53.   Serial.begin(115200);
  54. }
  55. void loop() {
  56.   // Check whether we keep receving data, or we have a connection between the two modules
  57.   currentTime = millis();
  58.   if ( currentTime - lastReceiveTime > 1000 ) { // If current time is more then 1 second since we have recived the last data, that means we have lost connection
  59.     resetData(); // If connection is lost, reset the data. It prevents unwanted behavior, for example if a drone jas a throttle up, if we lose connection it can keep flying away if we dont reset the function
  60.   }
  61.   // Check whether there is data to be received
  62.   if (radio.available()) {
  63.     radio.read(&data, sizeof(Data_Package)); // Read the whole data and store it into the 'data' structure
  64.     lastReceiveTime = millis(); // At this moment we have received the data
  65.   }
  66.   // Set speed - left potentiometer
  67.   wheelSpeed = map(data.pot1, 0, 255, 100, 3000);
  68.   
  69.   if (data.j1PotX > 150) {
  70.     moveSidewaysLeft();
  71.   }
  72.   else if (data.j1PotX < 100) {
  73.     moveSidewaysRight();
  74.   }
  75.   else if (data.j1PotY > 160) {
  76.     moveForward();
  77.   }
  78.   else if (data.j1PotY < 100) {
  79.     moveBackward();
  80.   }
  81.   else if (data.j2PotX < 100 & data.j2PotY > 160) {
  82.     moveRightForward();
  83.   }
  84.   else if (data.j2PotX > 160 & data.j2PotY > 160) {
  85.     moveLeftForward();
  86.   }
  87.   else if (data.j2PotX < 100 & data.j2PotY < 100) {
  88.     moveRightBackward();
  89.   }
  90.   else if (data.j2PotX > 160 & data.j2PotY < 100) {
  91.     moveLeftBackward();
  92.   }
  93.   else if (data.j2PotX < 100) {
  94.     rotateRight();
  95.   }
  96.   else if (data.j2PotX > 150) {
  97.     rotateLeft();
  98.   }
  99.   else {
  100.     stopMoving();
  101.   }
  102.   // Execute the steps
  103.   LeftFrontWheel.runSpeed();
  104.   LeftBackWheel.runSpeed();
  105.   RightFrontWheel.runSpeed();
  106.   RightBackWheel.runSpeed();
  107.   
  108.   // Monitor the battery voltage
  109.   int sensorValue = analogRead(A0);
  110.   float voltage = sensorValue * (5.0 / 1023.00) * 3; // Convert the reading values from 5v to suitable 12V i
  111.   // If voltage is below 11V turn on the LED
  112.   if (voltage < 11) {
  113.     digitalWrite(led, HIGH);
  114.   }
  115.   else {
  116.     digitalWrite(led, LOW);
  117.   }
  118. }
  119. void moveForward() {
  120.   LeftFrontWheel.setSpeed(wheelSpeed);
  121.   LeftBackWheel.setSpeed(wheelSpeed);
  122.   RightFrontWheel.setSpeed(wheelSpeed);
  123.   RightBackWheel.setSpeed(wheelSpeed);
  124. }
  125. void moveBackward() {
  126.   LeftFrontWheel.setSpeed(-wheelSpeed);
  127.   LeftBackWheel.setSpeed(-wheelSpeed);
  128.   RightFrontWheel.setSpeed(-wheelSpeed);
  129.   RightBackWheel.setSpeed(-wheelSpeed);
  130. }
  131. void moveSidewaysRight() {
  132.   LeftFrontWheel.setSpeed(wheelSpeed);
  133.   LeftBackWheel.setSpeed(-wheelSpeed);
  134.   RightFrontWheel.setSpeed(-wheelSpeed);
  135.   RightBackWheel.setSpeed(wheelSpeed);
  136. }
  137. void moveSidewaysLeft() {
  138.   LeftFrontWheel.setSpeed(-wheelSpeed);
  139.   LeftBackWheel.setSpeed(wheelSpeed);
  140.   RightFrontWheel.setSpeed(wheelSpeed);
  141.   RightBackWheel.setSpeed(-wheelSpeed);
  142. }
  143. void rotateLeft() {
  144.   LeftFrontWheel.setSpeed(-wheelSpeed);
  145.   LeftBackWheel.setSpeed(-wheelSpeed);
  146.   RightFrontWheel.setSpeed(wheelSpeed);
  147.   RightBackWheel.setSpeed(wheelSpeed);
  148. }
  149. void rotateRight() {
  150.   LeftFrontWheel.setSpeed(wheelSpeed);
  151.   LeftBackWheel.setSpeed(wheelSpeed);
  152.   RightFrontWheel.setSpeed(-wheelSpeed);
  153.   RightBackWheel.setSpeed(-wheelSpeed);
  154. }
  155. void moveRightForward() {
  156.   LeftFrontWheel.setSpeed(wheelSpeed);
  157.   LeftBackWheel.setSpeed(0);
  158.   RightFrontWheel.setSpeed(0);
  159.   RightBackWheel.setSpeed(wheelSpeed);
  160. }
  161. void moveRightBackward() {
  162.   LeftFrontWheel.setSpeed(0);
  163.   LeftBackWheel.setSpeed(-wheelSpeed);
  164.   RightFrontWheel.setSpeed(-wheelSpeed);
  165.   RightBackWheel.setSpeed(0);
  166. }
  167. void moveLeftForward() {
  168.   LeftFrontWheel.setSpeed(0);
  169.   LeftBackWheel.setSpeed(wheelSpeed);
  170.   RightFrontWheel.setSpeed(wheelSpeed);
  171.   RightBackWheel.setSpeed(0);
  172. }
  173. void moveLeftBackward() {
  174.   LeftFrontWheel.setSpeed(-wheelSpeed);
  175.   LeftBackWheel.setSpeed(0);
  176.   RightFrontWheel.setSpeed(0);
  177.   RightBackWheel.setSpeed(-wheelSpeed);
  178. }
  179. void stopMoving() {
  180.   LeftFrontWheel.setSpeed(0);
  181.   LeftBackWheel.setSpeed(0);
  182.   RightFrontWheel.setSpeed(0);
  183.   RightBackWheel.setSpeed(0);
  184. }
  185. void resetData() {
  186.   // Reset the values when there is no radio connection - Set initial default values
  187.   data.j1PotX = 127;
  188.   data.j1PotY = 127;
  189.   data.j2PotX = 127;
  190.   data.j2PotY = 127;
  191.   data.j1Button = 1;
  192.   data.j2Button = 1;
  193.   data.pot1 = 1;
  194.   data.pot2 = 1;
  195.   data.tSwitch1 = 1;
  196.   data.tSwitch2 = 1;
  197.   data.button1 = 1;
  198.   data.button2 = 1;
  199.   data.button3 = 1;
  200.   data.button4 = 1;
  201. }
复制代码

代码描述:以上代码是使用RF24库进行无线电通信,使用AccelStepper库来控制步进电机。首先,我们需要定义所有连接的引脚,定义下面程序所需的一些变量,并在setup函数部分设置步进器最大速度并开始无线电通信。

loop()函数部分,我们首先读取来自RC发射器的数据。 因此,根据接收到的数据,例如,如果向左移动操纵杆,其值将大于160,在这种情况下将调用moveForward()自定义函数。该函数就是将电机的速度设置为正。向后移动时,速度设置为负。因此,为了在所有其他方向上移动,我们必须如开头所述适当地设置轮子的旋转。

为了执行这些命令,在loop部分我们需要为所有步进器调用runSpeed()函数。在loop函数部分,我们还读取了来自电池的分压器的模拟输入,根据这个值,我们可以知道电池电压何时降至11V以下,这样我们就可以打开指示LED。

回复

使用道具 举报

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

本版积分规则

主题 700 | 回复: 1479



手机版|

GMT+8, 2024-3-29 21:16 , Processed in 0.094829 second(s), 6 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

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

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