极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2721|回复: 0

3自由度并联绘图机器人实现写字功能

[复制链接]
发表于 2023-4-19 09:28:39 | 显示全部楼层 |阅读模式
本帖最后由 机器谱 于 2023-4-19 09:28 编辑

1. 功能说明
     本文示例将实现R305样机3自由度并联绘图机器人写字的功能。
2. 电子硬件
     在这个示例中,采用了以下硬件,请大家参考:

主控板
Basra主控板(兼容Arduino Uno)
扩展板
Bigfish2.1扩展板
电池
7.4V锂电池

3. 功能实现
3.1建立坐标系

       我们需要先对3自由度并联绘图机器人进行极限位置调节,下图中为左极限位置,右极限位置与其对称。3自由度并联绘图机器人绘图主要由图中所示两个伺服电机控制。


3.2硬件连接
     ① 左侧舵机连接Bigfish扩展板D4号引脚
     ② 右侧舵机连接Bigfish扩展板D7号引脚
     ③ 抬笔舵机连接到Bigfish扩展板D11号引脚


3.3 示例程序
编程环境:
Arduino 1.8.19
       将参考例程(_1_servoWrite.ino)下载到主控板,调试时可以先只安装舵机输出头,或者安装输出头及L1连杆,运行观察舵机转动状况。
  1. /*------------------------------------------------------------------------------------

  2.   版权说明:Copyright 2023 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved.

  3.            Distributed under MIT license.See file LICENSE for detail or copy at

  4.            https://opensource.org/licenses/MIT

  5.            by 机器谱 2023-03-31 https://www.robotway.com/

  6.   ------------------------------*/

  7. #define SERVOLEFTNULL 500      //左侧舵机转动到0度的值

  8. #define SERVORIGHTNULL 500     //右侧舵机转动到0度的值


  9. #define SERVOFAKTORLEFT 603    //左侧舵机转动到0度右侧舵机转动到90度时的值

  10. #define SERVOFAKTORRIGHT 610   //左侧舵机转动到90度右侧舵机转动到180度时的值


  11. #define LIFT0 2000             //落笔写字时舵机转动的值

  12. #define LIFT1 1800             //一笔写完换笔时舵机转动的值

  13. #define LIFT2 1400             //初始及完成写字后抬笔时舵机的值


  14. #define SERVOPINLEFT 4         //定义一些舵机引脚

  15. #define SERVOPINRIGHT 7

  16. #define SERVOPINLIFT 11


  17. #define LIFTSPEED 1500         //定义抬笔落笔时舵机转动的速度


  18. #define L1 90                  //定义与舵机相连杆的长度 mm  

  19. #define L2 117.6               //定义与舵机相连杆的端点铰接处中心到笔中心的距离 mm

  20. #define L3 31.6                //定义中间杆顶端铰接处中心到笔的距离 mm


  21. #define X1 40.0                //定义左侧舵机中心轴到原点在X方向上的距离

  22. #define Y1 -42                 //定义左侧舵机中心轴到X轴的垂直距离

  23. #define X2 111.4               //定义右侧舵机中心轴到原点在X方向上的距离

  24. #define Y2 -42                 //定义右侧舵机中心轴到到X轴的垂直距离


  25. //坐标系建立第一象限,X轴方向为140mm,Y轴方向为120mm,选取坐标点时Y值建议大于70

  26. int coAry[10][10][2] = {         


  27.               //汉字   王

  28.               {{25,110},{0,0},{51,110},{1,1}},

  29.               {{26,98},{0,0},{49,98},{1,1}},

  30.               {{25,84},{0,0},{51,84},{1,1}},

  31.               {{37,110},{0,0},{37,84},{1,1}},


  32.               //汉字   云

  33.               {{61,110},{0,0},{81,110},{1,1}},

  34.               {{58,100},{0,0},{85,100},{1,1}},

  35.               {{68,100},{0,0},{62,85},{86,85},{1,1}},

  36.               {{80,96},{0,0},{91,82},{1,1}},

  37.             

  38.               //汉字   飞

  39.               {{99,110},{0,0},{114,110},{114,98},{115,90},{115,86},{118,84},{121,82},{126,88},{1,1}},

  40.               {{121,103},{0,0},{116,98},{122,94},{1,1}}

  41.                         

  42. };


  43. #include <Servo.h>


  44. int servoLift = LIFT2;


  45. Servo servo1;

  46. Servo servo2;

  47. Servo servo3;


  48. volatile double lastX = 57;   //笔初始坐标值

  49. volatile double lastY = 93;


  50. void setup() {

  51.   Serial.begin(9600);        //开启串口通信



  52.   /*servo1.attach(SERVOPINLEFT);

  53.   servo2.attach(SERVOPINRIGHT);

  54.   servo3.attach(SERVOPINLIFT);

  55.   */



  56. }


  57. void loop() {



  58.   Serial.println("begin");



  59.   if(1)

  60.   {  

  61.    

  62.     if(!servo1.attached()) servo1.attach(SERVOPINLEFT);

  63.     if(!servo2.attached()) servo2.attach(SERVOPINRIGHT);

  64.     if(!servo3.attached()) servo3.attach(SERVOPINLIFT);

  65.    

  66.     lift(2);

  67.     //delay(1000);


  68.     //汉字坐标处理

  69.     for(int i=0;i<10;i++)

  70.     {

  71.       for(int j=0;j<10;j++)

  72.       {

  73.         int x = coAry[i][j][0];

  74.         int y = coAry[i][j][1];

  75.       

  76.         //Serial.println(x);

  77.         //Serial.println(y);

  78.       

  79.         if(x == 0 && y == 0)

  80.         {

  81.           lift(0);

  82.           continue;

  83.         }

  84.         else if(x == 1 && y == 1)

  85.         {

  86.           lift(1);

  87.           break;

  88.         }

  89.       

  90.         drawTo(x,y);

  91.       

  92.        //delay(10);

  93.       

  94.       }

  95.     }

  96.    


  97.     /*

  98.     //摆臂测试坐标,左侧舵机转动到0度,右侧舵机转动到90度;左侧舵机转动到90度,右侧舵机转动到180度,依次循环

  99.     drawTo(0,120.0);

  100.     delay(1000);

  101.    

  102.     Serial.println("----------------------");

  103.    

  104.     drawTo(140.0, 120.0);

  105.     delay(1000);

  106.     ///////

  107.     */

  108.    

  109.     lift(2);

  110.    

  111.     servo1.detach();

  112.     servo2.detach();

  113.     servo3.detach();   

  114.    

  115.    

  116.     Serial.println("end");

  117.    

  118.   }



  119. }


  120. //抬笔舵机转动函数,三个动作,落笔、换笔、起笔, 0 ,1, 2

  121. void lift(char lift)

  122. {

  123.   switch(lift)

  124.   {

  125.     case 0:

  126.         Serial.println("lift0");

  127.         if(servoLift >= LIFT0)

  128.         {

  129.           while(servoLift >= LIFT0)

  130.           {

  131.             servoLift--;

  132.             servo3.writeMicroseconds(servoLift);

  133.             delayMicroseconds(LIFTSPEED);

  134.           }

  135.         }

  136.         else

  137.         {

  138.            while(servoLift <= LIFT0)

  139.            {

  140.              servoLift++;

  141.              servo3.writeMicroseconds(servoLift);

  142.              delayMicroseconds(LIFTSPEED);

  143.            }

  144.         }

  145.     break;

  146.     case 1:

  147.         Serial.println("lift1");

  148.         if(servoLift >= LIFT1)

  149.         {

  150.           while(servoLift >= LIFT1)

  151.           {

  152.             servoLift--;

  153.             servo3.writeMicroseconds(servoLift);

  154.             delayMicroseconds(LIFTSPEED);

  155.           }

  156.         }

  157.         else

  158.         {

  159.           while(servoLift <= LIFT1)

  160.           {

  161.             servoLift++;

  162.             servo3.writeMicroseconds(servoLift);

  163.             delayMicroseconds(LIFTSPEED);

  164.           }

  165.         }

  166.     break;

  167.     case 2:

  168.         Serial.println("lift2");

  169.         if(servoLift >= LIFT2)

  170.         {

  171.           while(servoLift >= LIFT2)

  172.           {

  173.             servoLift--;

  174.             servo3.writeMicroseconds(servoLift);

  175.             delayMicroseconds(LIFTSPEED);

  176.           }

  177.         }

  178.         else

  179.         {

  180.           while(servoLift <= LIFT2)

  181.           {

  182.             servoLift++;

  183.             servo3.writeMicroseconds(servoLift);

  184.             delayMicroseconds(LIFTSPEED);

  185.           }

  186.         }

  187.     break;

  188.     default:break;

  189.   }

  190. }


  191. //笔移动函数,参数为点坐标值,计算两点坐标距离来控制笔移动

  192. void drawTo(double pX, double pY) {

  193.   double dx, dy, c;

  194.   int i;



  195.   Serial.println(pX);

  196.   Serial.println(pY);


  197.   // dx dy of new point

  198.   dx = pX - lastX;

  199.   dy = pY - lastY;

  200.   //path lenght in mm, times 4 equals 4 steps per mm

  201.   c = floor(1 * sqrt(dx * dx + dy * dy));


  202.   if (c < 1) c = 1;


  203.   for (i = 0; i <= c; i++) {

  204.     // draw line point by point

  205.     set_XY(lastX + (i * dx / c), lastY + (i * dy / c));


  206.   }


  207.   lastX = pX;

  208.   lastY = pY;

  209. }



  210. double return_angle(double a, double b, double c) {

  211.   // cosine rule for angle between c and a

  212.   return acos((a * a + c * c - b * b) / (2 * a * c));

  213. }



  214. //用各种三角函数把位置坐标换算成舵机的角度,如何计算,请参考

  215. //http://www.thingiverse.com/thing:248009/

  216. void set_XY(double Tx, double Ty)

  217. {

  218.   delay(1);

  219.   double dx, dy, c, a1, a2, Hx, Hy;


  220.   // calculate triangle between pen, servoLeft and arm joint

  221.   // cartesian dx/dy

  222.   dx = Tx - X1;

  223.   dy = Ty - Y1;


  224.   // polar lemgth (c) and angle (a1)

  225.   c = sqrt(dx * dx + dy * dy); //

  226.   a1 = atan2(dy, dx); //

  227.   a2 = return_angle(L1, L2, c);



  228.   //Serial.println(floor(((M_PI-a1 - a2) * SERVOFAKTORLEFT) + SERVOLEFTNULL));


  229.   servo1.writeMicroseconds(floor(((M_PI-a1 - a2) * SERVOFAKTORLEFT) + SERVOLEFTNULL));


  230.   // calculate joinr arm point for triangle of the right servo arm

  231.   a2 = return_angle(L2, L1, c);

  232.   Hx = Tx + L3 * cos((a1 - a2 + 0.621) + M_PI); //36,5掳

  233.   Hy = Ty + L3 * sin((a1 - a2 + 0.621) + M_PI);


  234.   // calculate triangle between pen joint, servoRight and arm joint

  235.   dx = Hx - X2;

  236.   dy = Hy - Y2;


  237.   c = sqrt(dx * dx + dy * dy);

  238.   a1 = atan2(dy, dx);

  239.   a2 = return_angle(L1, (L2 - L3), c);



  240.   //Serial.println(floor(((M_PI - a1 + a2) * SERVOFAKTORRIGHT) + SERVORIGHTNULL));


  241.   servo2.writeMicroseconds(floor(((M_PI - a1 + a2) * SERVOFAKTORRIGHT) + SERVORIGHTNULL));


  242. }
