R111样机是一款拥有12个自由度的串联仿生六足机器人。本文示例所实现的功能为:R111样机12自由度六足机器人原地舞蹈。
R111样机(R111b)由6个2自由度连杆仿生腿结构组成,2自由度连杆仿生腿两两对称组合,分别构成机器昆虫的三对足。三对足之间由零件结合固定,从而构成机器昆虫的本体,呈现出非常规整的模块化结构。
该2自由度串联结构由舵机1和舵机2驱动,其中舵机1实现腿部前后摆动,舵机2实现腿部的上下抬伸。其中抬伸通过一个平行四连杆ABCD作为传动结构以增加腿部的行程和增强腿部运动的稳定性。
在这个示例中,我们采用了以下硬件,请大家参考:
主控板 | Basra主控板(兼容Arduino Uno) |
扩展板 | SH-SR舵机扩展板 |
舵机 | 标准舵机 |
电池 | 7.4V锂电池 |
电路连接说明:
因为12自由度六足机器人结构上装有12个舵机,所以将采用 SH-SR舵机扩展板 。
舵机接线顺序:1、3; 4、 5; 6、 8;11、13;15、 21;24、26。
上位机:Controller 1.0
下位机编程环境:Arduino 1.8.19
① 将Controller下位机程序servo.ino直接下载到主控板。这段代码供Controller上位机与主控板通信,并允许调试舵机。代码如下:
/*------------------------------------------------------------------------------------版权说明:Copyright 2023 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved.Distributed under MIT license.See file LICENSE for detail or copy athttps://opensource.org/licenses/MITby 机器谱 2023-02-16 https://www.robotway.com/------------------------------*/#include #include int data_array[2] = {0,0}; //servo_pin: data_array[0], servo_value: data_array[1];String data = "";boolean dataComplete = false;void setup() {Serial.begin(9600);Tlc.init(0);tlc_initServos();delay(1000);}void loop() {while(Serial.available()){int B_flag, P_flag, T_flag;data = Serial.readStringUntil('\n');data.trim();for(int i=0;i
下载完成后,保持主控板和电脑的USB连接,并打开主控板电源,以便利用上位机进行调试。
② 双击打开Controller 1.0b.exe:
③ 点击联机,选择对应的端口号,波特率设置为9600,如下图所示:
控制块内容说明如下:
④ 此时上位机软件已经与下位机建立通信连接,我们拖动舵机引脚号对应的滑块即可对舵机进行角度调节。下图为软件中各个按钮说明:
⑤ 设置面板说明:点击左上角设置-设置面板,即可打开(如下图)。点击对应序号的复选框即可控制软件主界面中相应控制块的显示和隐藏,以及全部显示和全部隐藏等;点击重置按钮,可将各个控制块恢复初始位置;点击确定可关闭设置界面。
⑥ 控制块任意位置拖动:如下图,可拖动至需要的形状。
注:每次重启会恢复初始位置。
调试好角度后,将角度参数复制到下面的12自由度六足机器人原地舞蹈的参考例程(robot_dance.ino)之中,并下载到主控板:
/*------------------------------------------------------------------------------------版权说明:Copyright 2023 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved.Distributed under MIT license.See file LICENSE for detail or copy athttps://opensource.org/licenses/MITby 机器谱 2023-02-16 https://www.robotway.com/------------------------------*/#include #include #include "Config.h"#include #include int count_input = 0;boolean _b = false;/**************+++++++++++动作组数组,请将转换后的动作组数据粘贴到相应的动作组中+++++++***************************/const PROGMEM int actionInit[] = {1090, 1790, 1220, 980, 650, 1800, 1020, 1330, 520, 1155, 1260, 2020,1090, 1790, 1220, 980, 650, 1800, 1020, 1330, 520, 1155, 1260, 2020,};const PROGMEM int actionLeft[] = {};const PROGMEM int actionRight[] = {};const PROGMEM int actionBack[] = {};const PROGMEM int actionDance[] = {};const PROGMEM int actionDance[] = {1660, 1230, 1220, 980, 1280, 1190, 1020, 1330, 1090, 1155, 1260, 1540,1090,1790,1220,980,650,1800,1020,1330,520,1155,1260,2020,1490,1590,1220,980,850,1400,1020,1330,1320,1155,1260,2020,1490,1590,1220,980,850,1400,1020,1330,1320,1155,1700,1700,1490,1590,1220,980,850,1400,1020,1330,1320,1155,1700,2020,1090,1790,1220,980,650,1800,1020,1330,520,1155,1260,2020,1490,1590,1220,980,850,1400,1020,1330,520,1155,1260,1220,1490,1590,1220,980,850,1400,1020,1330,800,700,1260,1220,1490,1590,1220,980,850,1400,1020,1330,520,700,1260,1220,1090,1790,1220,980,650,1800,1020,1330,520,1155,1260,2020,1670,1190,1220,980,1370,1100,1020,1330,1100,1155,1260,1430,1090,1190,1220,980,1370,1800,620,1730,1100,1155,1260,1430,1090,1190,1220,980,1370,1100,620,1730,1100,1155,1260,1430,1670,1190,1220,980,1370,1800,620,1730,1100,1155,1260,1430,1090,1190,1220,980,1370,1100,620,1730,1100,1155,1260,1430,1090,1190,1220,980,1370,1800,700,1570,1100,1155,1260,1430,1670,1190,1220,980,1370,1100,700,1570,1100,1155,1260,1430,1670,1190,1220,980,1370,1100,700,1570,520,520,1930,2020,1670,1190,1220,980,1370,1100,700,1570,800,520,1930,1700,1670,1190,1220,980,1370,1100,700,1570,520,520,1930,2020,1670,1190,1220,980,1370,1100,700,1570,800,520,1930,1700,1670,1190,1220,980,1370,1100,700,1570,1100,1155,1260,1430,1670,1190,1220,980,1370,1100,1020,1330,1100,1155,1260,1430,1670,1190,1220,980,1370,1100,1020,1330,1100,1155,1260,1430,1670,1190,1220,980,900,1590,1020,1330,720,1155,1260,1430,1320,1540,1220,980,1370,1100,1020,1330,1100,1155,1260,1830,1670,1190,1220,980,1370,1100,1020,1330,1100,1155,1260,1430,1320,1410,1220,980,1370,1100,1020,1330,1100,1155,1260,1950,1300,1670,1220,980,1370,1100,1020,1330,1100,1155,1260,1600,1670,1190,1220,980,940,1540,1020,1330,920,1155,1260,1430,1670,1190,1220,980,1235,1480,1020,1330,580,1155,1260,1430,1670,1190,1220,980,940,1540,1020,1330,920,1155,1260,1430,1670,1190,990,1210,940,1540,1140,1100,920,1400,1060,1430,1300,1670,990,1210,1370,1100,1140,1100,1100,1400,1060,1600,1320,1540,990,1210,1370,1100,1140,1100,1100,1400,1060,1830,1670,1190,990,1210,1370,1100,1140,1100,1100,1400,1060,1430,1670,1190,990,1210,1370,1100,1140,1100,1100,1400,1060,1430,1670,1190,1280,920,1370,1100,920,1410,1100,1030,1410,1430,1670,1190,990,1210,1370,1100,1140,1100,1100,1400,1060,1430,1670,1190,1280,920,1370,1100,920,1410,1100,1030,1410,1430,1670,1190,1220,980,1370,1100,1020,1330,1100,1155,1260,1430,};/**************************+++++---------分割线--------++++++*******************************************************///动作组数组长度获取函数,增加动作组时需要按如下格式添加:actPwmNum[增加的动作组序号] = sizeof(增加的动作组名称) / sizeof(增加的动作组名称[0]);void act_length(){actPwmNum[0] = (sizeof(actionMove) / sizeof(actionMove[0]))/servo_num;actPwmNum[1] = (sizeof(actionLeft) / sizeof(actionLeft[0]))/servo_num;actPwmNum[2] = (sizeof(actionRight) / sizeof(actionRight[0]))/servo_num;actPwmNum[3] = (sizeof(actionBack) / sizeof(actionBack[0]))/servo_num;actPwmNum[4] = (sizeof(actionDance) / sizeof(actionDance[0]))/servo_num;actPwmNum[5] = (sizeof(actionInit) / sizeof(actionInit[0]))/servo_num;}//map映射函数long map_servo(long x, long in_min, long in_max, long out_min, long out_max){return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;}//PWM 转换为舵机角度的函数,增加动作组时需要修改void vlaue2angle(int p, int act){switch(act){case 0: value_cur[p] = map_servo(pgm_read_word_near(actionMove + p + servo_num * count_input), 500, 2500, 0, 180); break;case 1: value_cur[p] = map_servo(pgm_read_word_near(actionLeft + p + servo_num * count_input), 500, 2500, 0, 180); break;case 2: value_cur[p] = map_servo(pgm_read_word_near(actionRight + p + servo_num * count_input), 500, 2500, 0, 180); break;case 3: value_cur[p] = map_servo(pgm_read_word_near(actionBack + p + servo_num * count_input), 500, 2500, 0, 180); break;case 4: value_cur[p] = map_servo(pgm_read_word_near(actionDance + p + servo_num * count_input), 500, 2500, 0, 180); break;case 5: value_cur[p] = map_servo(pgm_read_word_near(actionInit + p + servo_num * count_input), 500, 2500, 0, 180); break;default: break;}}//舵机初始化函数,动作组第一行为舵机初始化值void servo_init(int act, int num){ if(!_b){for(int i=0;i 0 ;void servo_move(int act, int num){ float value_delta[servo_num] = {};float in_value[servo_num] = {};servo_init(act, num);for(int i=0;i< num * actPwmNum[act];i++){count_input++;if(count_input == actPwmNum[act]){count_input = 0;continue;}for(int i=0;i
对于机器人来说,实现某一个自身结构的极限动作并不难,难度在于如何让动作变得有节奏-舞蹈。因为机器人无法达到人体的柔和度,所以为了让机器人跳舞更具有观赏性,建议大家选择节奏点清晰的音乐,尝试根据音乐节奏来设计舞蹈动作。
改变足对之间的连接零件,就可以扩展出不同的样机,甚至还可以考虑在足对之间加入关节,使其具备更丰富的自由度。
①样机3D文件
②原地舞蹈-例程源代码
③Controller1.0b资料包
④音乐素材.mp3
详细资料下载请参考 12自由度六足-原地舞蹈
上一篇: 大学生职业规划