17浏览
查看: 17|回复: 2

[项目] 【Arduino 动手做】全向旋转和平移的六轴球平衡机器人

[复制链接]
在这个 instructable 中,我将逐步向您展示我是如何创建球平衡机器人的。更正式的名称是 Stewart 平台,这个机器人具有 6DOF 机器人是全向旋转和全平移的。通过添加摄像头,这个 Stewart 平台可以变成一个防止球掉落的机器人。

以下是构建所需的工具和部件列表。

工具
尖嘴钳
剪线钳
剥线钳
2.5mm 内六角扳手
烙铁和焊料
Exacto 刀
热胶枪和热胶
零件 ($483)
电子产品 ($400)
JX CLS6336HV 35kg 数字舵机 (x6)
小小 4.1
6 通道 Polulu Maestro 伺服控制器
Pixy2 相机
3.3 至 5V 逻辑电平转换器
半原型板 + 螺丝端子
SPST 开关
18 AWG 电线
XT60H 连接器对
2S (7.4v) 6200mah 锂电池
其他用品 ($83)
25T 伺服盘 (x 6)
M3 x 120mm 推杆连接器 (x6)
22mm 长的 M3 拉杆 (x12)
M3 x 6mm 螺纹嵌件 (x36)
M3 x 10mm 支座 (x3)
M3 x 5mm 支座 (x14)
M3 锁紧螺母 (x24)
3/4 x 48 英寸木销钉
#6 x 1-1/4 英寸木螺丝 (x4)
M3 螺丝
m3 x 5 毫米 (x24)
m3 x 10 毫米 (x2)
m3 x 12 毫米 (x18)
m3 x 14 毫米 (x6)
m3 x 15 毫米 (x4)
M3 x 20mm 圆头 (x3)
m3 x 22 毫米 (x6)
m3 x 30 毫米 (x3)

球放在一个透明的 0.118 英寸厚的 8 英寸 x 8 英寸聚碳酸酯平台上。您将需要制造此平台。我无法使用水刀,因此我在 Andymark 站点上使用了水刀服务。如果您走这条路线,我已经在下面附上了 dxf 文件。另一种选择是简单地从一块聚碳酸酯上切出一个 8 英寸 x 8 英寸的平台,然后钻出所有孔。我还在下面附上了该平台的 pdf 图纸。

我在 Autodesk Inventor 中设计了这个机器人。总共有 18 个 3D 打印部件。我用 PLA 细丝打印了所有这些部件。我附上了下面的所有 STL 文件。请记住,某些零件必须多次打印。此编号在文件名中指定。除了球和中心标记外,零件的颜色无关紧要。这些应打印为红色,以便相机轻松检测到。

现在进入项目的核心,电子设备!正确创建电路对于此项目至关重要。制作电路的第一部分是准备 teensy 4.1 微控制器。teensy 是机器人的大脑。所有其他电子元件都连接到 teensy。我们将使用 Arduino IDE 进行编程。如果您以前从未使用过 teensy,则需要执行以下两项作之一,以允许 Arduino 软件支持 teensy。
如果您使用的是 Arduino 2.0.0 或更高版本,则需要按照此处的说明允许 Arduino 支持 teensy。
如果您使用的是低于 2.0.0 的 Arduino 版本,则需要下载 Teensyduino 才能允许 Arduino 支持 teensy。
完成此作后,我建议通过将 blink 示例草图上传到 teensy 来验证一切是否正常。
在此之后,您需要通过在 teensy 背面剪切 VIN 到 USB 跟踪来修改 teensy。我指出了图像 #2 中剪切此轨迹的位置。它也在图 #4 的图表上进行了标记。这样做可以确保 teensy 需要外部电源才能工作。我们希望完成这项工作,因为我们将使用 7.4V 电池为 teensy 供电。我们不需要 teensy 在插入计算机时由计算机供电。
有关 teensy 4.1 微控制器的更多信息,请点击此处。
注意:teensy 不会从电池接收 7.4V,因为这太高了。teensy 将收到 5V。它将从 polulu maestro 获得这个 5V(下一步会详细介绍)。

