【华为云技术分享】40多元成本制作基于Arduin的随动四轴机械臂,机械臂实现步骤记录、复现等功能
【摘要】 Arduin随动四轴机械臂,机械臂实现步骤记录、复现等功能;主要原材料元器件有:电位器 * 4、9g舵机 * 4、轻触开关 * 1、Arduin UNO * 1、热熔胶、杜邦线多根(建议用质量好的杜邦线)、连接用的木棍(可以用其他代替)。
制作这个机械臂是导师留下的作业,任务要求是夹取印章,然后在指定的地方盖章。程序要求能记录步骤,并且复现出来。
先大概看下丑陋的成品:
说实话确实很丑,因为临近毕业了,事情又多,没时间搞那么好看了
原材料
电位器 * 4
9g舵机 * 4
轻触开关 * 1
面包板 * 1
Arduin UNO * 1
热熔胶
杜邦线多根(建议用质量好的杜邦线)
连接用的木棍(可以用其他代替)
然后用热熔胶连接成下图的样子:
这样就可以做成随动机械臂了,但是后来因为用电烙铁把电位器管脚连接起来后接触不良,原因是电烙铁的温度使电位器的连接处发生变形,导致的接触不良。随后就拆掉了,也没心思搞了,最后就变成一开始的样子了。
电路连接图如下:
最终的成品:
老师布置的任务要求是夹取印章,然后在指定的地方盖章。程序要求能记录步骤,并且复现出来。
为了节约成本,我只用了一个按键
按键功能:(按几次板子上的灯也相应的会闪烁几次,长按会快速闪烁4次)
按1次:按顺序记录步骤n;
按2次:复现(把刚刚记录的步骤重复一遍);
按3次:暂未定义;
长按1秒:清除记录的所有步骤。
下面我把自己写的代码贴出来(自己研究一下吧):
1 #include <Servo.h> //舵机头文件 2 #include <stdio.h> 3 #include <string.h> 4 #include <MsTimer2.h> //定时器库的 头文件,需添加对应的头文件才可使用,文件放在尾端资源处,自行下载 5 6 Servo myservo1; // 创建一个伺服电机对象1 7 Servo myservo2; // 创建一个伺服电机对象2 8 Servo myservo3; // 创建一个伺服电机对象3 9 Servo myservo4; // 创建一个伺服电机对象4 10 11 #define Servo_Num 4 //自定义舵机个数 12 #define STEP 30 //自定义最大记录步数 13 #define KEY 2 //定义多功能按键管脚 14 #define Step_time 15 //定义步骤复现时舵机改变1度的时间,单位:ms 15 16 int dianweiqi1 = 0; 17 int dianweiqi2 = 0; 18 int dianweiqi3 = 0; 19 int dianweiqi4 = 0; 20 21 unsigned int step_num = 1; //定义已走步数变量 22 unsigned int flag = 0; //定义按键次数标志位 23 unsigned int key_num = 0; //按键次数 24 25 unsigned char Step_Receive [ STEP + 1 ][ Servo_Num ] = {0}; //定义储存步数,初始化为0,最多存储STEP步 26 27 //函数声明 28 void Servo_Read(); 29 void Blink(int i); 30 void slow_Step(int i); 31 32 33 void setup() 34 { 35 pinMode(KEY,INPUT_PULLUP); //初始化按键,上拉输入 36 pinMode(LED_BUILTIN, OUTPUT); //初始化LED灯 37 38 myservo1.attach(6); // 爪 39 myservo2.attach(9); // 小臂舵机 40 myservo3.attach(10); // 大臂舵机 41 myservo4.attach(11); // 底座旋转 42 43 MsTimer2::set(700, RT); // 中断设置函数,每 700ms 进入一次中断 44 45 } 46 47 48 49 void loop() 50 { 51 52 dianweiqi1 = analogRead(0); //读取A0口模拟量 53 dianweiqi1 = map(dianweiqi1, 0, 1023, 180, 0); //将模拟量转换为0~180之间的数值 54 myservo1.write( dianweiqi1 ); 55 56 dianweiqi2 = analogRead(1); 57 dianweiqi2 = map(dianweiqi2, 0, 1023, 0, 180); //这样更改值会使舵机反着转 58 myservo2.write( dianweiqi2 ); 59 60 dianweiqi3 = analogRead(2); 61 dianweiqi3 = map(dianweiqi3, 0, 1023, 180, 0); 62 myservo3.write( dianweiqi3 ); 63 64 dianweiqi4 = analogRead(3); 65 dianweiqi4 = map(dianweiqi4, 0, 1023, 0, 180); 66 myservo4.write( dianweiqi4 ); 67 68 Scan_KEY(); //按键扫描 69 if(key_num > 0) 70 { 71 if( flag == 0 && key_num == 1 ) //按一次记录步骤 72 { 73 Blink(key_num, 400); 74 Servo_Read(); 75 key_num = 0; 76 } 77 78 else if(flag == 0 && key_num == 2)//按两次记录复现 79 { 80 Blink(key_num, 400); 81 Servo_Step_recur(); 82 key_num = 0; 83 } 84 85 else if(flag == 0 && key_num == 3)//按三次循环复现 86 { 87 Blink(key_num, 400); 88 key_num = 0; 89 } 90 91 else if(flag == 0 && key_num >= 4)//长按清除记录步骤 92 { 93 memset( Step_Receive, 0, sizeof(Step_Receive) / 4 ); 94 step_num = 1; //步数记录回到第1步 95 Blink(key_num, 200); //LED灯闪烁4次 96 key_num = 0; 97 } 98 } 99 100 } 101 102 103 void RT() //中断函数 104 { 105 flag = 0; 106 MsTimer2::stop(); //停止计时 107 } 108 109 void Scan_KEY() //按键扫描 110 { 111 if( digitalRead(KEY) == 0 ) //查看按键是否按下 112 { 113 delay(80); //延时80ms,去抖动 114 if( digitalRead(KEY) == 0 ) //查看按键是否按下 115 { 116 key_num++; 117 flag = 1; 118 MsTimer2::start(); //启动定时器 119 120 while(digitalRead(KEY) == 0) //松手检测,若超过700ms未松手,则判断为长按 121 { 122 delay(10); 123 if( key_num == 1 && flag == 0 ) 124 { 125 key_num = 4; 126 } 127 } 128 } 129 130 } 131 132 } 133 134 void slow_Step(int i) 135 { 136 int j = 0; 137 int arr[Servo_Num + 1] = {0}; 138 int arr_temp[Servo_Num + 1] = {0}; 139 140 //如果是第一步,则记录现在的位置,作为对比 141 if(i == 1) 142 { 143 Step_Receive[i - 1][0] = dianweiqi1; 144 Step_Receive[i - 1][1] = dianweiqi2; 145 Step_Receive[i - 1][2] = dianweiqi3; 146 Step_Receive[i - 1][3] = dianweiqi4; 147 } 148 149 150 //与上一步对比,缓慢前进 151 for(j = 0; j < Servo_Num; j++) 152 { 153 if( Step_Receive[i][j] - Step_Receive[i - 1][j] > 0 ) 154 { 155 arr[j] = 1; 156 arr_temp[j] = 1; 157 } 158 159 else if( Step_Receive[i][j] - Step_Receive[i - 1][j] < 0 ) 160 { 161 arr[j] = -1; 162 arr_temp[j] = -1; 163 } 164 else 165 { 166 arr[j] = 0; 167 arr_temp[j] = 0; 168 } 169 } 170 171 while( ( (Step_Receive[i - 1][0] + arr[0]) != (Step_Receive[i][0]) ) || 172 ( (Step_Receive[i - 1][1] + arr[1]) != (Step_Receive[i][1]) ) || 173 ( (Step_Receive[i - 1][2] + arr[2]) != (Step_Receive[i][2]) ) || 174 ( (Step_Receive[i - 1][3] + arr[3]) != (Step_Receive[i][3]) ) ) 175 { 176 177 myservo1.write( Step_Receive[i - 1][0] + arr[0] ); 178 if( (Step_Receive[i - 1][0] + arr[0]) != (Step_Receive[i][0]) ){ 179 arr[0] += arr_temp[0]; 180 } 181 182 myservo2.write( Step_Receive[i - 1][1] + arr[1] ); 183 if( (Step_Receive[i - 1][1] + arr[1]) != (Step_Receive[i][1]) ){ 184 arr[1] += arr_temp[1]; 185 } 186 187 myservo3.write( Step_Receive[i - 1][2] + arr[2] ); 188 if( (Step_Receive[i - 1][2] + arr[2]) != (Step_Receive[i][2]) ){ 189 arr[2] += arr_temp[2]; 190 } 191 192 myservo4.write( Step_Receive[i - 1][3] + arr[3] ); 193 if( (Step_Receive[i - 1][3] + arr[3]) != (Step_Receive[i][3]) ){ 194 arr[3] += arr_temp[3]; 195 } 196 197 delay(Step_time); 198 } 199 200 } 201 202 203 void Servo_Step_recur()//舵机步骤复现 204 { 205 int i = 0, j = 0; 206 for(i = 1; i < step_num; i++) 207 { 208 slow_Step(i); 209 // for(j = 0; j < 1; j++)//循环多次,让舵机接收PWM波持续一段时间 210 // { 211 // myservo1.write( Step_Receive[i][0] ); 212 // myservo2.write( Step_Receive[i][1] ); 213 // myservo3.write( Step_Receive[i][2] ); 214 // myservo4.write( Step_Receive[i][3] ); 215 // } 216 // delay(1000);//等待舵机到位 217 } 218 219 } 220 221 222 223 void Servo_Read() //读取脉冲值 224 { 225 Step_Receive[step_num][0] = dianweiqi1; 226 Step_Receive[step_num][1] = dianweiqi2; 227 Step_Receive[step_num][2] = dianweiqi3; 228 Step_Receive[step_num][3] = dianweiqi4; 229 if (step_num < STEP) 230 { 231 step_num++; 232 } 233 else{ 234 Blink(15, 100);//超过最大记录步数 LED灯闪烁1.5s 235 } 236 } 237 238 void Blink(int i, int j ){ //闪烁灯程序,i为闪烁次数,j为闪烁间隔 单位ms 239 for(; i > 0; i--) 240 { 241 digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) 242 delay(j); // wait for a second 243 digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW 244 delay(j); 245 }// wait for a second 246 }
作者:Micah