极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2925|回复: 0

串联仿生毛毛虫的制作分享

[复制链接]
发表于 2022-12-21 11:18:13 | 显示全部楼层 |阅读模式
本帖最后由 机器谱 于 2022-12-21 11:20 编辑

1. 运动功能说明
该样机是一款纯关节串联的蠕虫形机器人,可以像虫子一样的上下蠕动前进,样子呈波浪状。



2. 结构说明
该样机由5个关节模组串联构成,结构比较单纯。




3. 运动功能实现
      本样机只需要让5个舵机按照一定的时序,做出波浪形摆动的动作,即可实现蠕动爬行。
舵机和关节模组的控制方法请参考如何驱动模拟舵机https://www.robotway.com/h-col-129.html】,以及舵机关节模组https://www.robotway.com/h-col-121.html】。

3.1 电子硬件      
在这个示例中,采用了以下硬件,请大家参考:
主控板Basra(兼容Arduino Uno)
扩展板Bigfish2.1
电池7.4V锂电池

3.2 编写程序
编程环境:Arduino 1.8.19
(1)实现尾部关节运动(Tail_Swing.ino),代码如下:
  1. /*------------------------------------------------------------------------------------

  2.   版权说明:Copyright 2022 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 机器谱 2022-9-14 https://www.robotway.com/

  6.   ------------------------------

  7.   实验功能: 实现机器毛毛虫尾部关节运动。

  8.   -----------------------------------------------------

  9.   实验接线:尾部关节模组的舵机接D8。                                    

  10. ------------------------------------------------------------------------------------*/

  11. #include <Servo.h>

  12. #include <MsTimer2.h>

  13. int servoPort[5]={8,3,11,7,4}; //毛毛虫的舵机连接顺序及接口号,从尾巴开始。

  14. Servo myServo[5];

  15. long timeCount;

  16. #define DELTATIME 10


  17. void setup() {         

  18.   Serial.begin(9600);      

  19.   for(int i = 0; i < 5; i++)

  20.     myServo[i].attach(servoPort[i]);   

  21.   MsTimer2::set(DELTATIME, Timer);

  22.   MsTimer2::start();

  23.   delay(100);

  24. }



  25. void loop() {

  26.   ServoMove(0,60,120,2000); //0号舵机在2000ms内从60°转到120°

  27. }


  28. void Timer() {

  29.   timeCount++;

  30. }


  31. void ServoMove(int which, int start, int finish, long t)

  32. {

  33.   static int a;

  34.   static long count = 0;

  35.   static int i = 0;

  36.   static boolean begin = true;


  37.   if(begin){

  38.     if( ( start - finish ) > 0 )

  39.       a = -1;

  40.     else

  41.       a = 1;


  42.     count = timeCount;

  43.     begin = false;

  44.   }

  45.   else{

  46.     if( ( timeCount - count ) < (t/DELTATIME) ){

  47.       if( ( timeCount - count ) > ( i * (t/DELTATIME) / (abs(start-finish)) ) ){

  48.         myServo[which].write( start + i * a );  

  49.         delay(1);

  50.         i++;     

  51.         Serial.println(start + i * a);

  52.       }

  53.     }

  54.     else{

  55.       i = 0;

  56.       begin = true;

  57.       count = 0;

  58.     }   

  59.   }

  60. }
复制代码

       此段程序之所以看起来那么复杂,是因为它搭建了一个程序框架,在这个框架中,大家可以通过改变参数,来决定哪个舵机运动,以及怎么运动,不需要重写整个程序。

(2)编写并烧录以下程序,它可以让毛毛虫全身的关节一起运动(Body_Swing.ino),代码如下:

  1. /*------------------------------------------------------------------------------------

  2.   版权说明:Copyright 2022 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 机器谱 2022-9-14 https://www.robotway.com/

  6.   ------------------------------

  7.   实验功能: 实现机器毛毛虫全身关节运动。

  8.   -----------------------------------------------------

  9.   实验接线:从尾巴开始,对应舵机接口依次D8、D3、D11、D7、D4。                                    

  10. ------------------------------------------------------------------------------------*/


  11. #include <Servo.h>

  12. #include <MsTimer2.h>


  13. int servoPort[5]={8,3,11,7,4};

  14. Servo myServo[5];

  15. long servoCount[5];

  16. boolean begin[5] = {true,true,true,true,true};

  17. boolean complete[5] = {false,false,false,false,false};

  18. int direct[5] = {1,1,1,1,1};

  19. int delta[5] = {0,0,0,0,0};


  20. long timeCount;

  21. #define DELTATIME 10


  22. int up = 30; //关节起始角度

  23. int down = 120; //关节终止角度

  24. int turnTime = 1000; //关节运动时间


  25. String inputString = "";         // a string to hold incoming data

  26. boolean stringComplete = false;   // whether the string is complete


  27. void setup() {         

  28.   Serial.begin(9600);      

  29.   for(int i = 0; i < 5; i++)

  30.     myServo[i].attach(servoPort[i]);   

  31.   MsTimer2::set(DELTATIME, Timer);

  32.   MsTimer2::start();

  33.   delay(100);

  34. }



  35. void loop() {

  36.   static int phase[5] = {0,0,0,0,0};


  37.   if (stringComplete) {

  38.     Serial.println(inputString);


  39.     up = inputString.substring(0,inputString.indexOf(',')).toInt();

  40.     inputString = inputString.substring(inputString.indexOf(',')+1,inputString.length());


  41.     down = inputString.substring(0,inputString.indexOf(',')).toInt();

  42.     turnTime = inputString.substring(inputString.indexOf(',')+1,inputString.length()).toInt();


  43.     Serial.println(up);

  44.     Serial.println(down);

  45.     Serial.println(turnTime);


  46.     inputString = "";

  47.     stringComplete = false;

  48.   }


  49.   if(phase[0] == 0)

  50.     if(ServoMove(0,up,down,turnTime))

  51.       phase[0] = 1;

  52.   if(phase[0] == 1)

  53.     if(ServoMove(0,down,up,turnTime))

  54.       phase[0] = 0;


  55.   if(phase[1] == 0)

  56.     if(ServoMove(1,down,up,turnTime))

  57.       phase[1] = 1;

  58.   if(phase[1] == 1)

  59.     if(ServoMove(1,up,down,turnTime))

  60.       phase[1] = 0;


  61.   if(phase[2] == 0)

  62.     if(ServoMove(2,up,down,turnTime))

  63.       phase[2] = 1;

  64.   if(phase[2] == 1)

  65.     if(ServoMove(2,down,up,turnTime))

  66.       phase[2] = 0;


  67.   if(phase[3] == 0)

  68.     if(ServoMove(3,down,up,turnTime))

  69.       phase[3] = 1;

  70.   if(phase[3] == 1)

  71.     if(ServoMove(3,up,down,turnTime))

  72.       phase[3] = 0;


  73.   if(phase[4] == 0)

  74.     if(ServoMove(4,up,down,turnTime))

  75.       phase[4] = 1;

  76.   if(phase[4] == 1)

  77.     if(ServoMove(4,down,up,turnTime))

  78.       phase[4] = 0;

  79. }


  80. void Timer() {

  81.   timeCount++;

  82. }


  83. void serialEvent() {

  84.   while (Serial.available()) {

  85.     char inChar = (char)Serial.read();

  86.     inputString += inChar;

  87.       if (inChar == '\n')

  88.       stringComplete = true;

  89.     }

  90. }


  91. boolean ServoMove(int which, int start, int finish, long t)

  92. {

  93.   if(begin[which]){

  94.     if( ( start - finish ) > 0 )

  95.       direct[which] = -1;

  96.     else

  97.       direct[which] = 1;


  98.     servoCount[which] = timeCount;

  99.     begin[which] = false;

  100.     complete[which] = false;

  101.   }

  102.   else{

  103.     if( ( timeCount - servoCount[which] ) < (t/DELTATIME) ){

  104.       if( ( timeCount - servoCount[which] ) > ( delta[which] * (t/DELTATIME) / (abs(start-finish)) ) ){

  105.         myServo[which].write( start + delta[which] * direct[which] );

  106.         delay(1);

  107.         delta[which]++;     

  108.         //Serial.println(start + i * a);

  109.       }

  110.     }

  111.     else{

  112.       delta[which] = 0;

  113.       begin[which] = true;

  114.       servoCount[which] = 0;

  115.       complete[which] = true;

  116.     }   

  117.   }


  118.   return (complete[which]);

  119. }
复制代码

烧录后,打开Serial Monitor,输入up,down,turnTime的值,可直接改变全部关节的运动参数,例如,输入50,100,2000。


       关节的运动状态会实时发生变化。其中50代表摆动的起始角度50°,100代表摆动的终止角度100°,2000代表运动持续时间是2000毫秒。