现在,我们将伺服臂安装到伺服系统上。为此,我们必须首先上传一个 Arduino 草图,该草图会将所有舵机移动到它们的主位置。
确保电池已插上并且开关已打开,然后将下面的 Arduino 草图上传到 teensy。您应该听到所有伺服器都转向它们的起始位置。
现在拧上伺服臂(使用 m3 x 12mm 螺钉 (x6)),使它们尽可能接近垂直于伺服器,如图 #4 所示。对所有 servos 执行此作。
微调伺服位置
正如您会注意到的那样,当连接伺服臂时,它们不会像图像 #4 那样完全垂直。它们很可能看起来更像图像 #3。 要使这些伺服臂完全垂直,您需要更改代码中每个伺服的偏移值。
在这部分代码中,所有偏移值最初都将设置为 0,如图 #5 所示。 遍历每个伺服器并将偏移值从 0 更改为 5。查看伺服臂是否更接近垂直。
如果它确实更接近垂直,请通过升高或低于 5 来微调伺服臂的位置,但仍保持该值为正。例如,如果伺服臂需要更接近垂直,则可以将值更改为 7。
如果伺服器远离垂直,则将偏移值设为 -5 并微调该值(同时仍保持负值),直到机械臂完全垂直。对所有 servos 执行此作。最后,您将得到每个伺服的偏移值,如图 #6 所示。
任何 servos 都不应超过 -14 和 14 之间的偏移值范围。
注: 每次更改偏移值时,请重新上传草图以查看其效果。
确保将这些偏移值保存在某个位置,稍后需要更改其他两个程序的偏移值。
完成此作后,每次将此草图上传到机器人时,所有手臂都应移动到其初始位置并完全垂直。

对这个机器人进行编程有两个主要组件:旋转平台和平衡球。能够向任何方向旋转平台是允许机器人平衡球的原因。那么机器人是如何完成这些任务的呢?
旋转平台:
为了能够旋转平台,机器人必须使用逆运动方程。这些方程式接受一个输入(我们希望机器人如何定向)并输出 6 个值(每个伺服器要转向的位置)。例如,当我们希望平台完全平坦时,机器人会计算出所有伺服系统都必须移动到其初始位置。我使用矢量微积分推导出了所有这些方程。您可以在图 #1 中看到这些方程。
平衡球:
为了能够平衡球,机器人使用 PD 算法,其中:
设定点是平台的中心。
误差是球相对于平台中心的位置。
导数项是球的速度。
这是在图片 #4 中绘制的
因此,为了平衡球,机器人必须考虑球的位置和球在任何给定时刻的速度。然后,它使用这些值同时将球移近平台中心并减慢球的速度。
如果只考虑球的位置,那么机器人将无法减慢球的速度,球会掉落。
如果只考虑球的速度,那么机器人将无法将球移近平台中心,球最终会掉落。
一旦机器人确定了使平台倾斜以减慢球速并将其更靠近中心的最有效方向,它就会使用逆运动学方程来确定移动伺服系统的位置,以使平台移动到该倾斜位置。

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图2

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图1

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图3

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图6

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图4

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图5

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图7

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图8

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图9

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图10

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图12

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图11

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图15

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图13

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图14

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图17

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图16

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图18

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图19

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图20

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图21

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人图22

驴友花雕  中级技神
 楼主|

发表于 6 小时前

【Arduino 动手做】全向旋转和平移的六轴球平衡机器人