复制代码

       两个舵机输出头会保持一个水平的同时另一个垂直,如上述演示视频中所示,如果差距较大,可拆下输出头进行调节,如果比较接近,可以修改程序中前四行参数的值:

       SERVOFAKTORLEFT 左侧舵机水平、右侧舵机垂直位置,数值增加顺时针调整;        SERVOFAKTORRIGHT 右侧舵机水平、左侧舵机垂直位置,数值减小逆时针调整;

       SERVOLEFTNULL 左侧舵机0°位置,可不调节;

       SERVORIGHTNULL 右侧舵机0°位置,可不调节。

       当调试完成后可以安装其余连杆,此测试例程中所调节的是笔架在绘图区域中的两端位置,即左侧点(0, 120),右侧点(140, 120)。

       根据上述步骤中所调节的四个参数修改_1_servoWrite.ino例程中对应参数的值。然后将该例程下载到主控板中,运行程序即可书写汉字。程序中所存储的汉字为“王云飞”坐标,如果要书写其它字体,可按照上述3.1步骤所示建立相应坐标系,将各笔画记录到程序中即可。

       坐标系可以按如下格式建立:


       根据上面图表中可知,只要记录每一笔画的坐标值到程序中即可,字体的坐标值在程序中将以数组的形式记录。如下图所示:


       以王字的第一笔:横来说,{25,110}表示横的第一个点坐标,数组中{0,0}表示当x=0&&y=0时落笔,每一笔的第一个坐标后要添加{0,0},然后{51,110}为横的第二个点坐标,因为之前笔已经落下,所以此处将绘制此横;然后{1,1}表示当x=1&&y=1时抬笔,此时一笔写完,将执行下一行坐标。每一笔坐标用大括号括起来,因此{{25,110},{0,0},{51,110},{1,1}},表示王字的第一笔。如要写其它字体,按以上所示建立坐标系,获取坐标数据,按格式记录到程序中即可,并按笔画数量修改数组大小。

4. 资料下载
资料内容:
​①写字-例程源代码
​②写字-样机3D文件
资料下载地址:https://www.robotway.com/h-col-205.html

想了解更多机器人开源项目资料请关注 机器谱网站 https://www.robotway.com

回复

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-28 18:17 , Processed in 0.035930 second(s), 17 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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