本帖最后由 机器谱 于 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),代码如下: - /*------------------------------------------------------------------------------------
- 版权说明:Copyright 2022 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved.
- Distributed under MIT license.See file LICENSE for detail or copy at
- https://opensource.org/licenses/MIT
- by 机器谱 2022-9-14 https://www.robotway.com/
- ------------------------------
- 实验功能: 实现机器毛毛虫尾部关节运动。
- -----------------------------------------------------
- 实验接线:尾部关节模组的舵机接D8。
- ------------------------------------------------------------------------------------*/
- #include <Servo.h>
- #include <MsTimer2.h>
- int servoPort[5]={8,3,11,7,4}; //毛毛虫的舵机连接顺序及接口号,从尾巴开始。
- Servo myServo[5];
- long timeCount;
- #define DELTATIME 10
- void setup() {
- Serial.begin(9600);
- for(int i = 0; i < 5; i++)
- myServo[i].attach(servoPort[i]);
- MsTimer2::set(DELTATIME, Timer);
- MsTimer2::start();
- delay(100);
- }
- void loop() {
- ServoMove(0,60,120,2000); //0号舵机在2000ms内从60°转到120°
- }
- void Timer() {
- timeCount++;
- }
- void ServoMove(int which, int start, int finish, long t)
- {
- static int a;
- static long count = 0;
- static int i = 0;
- static boolean begin = true;
- if(begin){
- if( ( start - finish ) > 0 )
- a = -1;
- else
- a = 1;
- count = timeCount;
- begin = false;
- }
- else{
- if( ( timeCount - count ) < (t/DELTATIME) ){
- if( ( timeCount - count ) > ( i * (t/DELTATIME) / (abs(start-finish)) ) ){
- myServo[which].write( start + i * a );
- delay(1);
- i++;
- Serial.println(start + i * a);
- }
- }
- else{
- i = 0;
- begin = true;
- count = 0;
- }
- }
- }
复制代码
此段程序之所以看起来那么复杂,是因为它搭建了一个程序框架,在这个框架中,大家可以通过改变参数,来决定哪个舵机运动,以及怎么运动,不需要重写整个程序。
(2)编写并烧录以下程序,它可以让毛毛虫全身的关节一起运动(Body_Swing.ino),代码如下: - /*------------------------------------------------------------------------------------
- 版权说明:Copyright 2022 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved.
- Distributed under MIT license.See file LICENSE for detail or copy at
- https://opensource.org/licenses/MIT
- by 机器谱 2022-9-14 https://www.robotway.com/
- ------------------------------
- 实验功能: 实现机器毛毛虫全身关节运动。
- -----------------------------------------------------
- 实验接线:从尾巴开始,对应舵机接口依次D8、D3、D11、D7、D4。
- ------------------------------------------------------------------------------------*/
- #include <Servo.h>
- #include <MsTimer2.h>
- int servoPort[5]={8,3,11,7,4};
- Servo myServo[5];
- long servoCount[5];
- boolean begin[5] = {true,true,true,true,true};
- boolean complete[5] = {false,false,false,false,false};
- int direct[5] = {1,1,1,1,1};
- int delta[5] = {0,0,0,0,0};
- long timeCount;
- #define DELTATIME 10
- int up = 30; //关节起始角度
- int down = 120; //关节终止角度
- int turnTime = 1000; //关节运动时间
- String inputString = ""; // a string to hold incoming data
- boolean stringComplete = false; // whether the string is complete
- void setup() {
- Serial.begin(9600);
- for(int i = 0; i < 5; i++)
- myServo[i].attach(servoPort[i]);
- MsTimer2::set(DELTATIME, Timer);
- MsTimer2::start();
- delay(100);
- }
- void loop() {
- static int phase[5] = {0,0,0,0,0};
- if (stringComplete) {
- Serial.println(inputString);
- up = inputString.substring(0,inputString.indexOf(',')).toInt();
- inputString = inputString.substring(inputString.indexOf(',')+1,inputString.length());
- down = inputString.substring(0,inputString.indexOf(',')).toInt();
- turnTime = inputString.substring(inputString.indexOf(',')+1,inputString.length()).toInt();
- Serial.println(up);
- Serial.println(down);
- Serial.println(turnTime);
- inputString = "";
- stringComplete = false;
- }
- if(phase[0] == 0)
- if(ServoMove(0,up,down,turnTime))
- phase[0] = 1;
- if(phase[0] == 1)
- if(ServoMove(0,down,up,turnTime))
- phase[0] = 0;
- if(phase[1] == 0)
- if(ServoMove(1,down,up,turnTime))
- phase[1] = 1;
- if(phase[1] == 1)
- if(ServoMove(1,up,down,turnTime))
- phase[1] = 0;
- if(phase[2] == 0)
- if(ServoMove(2,up,down,turnTime))
- phase[2] = 1;
- if(phase[2] == 1)
- if(ServoMove(2,down,up,turnTime))
- phase[2] = 0;
- if(phase[3] == 0)
- if(ServoMove(3,down,up,turnTime))
- phase[3] = 1;
- if(phase[3] == 1)
- if(ServoMove(3,up,down,turnTime))
- phase[3] = 0;
- if(phase[4] == 0)
- if(ServoMove(4,up,down,turnTime))
- phase[4] = 1;
- if(phase[4] == 1)
- if(ServoMove(4,down,up,turnTime))
- phase[4] = 0;
- }
- void Timer() {
- timeCount++;
- }
- void serialEvent() {
- while (Serial.available()) {
- char inChar = (char)Serial.read();
- inputString += inChar;
- if (inChar == '\n')
- stringComplete = true;
- }
- }
- boolean ServoMove(int which, int start, int finish, long t)
- {
- if(begin[which]){
- if( ( start - finish ) > 0 )
- direct[which] = -1;
- else
- direct[which] = 1;
- servoCount[which] = timeCount;
- begin[which] = false;
- complete[which] = false;
- }
- else{
- if( ( timeCount - servoCount[which] ) < (t/DELTATIME) ){
- if( ( timeCount - servoCount[which] ) > ( delta[which] * (t/DELTATIME) / (abs(start-finish)) ) ){
- myServo[which].write( start + delta[which] * direct[which] );
- delay(1);
- delta[which]++;
- //Serial.println(start + i * a);
- }
- }
- else{
- delta[which] = 0;
- begin[which] = true;
- servoCount[which] = 0;
- complete[which] = true;
- }
- }
- return (complete[which]);
- }
复制代码
烧录后,打开Serial Monitor,输入up,down,turnTime的值,可直接改变全部关节的运动参数,例如,输入50,100,2000。
关节的运动状态会实时发生变化。其中50代表摆动的起始角度50°,100代表摆动的终止角度100°,2000代表运动持续时间是2000毫秒。
(2) 上一例程中,机器毛毛虫相邻关节的运动相位差为180°,根据样机的运动姿态分析,各个关节的运动相位差为90°左右的时候运动效应该比较好。 将相邻关节的运动相位差调整为90°(Worm_Go.ino),代码如下: - /*------------------------------------------------------------------------------------
- 版权说明:Copyright 2022 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved.
- Distributed under MIT license.See file LICENSE for detail or copy at
- https://opensource.org/licenses/MIT
- by 机器谱 2022-9-14 https://www.robotway.com/
- ------------------------------
- 实验功能: 实现机器毛毛虫向前蠕动爬行。
- -----------------------------------------------------
- 实验接线:从尾巴开始,对应舵机接口依次D8、D3、D11、D7、D4。
- ------------------------------------------------------------------------------------*/
- #include <Servo.h>
- #include <MsTimer2.h>
- int servoPort[5]={8,3,11,7,4};
- Servo myServo[5];
- long servoCount[5];
- boolean begin[5] = {true,true,true,true,true};
- boolean complete[5] = {false,false,false,false,false};
- int direct[5] = {1,1,1,1,1};
- int delta[5] = {0,0,0,0,0};
- long timeCount;
- #define DELTATIME 10
- int up = 30;
- int down = 120;
- int turnTime = 1000;
- String inputString = ""; // a string to hold incoming data
- boolean stringComplete = false; // whether the string is complete
- void setup() {
- Serial.begin(9600);
- for(int i = 0; i < 5; i++)
- myServo[i].attach(servoPort[i]);
- MsTimer2::set(DELTATIME, Timer);
- MsTimer2::start();
- delay(100);
- }
- void loop() {
- static int phase[5] = {0,0,0,0,0};
- if (stringComplete) {
- Serial.println(inputString);
- up = inputString.substring(0,inputString.indexOf(',')).toInt();
- inputString = inputString.substring(inputString.indexOf(',')+1,inputString.length());
- down = inputString.substring(0,inputString.indexOf(',')).toInt();
- turnTime = inputString.substring(inputString.indexOf(',')+1,inputString.length()).toInt();
- Serial.println(up);
- Serial.println(down);
- Serial.println(turnTime);
- inputString = "";
- stringComplete = false;
- }
- if(phase[0] == 0)
- if(ServoMove(0,up,down,turnTime))
- phase[0] = 1;
- if(phase[0] == 1)
- if(ServoMove(0,down,up,turnTime))
- phase[0] = 0;
- if(servoCount[0]>0 && (timeCount - servoCount[0])>(turnTime/(4*DELTATIME))){
- if(phase[1] == 0)
- if(ServoMove(1,up,down,turnTime))
- phase[1] = 1;
- if(phase[1] == 1)
- if(ServoMove(1,down,up,turnTime))
- phase[1] = 0;
- }
- if(servoCount[1]>0 && (timeCount - servoCount[1])>(turnTime/(4*DELTATIME))){
- if(phase[2] == 0)
- if(ServoMove(2,up,down,turnTime))
- phase[2] = 1;
- if(phase[2] == 1)
- if(ServoMove(2,down,up,turnTime))
- phase[2] = 0;
- }
- if(servoCount[2]>0 && (timeCount - servoCount[2])>(turnTime/(4*DELTATIME))){
- if(phase[3] == 0)
- if(ServoMove(3,up,down,turnTime))
- phase[3] = 1;
- if(phase[3] == 1)
- if(ServoMove(3,down,up,turnTime))
- phase[3] = 0;
- }
- if(servoCount[3]>0 && (timeCount - servoCount[3])>(turnTime/(4*DELTATIME))){
- if(phase[4] == 0)
- if(ServoMove(4,up,down,turnTime))
- phase[4] = 1;
- if(phase[4] == 1)
- if(ServoMove(4,down,up,turnTime))
- phase[4] = 0;
- }
- }
- void Timer() {
- timeCount++;
- }
- void serialEvent() {
- while (Serial.available()) {
- char inChar = (char)Serial.read();
- inputString += inChar;
- if (inChar == '\n')
- stringComplete = true;
- }
- }
- boolean ServoMove(int which, int start, int finish, long t)
- {
- if(begin[which]){
- if( ( start - finish ) > 0 )
- direct[which] = -1;
- else
- direct[which] = 1;
- servoCount[which] = timeCount;
- begin[which] = false;
- complete[which] = false;
- }
- else{
- if( ( timeCount - servoCount[which] ) < (t/DELTATIME) ){
- if( ( timeCount - servoCount[which] ) > ( delta[which] * (t/DELTATIME) / (abs(start-finish)) ) ){
- myServo[which].write( start + delta[which] * direct[which] );
- delay(1);
- delta[which]++;
- //Serial.println(start + i * a);
- }
- }
- else{
- delta[which] = 0;
- begin[which] = true;
- //servoCount[which] = 0;
- complete[which] = true;
- }
- }
- return (complete[which]);
- }
复制代码
烧录后,打开Serial Monitor,输入up,down,turnTime的值,并实时观察运动变化。你可以通过这种方法调整机器人的运动姿态,直至对爬行效果满意为止。
4. 扩展样机 本样机没有设计左右摆动的结构,因此不能左右转向,有兴趣的朋友可以尝试为其加上左右摆动的结构,让它的运动方式更加丰富。
5. 资料下载
资料内容:
①样机3D文件
②样机例程源代码
资料下载链接https://www.robotway.com/h-col-149.html
|