(2) 上一例程中,机器毛毛虫相邻关节的运动相位差为180°,根据样机的运动姿态分析,各个关节的运动相位差为90°左右的时候运动效应该比较好。
将相邻关节的运动相位差调整为90°(Worm_Go.ino),代码如下:
  1. /*------------------------------------------------------------------------------------

  2.   版权说明:Copyright 2022 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 机器谱 2022-9-14 https://www.robotway.com/

  6.   ------------------------------

  7.   实验功能: 实现机器毛毛虫向前蠕动爬行。

  8.   -----------------------------------------------------

  9.   实验接线:从尾巴开始,对应舵机接口依次D8、D3、D11、D7、D4。                                    

  10. ------------------------------------------------------------------------------------*/

  11. #include <Servo.h>

  12. #include <MsTimer2.h>


  13. int servoPort[5]={8,3,11,7,4};

  14. Servo myServo[5];

  15. long servoCount[5];

  16. boolean begin[5] = {true,true,true,true,true};

  17. boolean complete[5] = {false,false,false,false,false};

  18. int direct[5] = {1,1,1,1,1};

  19. int delta[5] = {0,0,0,0,0};


  20. long timeCount;

  21. #define DELTATIME 10


  22. int up = 30;

  23. int down = 120;

  24. int turnTime = 1000;


  25. String inputString = "";         // a string to hold incoming data

  26. boolean stringComplete = false;   // whether the string is complete


  27. void setup() {         

  28.   Serial.begin(9600);      

  29.   for(int i = 0; i < 5; i++)

  30.   myServo[i].attach(servoPort[i]);   

  31.   MsTimer2::set(DELTATIME, Timer);

  32.   MsTimer2::start();

  33.   delay(100);

  34. }


  35. void loop() {

  36. static int phase[5] = {0,0,0,0,0};


  37. if (stringComplete) {

  38. Serial.println(inputString);


  39. up = inputString.substring(0,inputString.indexOf(',')).toInt();

  40. inputString = inputString.substring(inputString.indexOf(',')+1,inputString.length());


  41. down = inputString.substring(0,inputString.indexOf(',')).toInt();

  42. turnTime = inputString.substring(inputString.indexOf(',')+1,inputString.length()).toInt();


  43. Serial.println(up);

  44. Serial.println(down);

  45. Serial.println(turnTime);


  46. inputString = "";

  47. stringComplete = false;

  48. }


  49. if(phase[0] == 0)

  50. if(ServoMove(0,up,down,turnTime))

  51. phase[0] = 1;

  52. if(phase[0] == 1)

  53. if(ServoMove(0,down,up,turnTime))

  54. phase[0] = 0;


  55. if(servoCount[0]>0 && (timeCount - servoCount[0])>(turnTime/(4*DELTATIME))){

  56. if(phase[1] == 0)

  57. if(ServoMove(1,up,down,turnTime))

  58. phase[1] = 1;

  59. if(phase[1] == 1)

  60. if(ServoMove(1,down,up,turnTime))

  61. phase[1] = 0;

  62. }


  63. if(servoCount[1]>0 && (timeCount - servoCount[1])>(turnTime/(4*DELTATIME))){

  64. if(phase[2] == 0)

  65. if(ServoMove(2,up,down,turnTime))

  66. phase[2] = 1;

  67. if(phase[2] == 1)

  68. if(ServoMove(2,down,up,turnTime))

  69. phase[2] = 0;

  70. }


  71. if(servoCount[2]>0 && (timeCount - servoCount[2])>(turnTime/(4*DELTATIME))){

  72. if(phase[3] == 0)

  73. if(ServoMove(3,up,down,turnTime))

  74. phase[3] = 1;

  75. if(phase[3] == 1)

  76. if(ServoMove(3,down,up,turnTime))

  77. phase[3] = 0;

  78. }


  79. if(servoCount[3]>0 && (timeCount - servoCount[3])>(turnTime/(4*DELTATIME))){

  80. if(phase[4] == 0)

  81. if(ServoMove(4,up,down,turnTime))

  82. phase[4] = 1;

  83. if(phase[4] == 1)

  84. if(ServoMove(4,down,up,turnTime))

  85. phase[4] = 0;

  86. }

  87. }


  88. void Timer() {

  89. timeCount++;

  90. }


  91. void serialEvent() {

  92. while (Serial.available()) {

  93. char inChar = (char)Serial.read();

  94. inputString += inChar;

  95.     if (inChar == '\n')

  96. stringComplete = true;

  97.   }

  98. }


  99. boolean ServoMove(int which, int start, int finish, long t)

  100. {

  101. if(begin[which]){

  102. if( ( start - finish ) > 0 )

  103. direct[which] = -1;

  104. else

  105. direct[which] = 1;


  106. servoCount[which] = timeCount;

  107. begin[which] = false;

  108. complete[which] = false;

  109. }

  110. else{

  111. if( ( timeCount - servoCount[which] ) < (t/DELTATIME) ){

  112. if( ( timeCount - servoCount[which] ) > ( delta[which] * (t/DELTATIME) / (abs(start-finish)) ) ){

  113. myServo[which].write( start + delta[which] * direct[which] );

  114. delay(1);

  115. delta[which]++;

  116. //Serial.println(start + i * a);

  117. }

  118. }

  119. else{

  120. delta[which] = 0;

  121. begin[which] = true;

  122. //servoCount[which] = 0;

  123. complete[which] = true;

  124. }

  125. }


  126. return (complete[which]);

  127. }
复制代码

       烧录后,打开Serial Monitor,输入up,down,turnTime的值,并实时观察运动变化。你可以通过这种方法调整机器人的运动姿态,直至对爬行效果满意为止。

4. 扩展样机
本样机没有设计左右摆动的结构,因此不能左右转向,有兴趣的朋友可以尝试为其加上左右摆动的结构,让它的运动方式更加丰富。

5. 资料下载
资料内容:
①样机3D文件
②样机例程源代码

资料下载链接https://www.robotway.com/h-col-149.html





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

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

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

Archiver|联系我们|极客工坊

GMT+8, 2024-4-19 03:33 , Processed in 0.038198 second(s), 18 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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