项目代码

  1. /*               ****NOTES****
  2.   Before using this, go to the Serial Settings
  3.   tab in the Maestro Control Center and apply these settings:
  4.    Serial mode: UART, fixed baud rate
  5.    Baud rate: 9600
  6.    CRC disabled
  7.   Be sure to click "Apply Settings" after making any changes.
  8.   Array Indexes
  9.   -------------
  10.   a1 = 0
  11.   a2 = 1
  12.   b1 = 2
  13.   b2 = 3
  14.   c1 = 4
  15.   c2 = 5
  16.   range for hz (105, 140)
  17. */
  18. // libraries
  19. #include "PololuMaestro.h"
  20. #include "math.h"
  21. #include <Pixy2SPI_SS.h>
  22. #define maestroSerial SERIAL_PORT_HARDWARE_OPEN  //for teensy
  23. // objects
  24. Pixy2SPI_SS pixy;
  25. MicroMaestro maestro(maestroSerial);  // if using the Maestro Micro controller
  26. //**CONSTANTS**
  27. //-------------
  28. float abs_0 = 4000;                                     //ms position of absolute 0 degrees
  29. float abs_90 = 8000;                                    //ms position of absolute 90 degrees
  30. float toDeg = 180 / PI;                                 // radians to degrees conversion factor
  31. int x = 0, y = 1, z = 2;                                // defines x, y, and z array indexes to be used
  32. String ID[6] = { "a1", "a2", "b1", "b2", "c1", "c2" };  //servo ID's
  33. //**USER DEFINED VALUES**
  34. //----------------------
  35. // angle range for each servo going CCW
  36. // each servo can move from absolute 0 to absolute 90 degrees
  37. // this defines a different range such as 90 to 180 degrees
  38. float range[6][2] = { { -45, 45 }, { 45, -45 },  // a1, a2
  39.                       { -45, 45 },
  40.                       { 45, -45 },  // b1, b2
  41.                       { -45, 45 },
  42.                       { 45, -45 } };  // c1, c2
  43. // angle offset value for each servo (should be less than 14 degrees since there are 25 teeth on the servo)
  44. // redefines the position of the lower range of each servo
  45. // Example: a servo with a range [0, 90] and an offset value of 5 would have its new 0 degree position where the old 5 degree position was
  46. float offset[6] = { 0, 0,    // channel #0 and channel #1
  47.                     0, 0,    // channel #2 and channel #3
  48.                     0, 0 };  // channel #4 and channel #5
  49. //**INVERSE KINEMATICS**
  50. //----------------------
  51. // user defined lengths (in mm)
  52. float l0 = 73.025;
  53. float lf = 67.775;
  54. float d1 = 36.8893;
  55. float d2 = 38.1;
  56. float m = 12.7;
  57. float p1 = 31.75;
  58. float p2 = 129;
  59. //calculates normal vectors nab, nac, and nbc for each side of the triangle
  60. float nab[3] = { sqrt(3) * 0.5, -0.5, 0 };
  61. float nac[3] = { sqrt(3) * 0.5, 0.5, 0 };
  62. float nbc[3] = { 0, 1, 0 };
  63. // intermediate variables
  64. float t = (pow(lf, 2) * sqrt(3)) / 2;
  65. float u = sqrt(pow(l0, 2) + pow(d1, 2)) * sin((2 * PI / 3) - atan(l0 / d1));  //(2*pi/3 is 120 degrees)
  66. // calculates points a10, a20, b10, b20, c10, and c20
  67. float a10[3] = { (d2 - u * sqrt(3)) / 2, (-u - d2 * sqrt(3)) / 2, 0 };
  68. float a20[3] = { -a10[x], a10[y], 0 };
  69. float b10[3] = { (u * sqrt(3) + d2) / 2, (d2 * sqrt(3) - u) / 2, 0 };
  70. float b20[3] = { d2, u, 0 };
  71. float c10[3] = { -b20[x], b20[y], 0 };
  72. float c20[3] = { -b10[x], b10[y], 0 };
  73. // calculates vectors, ab, ac, and bc
  74. float ab[3] = { a20[x] - b10[x], a20[y] - b10[y], a20[z] - b10[z] };
  75. float ac[3] = { a10[x] - c20[x], a10[y] - c20[y], a10[z] - c20[z] };
  76. float bc[3] = { b20[x] - c10[x], b20[y] - c10[y], b20[z] - c10[z] };
  77. float theta[6];                      //array for calculated theta values a1, a2, b1, b2, c1, c2 respectively
  78. float nz = 1;                        //nz is predefined
  79. float hz_norm = 118.19374266158451;  //normal hz value (at this height all servos are at 0 degrees)
  80. float r_max = 0.25;                  // max radius of the nx and ny graph when nz = 1
  81. //pixy2 cam
  82. //----------------------
  83. float origin[2] = { 0, 0 };  // X and Y co-ords of the origin
  84. float r_platform = 0;          // the distance from the center of the platform to the corner of the platform seen from the pixy2 cam
  85. float ball[2];                   // X and Y co-ords of the ball
  86. // PID
  87. //----------------------
  88. float error[2];       // error of the ball
  89. float error_prev[2];  // previous error value used to calculate derivative. Derivative = (error-previous_error)/(change in time)
  90. float deriv[2];       // derivative of the error
  91. float deriv_prev[2];  // previous derivative value
  92. float kp = 6e-4;      // proportional constant
  93. float kd = 0.56;      // derivative constant
  94. float out[2];         // output values (nx and ny)
  95. float time_i;         // initial time
  96. float time_f;         // final time
  97. float time;           //change in time
  98. void setup() {
  99.   Serial.begin(115200);
  100.   maestroSerial.begin(9600);
  101.   pixy.init();
  102. }
  103. void loop() {
  104.   findBall();  // finds the location of the ball
  105.   if (ball[x] == 4004 && ball[y] == 4004) {
  106.     // sees if ball position (x and y) is 4004, if so then the ball is not detected and platform should be in home position
  107.     InverseKinematics(0, 0, hz_norm, 0, 0, 0);  //hx, hy, hz, nx, ny, ax
  108.     moveServos(20, 20);
  109.   } else {
  110.     PD();  // calculates the proportional and derivative terms and outputs them to the platform
  111.   }
  112.   //Serial.println((String)"BALL LOCATION: [" + ball[x]+", "+ball[y]+"]"); //prints location of the ball
  113.   //Serial.println((String)"OUTPUT: [" + out[x]+", "+ out[y]+"]"); //prints the output values
  114. }
  115. //Functions
  116. void moveServo(int i, float pos, int spd, int acc) {        //moves servo i to an input position at a certain speed and acceleration value
  117.   pos = pos + offset[i];                                    //adds offset amount to the input position
  118.   pos = map(pos, range[i][0], range[i][1], abs_0, abs_90);  //converts input pos to ms position
  119.   maestro.setSpeed(i, spd);                                 //sets input speed to servo i
  120.   maestro.setAcceleration(i, spd);                          //sets input acceleration to servo i
  121.   maestro.setTarget(i, pos);                                //drives motor to calculated position
  122. }
  123. void moveServos(int spd, int acc) {  //moves servos to their calculated positions at a certain speed and acceleration value
  124.   float pos;
  125.   for (int i = 0; i < 6; i++) {
  126.     maestro.setSpeed(i, spd);                                 //sets input speed to servo i
  127.     maestro.setAcceleration(i, acc);                          //sets input acceleration to servo i
  128.     pos = theta[i] + offset[i];                               //adds offset amount to the calculated angle
  129.     pos = map(pos, range[i][0], range[i][1], abs_0, abs_90);  //converts input pos to ms position
  130.     maestro.setTarget(i, pos);                                //drives motor to calculated position
  131.   }
  132. }
  133. void stop() {  //ends the program and stops all of the servos
  134.   for (int i = 0; i < 6; i++) {
  135.     maestro.setTarget(i, 0);  //stops servo i
  136.   }
  137.   while (1) {}
  138. }
  139. void findBall() {  // find the location of the ball using the pixy2 cam
  140.                    // grab blocks!
  141.   pixy.ccc.getBlocks();
  142.   // If there is 1 ball detected then collect and print the data
  143.   if (pixy.ccc.numBlocks == 1) {
  144.     //sets current X and Y co-ords
  145.     ball[x] = pixy.ccc.blocks[0].m_x;  // absolute X location of the ball
  146.     ball[y] = pixy.ccc.blocks[0].m_y;  // absolute Y location of the ball
  147.   }
  148.   // If there are multiple balls detected, then print so
  149.   else if (pixy.ccc.numBlocks > 1) {
  150.     Serial.println("MULTIPLE BALLS DETECTED");
  151.     ball[x] = 4004;  // X component of the ball
  152.     ball[y] = 4004;  // Y component of the ball
  153.   }
  154.   // If there is no ball detected, then print so
  155.   else {
  156.     //Serial.println("NO BALL DETECTED");
  157.     ball[x] = 4004;  // X component of the ball
  158.     ball[y] = 4004;  // Y component of the ball
  159.   }
  160. }
  161. void PD() {  // calculates the Proportional and Derivative values and moves the servos
  162.   // calculates the error of the ball
  163.   // the error is the difference of the location of the center of the ball and the center of the platform
  164.   // it is essentially a vector pointing from the center of the platform to the center of the ball
  165.   error[x] = origin[x] - ball[x];  // x component of error
  166.   error[y] = ball[y] - origin[y];  // y component of error
  167.   time_f = millis();       // sets final time
  168.   time = time_f - time_i;  // change in time
  169.   time_i = millis();
  170.   // sets initial time
  171.   deriv[x] = (error[x] - error_prev[x]) / time;  // x component of derivative
  172.   deriv[y] = (error[y] - error_prev[y]) / time;  // y component of derivative
  173.   // checks if derivative is NaN or INF. If so, set to zero
  174.   if (isnan(deriv[x]) || isinf(deriv[x])) {  // x component of derivative
  175.     deriv[x] = 0;
  176.   }
  177.   if (isnan(deriv[y]) || isinf(deriv[y])) {  // y component of derivative
  178.     deriv[y] = 0;
  179.   }
  180.   // sets previous error to current error
  181.   error_prev[x] = error[x];  // x component of previous error
  182.   error_prev[y] = error[y];  // x component of previous error
  183.   float r_ball = sqrt(pow(error[x], 2) + pow(error[y], 2));  // calculates the distance from the center of the platfrom to the ball
  184.   if (r_ball > r_platform) {
  185.     // checks to see if the platform should be moved to the home position
  186.     // checks if the ball is on the platform by comparing r_ball and r_platform. If r_ball is greater than r_platform, the ball is off the platform and the platform should be in the home position
  187.     InverseKinematics(0, 0, hz_norm, 0, 0, 0);  //hx, hy, hz, nx, ny, ax
  188.     moveServos(20, 20);
  189.   }
  190.   else {  //if the ball should not be in the home position then calculate PD outputs
  191.     // output values
  192.     out[x] = (error[x] * kp) + (deriv[x] * kd);  // calculates output x by adding proportional*kp and derivative*kd terms
  193.     out[y] = (error[y] * kp) + (deriv[y] * kd);  // calculates output y by adding proportional*kp and derivative*kd terms
  194.     // error prevention
  195.     float r_out = sqrt(pow(out[x], 2) + pow(out[y], 2));  //calculates magnitude of the out vector
  196.     if (r_out > r_max) {                                  // if the magnitude of the out vector is greater than r_max, then scale the out vector to have a magnitude of r
  197.       out[x] = out[x] * (r_max / r_out);
  198.       out[y] = out[y] * (r_max / r_out);
  199.     }
  200.     //move platform
  201.     InverseKinematics(0, 0, hz_norm, out[x], out[y], 0);  //hx, hy, hz, nx, ny, ax
  202.     moveServos(0, 0);
  203.   }
  204. }
  205. void InverseKinematics(float hx, float hy, float hz, float nx, float ny, float ax) {  // calculates theta values given hx, hy, hz, nx, ny, and ax (nz = 1 always)
  206.   //define vectors and points
  207.   float a[3] = { ax, 0, 0 }, a1f[3], a2f[3];
  208.   float b[3], b1f[3], b2f[3];
  209.   float c[3], c1f[3], c2f[3];
  210.   float n[3] = { nx, ny, nz };  // defines normal vector
  211.   n[x] = nx / mag(n);
  212.   n[y] = ny / mag(n);
  213.   n[z] = nz / mag(n);  // converts vector 'n' to a unit vector
  214.   float h[3] = { hx, hy, hz };  // defined point h (center point of platform)
  215.   // **STAGE 1 CALCULATIONS**
  216.   //-------------------------
  217.   // in regards to e, g, and k indexes 0, 1, and 2 are a, b, and c respectively
  218.   float e[3], g[3], k[3];
  219.   // af components
  220.   e[0] = a[x] - h[x];                                                                                                       // 'ea'
  221.   a[z] = ((n[y] * sqrt(pow(lf, 2) * (1 - pow(n[x], 2)) - pow(e[0], 2)) - n[z] * n[x] * e[0]) / (1 - pow(n[x], 2))) + h[z];  // 'az'
  222.   g[0] = a[z] - h[z];                                                                                                       // calculates 'ga'
  223.   a[y] = h[y] - sqrt(pow(lf, 2) - pow(g[0], 2) - pow(e[0], 2));                                                             // 'ay'
  224.   k[0] = a[y] - h[y];                                                                                                       // 'ka'
  225.   float w = sqrt(3) * (n[x] * g[0] - n[z] * e[0]);  // intermediate variable
  226.   // bf components
  227.   b[y] = h[y] + ((sqrt(pow(w, 2) - 3 * pow(lf, 2) * (1 - pow(n[y], 2)) + pow(2 * k[0], 2)) - w) / 2);  // 'by'
  228.   k[1] = b[y] - h[y];                                                                                  // 'kb'
  229.   b[x] = ((e[0] * k[1] - n[z] * t) / k[0]) + h[x];                                                     // 'bx'
  230.   e[1] = b[x] - h[x];                                                                                  // 'eb'
  231.   b[z] = ((n[x] * t + g[0] * k[1]) / k[0]) + h[z];                                                     //'bz'
  232.   g[1] = b[z] - h[z];                                                                                  // 'gb'
  233.   // cf components
  234.   c[y] = h[y] + ((w + sqrt(pow(w, 2) - 3 * pow(lf, 2) * (1 - pow(n[y], 2)) + pow(2 * k[0], 2))) / 2);  // 'cy'
  235.   k[2] = c[y] - h[y];                                                                                  // 'kc'
  236.   c[x] = ((e[0] * k[2] + n[z] * t) / k[0]) + h[x];                                                     // 'cx'
  237.   e[2] = c[x] - h[x];                                                                                  // 'ec'
  238.   c[z] = ((g[0] * k[2] - n[x] * t) / k[0]) + h[z];                                                     // 'cz'
  239.   g[2] = c[z] - h[z];                                                                                  // 'gc'
  240.   // STAGE 2 CALCULATIONS
  241.   //---------------------
  242.   // a1
  243.   a1f[x] = a[x] + (m / lf) * (n[z] * k[0] - n[y] * g[0]);  // a1fx
  244.   if (e[0] == 0) {                                         //if e[0] is 0 then there will be a divide by zero error
  245.     a1f[y] = a[y];                                         // a1fy
  246.     a1f[z] = a[z];                                         // a1fz
  247.   } else {
  248.     a1f[y] = a[y] + ((a1f[x] - a[x]) * k[0] - n[z] * lf * m) / e[0];  // a1fy
  249.     a1f[z] = a[z] + (n[y] * lf * m + (a1f[x] - a[x]) * g[0]) / e[0];  // a1fz
  250.   }
  251.   float a1[3] = { a1f[x] - a10[x], a1f[y] - a10[y], a1f[z] - a10[z] };  // vector 'a1'
  252.   // a2
  253.   a2f[x] = 2 * a[x] - a1f[x];                                           // a2fx
  254.   a2f[y] = 2 * a[y] - a1f[y];                                           // a2fy
  255.   a2f[z] = 2 * a[z] - a1f[z];                                           // a2fz
  256.   float a2[3] = { a2f[x] - a20[x], a2f[y] - a20[y], a2f[z] - a20[z] };  // vector 'a2'
  257.   // b1
  258.   b1f[x] = b[x] + (m / lf) * (n[z] * k[1] - n[y] * g[1]);               // b1fx
  259.   b1f[y] = b[y] + ((b1f[x] - b[x]) * k[1] - n[z] * lf * m) / e[1];      // b1fy
  260.   b1f[z] = b[z] + (n[y] * lf * m + (b1f[x] - b[x]) * g[1]) / e[1];      // b1fz
  261.   float b1[3] = { b1f[x] - b10[x], b1f[y] - b10[y], b1f[z] - b10[z] };  // vector 'b1'
  262.   // b2
  263.   b2f[x] = 2 * b[x] - b1f[x];                                           // b2fx
  264.   b2f[y] = 2 * b[y] - b1f[y];                                           // b2fy
  265.   b2f[z] = 2 * b[z] - b1f[z];                                           // b2fz
  266.   float b2[3] = { b2f[x] - b20[x], b2f[y] - b20[y], b2f[z] - b20[z] };  // vector 'b2'
  267.   // c1
  268.   c1f[x] = c[x] + (m / lf) * (n[z] * k[2] - n[y] * g[2]);               // c1fx
  269.   c1f[y] = c[y] + ((c1f[x] - c[x]) * k[2] - n[z] * lf * m) / e[2];      // c1fy
  270.   c1f[z] = c[z] + (n[y] * lf * m + (c1f[x] - c[x]) * g[2]) / e[2];      // c1fz
  271.   float c1[3] = { c1f[x] - c10[x], c1f[y] - c10[y], c1f[z] - c10[z] };  // vector 'c1'
  272.   // c2
  273.   c2f[x] = 2 * c[x] - c1f[x];                                           // c2fx
  274.   c2f[y] = 2 * c[y] - c1f[y];                                           // c2fy
  275.   c2f[z] = 2 * c[z] - c1f[z];                                           // c2fzSerial.println("-----------------------");
  276.   float c2[3] = { c2f[x] - c20[x], c2f[y] - c20[y], c2f[z] - c20[z] };  // vector 'c2'
  277.   //**STAGE 3 CALCULATIONS**
  278.   //------------------------
  279.   // theta_a1
  280.   float a1s[3] = { nac[x] * dot(a1, nac), nac[y] * dot(a1, nac), nac[z] * dot(a1, nac) };                                // vector 'a1s'
  281.   float mag_a1s = mag(a1s);                                                                                              // magnitude of vector 'a1s'
  282.   float a1_proj[3] = { a1[x] - a1s[x], a1[y] - a1s[y], a1[z] - a1s[z] };                                                 // projection of vector 'a1' onto the ac plane
  283.   float mag_a1_proj = mag(a1_proj);                                                                                      // magnitude of vector 'a1' projected on the ac plane
  284.   float mag_p2a1 = sqrt(pow(p2, 2) - pow(mag_a1s, 2));                                                                   // magnitude of link p2 projected on the ac plane
  285.   theta[0] = acos(-dot(a1_proj, ac) / (2 * d2 * mag_a1_proj));                                                           // theta a1
  286.   theta[0] = (theta[0] - acos((pow(mag_a1_proj, 2) + pow(p1, 2) - pow(mag_p2a1, 2)) / (2 * mag_a1_proj * p1))) * toDeg;  // theta a1 continued calculation
  287.   // theta_a2
  288.   float a2s[3] = { nab[x] * dot(a2, nab), nab[y] * dot(a2, nab), nab[z] * dot(a2, nab) };                                // vector 'a2s'
  289.   float mag_a2s = mag(a2s);                                                                                              // magnitude of vector 'a2s'
  290.   float a2_proj[3] = { a2[x] - a2s[x], a2[y] - a2s[y], a2[z] - a2s[z] };                                                 // projection of vector 'a2' onto the ab plane
  291.   float mag_a2_proj = mag(a2_proj);                                                                                      // magnitude of vector 'a2' projected on the ab plane
  292.   float mag_p2a2 = sqrt(pow(p2, 2) - pow(mag_a2s, 2));                                                                   // magnitude of link p2 projected on the ab plane
  293.   theta[1] = acos(-dot(a2_proj, ab) / (2 * d2 * mag_a2_proj));                                                           // theta a2
  294.   theta[1] = (theta[1] - acos((pow(mag_a2_proj, 2) + pow(p1, 2) - pow(mag_p2a2, 2)) / (2 * mag_a2_proj * p1))) * toDeg;  // theta a2 continued calculation
  295.   // theta_b1
  296.   float b1s[3] = { nab[x] * dot(b1, nab), nab[y] * dot(b1, nab), nab[z] * dot(b1, nab) };                                // vector 'b1s'
  297.   float mag_b1s = mag(b1s);                                                                                              // magnitude of vector 'b1s'
  298.   float b1_proj[3] = { b1[x] - b1s[x], b1[y] - b1s[y], b1[z] - b1s[z] };                                                 // projection of vector 'b1' onto the ab plane
  299.   float mag_b1_proj = mag(b1_proj);                                                                                      // magnitude of vector 'b1' projected on the ab plane
  300.   float mag_p2b1 = sqrt(pow(p2, 2) - pow(mag_b1s, 2));                                                                   // magnitude of link p2 projected on the ab plane
  301.   theta[2] = acos(dot(b1_proj, ab) / (2 * d2 * mag_b1_proj));                                                            // theta b1
  302.   theta[2] = (theta[2] - acos((pow(mag_b1_proj, 2) + pow(p1, 2) - pow(mag_p2b1, 2)) / (2 * mag_b1_proj * p1))) * toDeg;  // theta b1 continued calculation
  303.   // theta_b2
  304.   float b2s[3] = { nbc[x] * dot(b2, nbc), nbc[y] * dot(b2, nbc), nbc[z] * dot(b2, nbc) };                                // vector 'b2s'
  305.   float mag_b2s = mag(b2s);                                                                                              // magnitude of vector 'b2s'
  306.   float b2_proj[3] = { b2[x] - b2s[x], b2[y] - b2s[y], b2[z] - b2s[z] };                                                 // projection of vector 'b2' onto the bc plane
  307.   float mag_b2_proj = mag(b2_proj);                                                                                      // magnitude of vector 'b2' projected on the bc plane
  308.   float mag_p2b2 = sqrt(pow(p2, 2) - pow(mag_b2s, 2));                                                                   // magnitude of link p2 projected on the bc plane
  309.   theta[3] = acos(-dot(b2_proj, bc) / (2 * d2 * mag_b2_proj));                                                           // theta b2
  310.   theta[3] = (theta[3] - acos((pow(mag_b2_proj, 2) + pow(p1, 2) - pow(mag_p2b2, 2)) / (2 * mag_b2_proj * p1))) * toDeg;  // theta b2 continued calculation
  311.   // theta_c1
  312.   float c1s[3] = { nbc[x] * dot(c1, nbc), nbc[y] * dot(c1, nbc), nbc[z] * dot(c1, nbc) };                                // vector 'c1s'
  313.   float mag_c1s = mag(c1s);                                                                                              // magnitude of vector 'c1s'
  314.   float c1_proj[3] = { c1[x] - c1s[x], c1[y] - c1s[y], c1[z] - c1s[z] };                                                 // projection of vector 'c1' onto the bc plane
  315.   float mag_c1_proj = mag(c1_proj);                                                                                      // magnitude of vector 'c1' projected on the bc plane
  316.   float mag_p2c1 = sqrt(pow(p2, 2) - pow(mag_c1s, 2));                                                                   // magnitude of link p2 projected on the bc plane
  317.   theta[4] = acos(dot(c1_proj, bc) / (2 * d2 * mag_c1_proj));                                                            // theta c1
  318.   theta[4] = (theta[4] - acos((pow(mag_c1_proj, 2) + pow(p1, 2) - pow(mag_p2c1, 2)) / (2 * mag_c1_proj * p1))) * toDeg;  // theta c1 continued calculation
  319.   //theta_c2
  320.   float c2s[3] = { nac[x] * dot(c2, nac), nac[y] * dot(c2, nac), nac[z] * dot(c2, nac) };                                // vector 'c2s'
  321.   float mag_c2s = mag(c2s);                                                                                              // magnitude of vector 'c2s'
  322.   float c2_proj[3] = { c2[x] - c2s[x], c2[y] - c2s[y], c2[z] - c2s[z] };                                                 // projection of vector 'c2' onto the ac plane
  323.   float mag_c2_proj = mag(c2_proj);                                                                                      // magnitude of vector 'c2' projected on the ac plane
  324.   float mag_p2c2 = sqrt(pow(p2, 2) - pow(mag_c2s, 2));                                                                   // magnitude of link p2 projected on the ac plane
  325.   theta[5] = acos(dot(c2_proj, ac) / (2 * d2 * mag_c2_proj));                                                            // theta c2
  326.   theta[5] = (theta[5] - acos((pow(mag_c2_proj, 2) + pow(p1, 2) - pow(mag_p2c2, 2)) / (2 * mag_c2_proj * p1))) * toDeg;  // theta c2 continued calculation
  327.   for (int i = 0; i < 6; i++) {  //checks for errors to see if theta values are between -40 and 40 degrees and if they are real numbers
  328.     //Serial.print(String("theta "+ID[i]+": ")); // prints servo ID
  329.     //Serial.println(theta[i], 6); // prints theta value
  330.     if (abs(theta[i]) > 40) {
  331.       Serial.println("ERROR: CURRENT VALUES EXCEED ANGLE RANGE");
  332.       stop();
  333.     }
  334.     if (isnan(theta[i])) {
  335.       Serial.println("ERROR: CURRENT VALUES CANNOT PHYSICALLY BE EXECUTED");
  336.       stop();
  337.     }
  338.   }
  339. }
  340. float mag(float array[]) {  //finds the magnitude of an array of size 3
  341.   float mag = 0;
  342.   for (int i = 0; i < 3; i++) {
  343.     mag = mag + pow(array[i], 2);  //adds component i of array squared
  344.   }
  345.   mag = sqrt(mag);
  346.   return mag;
  347. }
  348. float dot(float array1[], float array2[]) {  //calculates the dot product of two arrays
  349.   return array1[0] * array2[0] + array1[1] * array2[1] + array1[2] * array2[2];
  350. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 6 小时前

回复

使用道具 举报

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

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail