2025年机械专业大二学生纯手工打造一台机械臂——充满妥协

机械专业大二学生纯手工打造一台机械臂——充满妥协我所建的为三自由度连杆机械臂 选择搭建这款机械臂主要是因为此机械臂操作简单 易于掌握 便于学习 以下为我在学习制造这款机械臂的一些流程 主要零件 主控板 arduino uno r3 扩展板 cnc shield v3 雕刻机扩展板 42 步进电机

大家好,我是讯享网,很高兴认识大家。

我所建的为三自由度连杆机械臂,选择搭建这款机械臂主要是因为此机械臂操作简单,易于掌握,便于学习。

以下为我在学习制造这款机械臂的一些流程:

主要零件

主控板:arduino uno r3

扩展板:cnc shield v3雕刻机扩展板

42步进电机,SG90电机,PVC板,A4988驱动模块,HC-06模块

由于我做一件事喜欢把它列出来,所以做了思维导图:


讯享网

并且在坐标自寻上我也进行了数学结算:

 

 以下为代码部分:

在代码部分中,由于本人编程能力较弱,一部分代码和编程思维均借鉴了多位B站UP主,并且本文章仅为记录我学习机械臂的过程。

手机模式和键盘模式代码:

/*电机步进模式须在cnc电机扩展版上进行调试。 * 启动程序,程序开始默认为键盘控制模式 * 在键盘模式中,'m'可一键切换至手机模式。 * 手机模式 * 在手机模式中,'m'可一键切换至键盘模式。 */ #include <Servo.h> #include <AccelStepper.h> #include <SoftwareSerial.h> SoftwareSerial BTserial(12, 13); // 建立SoftwareSerial对象,RX引脚12(SpnEn)接SpnDir, TX引脚13(SpnDir)接SpnEn // 定义电机控制用常量 const int enablePin = 8; // 使能控制引脚 const int xdirPin = 5; // x方向控制引脚 const int xstepPin = 2; // x步进控制引脚 const int ydirPin = 6; // y方向控制引脚 const int ystepPin = 3; // y步进控制引脚 const int zdirPin = 7; // z方向控制引脚 const int zstepPin = 4; // z步进控制引脚 const int clawMin = 144; //存储电机极限值 const int clawMax = 180; const int moveSteps = 5; //步进电机运行使用的运行步数(仅适用于手机模式) char cmd; //电机指令字符 int data; //电机指令参数 char stepperName; //控制电机编号 int stepNumber; //步进电机运行步数 int clawstep; //夹爪电机的目标角度 bool mode = 1; //mode = 1: 键盘模式, mode = 0: 手机模式 int DSD = 15; //Default Servo Delay (默认电机运动延迟时间) //此变量用于控制电机运行速度.增大此变量数值将 //降低电机运行速度从而控制机械臂动作速度。 int clawMoveStep = 2; // 每一次按下手柄按键,舵机移动量(仅适用于手机模式) Servo claw ; //建立伺服电机对象———夹爪电机 AccelStepper base_stepper(1,xstepPin,xdirPin); //建立步进电机对象———底座电机 AccelStepper forearm_stepper(1,ystepPin,ydirPin); //建立步进电机对象———前臂电机 AccelStepper upperarm_stepper(1,zstepPin,zdirPin); //建立步进电机对象———后臂电机 void setup() { pinMode(xstepPin,OUTPUT); // Arduino控制A4988x步进引脚为输出模式 pinMode(xdirPin,OUTPUT); // Arduino控制A4988x方向引脚为输出模式 pinMode(ystepPin,OUTPUT); // Arduino控制A4988y步进引脚为输出模式 pinMode(ydirPin,OUTPUT); // Arduino控制A4988y方向引脚为输出模式 pinMode(zstepPin,OUTPUT); // Arduino控制A4988z步进引脚为输出模式 pinMode(zdirPin,OUTPUT); // Arduino控制A4988z方向引脚为输出模式 pinMode(enablePin,OUTPUT); // Arduino控制A4988使能引脚为输出模式 digitalWrite(enablePin,LOW); // 将使能控制引脚设置为低电平从而让 // 电机驱动板进入工作状态 claw.attach(11); // claw 伺服舵机连接引脚Z+ 舵机代号'c' delay(200); // 稳定性等待 claw.write(90); delay(10); Serial.begin(9600); BTserial.begin(9600); // HC-06 默认波特率 9600 Serial.println(F("/\\\\\\\\\\\\\\\\\\")); Serial.println(F("The robotic arm serves you*")); Serial.println(F("/\\\\\\\\\\\\\\\\\\")); Serial.println(F("")); Serial.println(F("Please input motor command:")); Serial.print("HC-06 DEMO/TEST "); BTserial.print("AT"); //可在此处输入设置HC-06蓝牙模块的AT指令。 //此AT指令须在HC-06未连接蓝牙状态输入。 base_stepper.setMaxSpeed(100); // 设置电机最大速度为500 base_stepper.setAcceleration(50.0); // 初始化电机速度为0 setSpeed(0); forearm_stepper.setMaxSpeed(100); forearm_stepper.setAcceleration(50.0); upperarm_stepper.setMaxSpeed(100); upperarm_stepper.setAcceleration(50.0); claw.write(144); base_stepper.setCurrentPosition(0); forearm_stepper.setCurrentPosition(0); upperarm_stepper.setCurrentPosition(0); } void loop() { if (Serial.available()>0) { //Serial.available()>0 //BTserial.available()>0 cmd = Serial.read(); Serial.print(cmd); if( mode == 1 ){ keyboard_input(cmd); //键盘控制模式 } else { cellphone_input(cmd); //手机控制模式 } } base_stepper.run(); //底座电机运行 forearm_stepper.run(); //前臂电机运行 upperarm_stepper.run(); //后臂电机运行 } //Arduino根据串行指令执行相应操作 // void keyboard_input(char cmd){ //判断是否因搞错模式而输入错误的指令信息(键盘模式下输入手机模式信息) if ( cmd == 'w' || cmd == 's' || cmd == 'a' || cmd == 'd' || cmd == '5' || cmd == '4' || cmd == '6' || cmd == '8' ){ Serial.println("Warning!!! Warning!!! Warning!!! Currently in the keyboard_input"); delay(100); while(Serial.available()>0) char wrongCommand = Serial.read(); //清除串口缓存的错误指令 return; } if( cmd == 'b' || cmd == 'f' || cmd == 'u'){ data = Serial.parseInt(); RunCommand(cmd,data); }else{ switch (cmd){ case 'm' ://切换至手机控制模式 mode = 0; Serial.println("Enter the cellphone control mode"); break; case 'o' ://使机械臂复位 reset_arm(); Serial.println("Receive command"); break; case 'c' ://夹爪电机运行 int servoData = Serial.parseInt(); servoCmd(cmd, servoData, DSD); // 机械臂舵机运行函数(参数:舵机名,目标角度,延迟/速度) Serial.println("Receive the claw operation command"); break; default : //未知指令反馈 Serial.println("Unknown Command."); } } } void cellphone_input (char cmd ){ //判断人类是否因搞错模式而输入错误的指令信息(手机模式下输入键盘模式信息) if (cmd == 'b' || cmd == 'f' || cmd == 'u' || cmd == 'v'){ Serial.println("Warning!!! Warning!!! Warning!!! Currently in the cellphone_input"); delay(100); while(Serial.available()>0) char wrongCommand = Serial.read(); //清除串口缓存的错误指令 return; } int basestep; int forearmstep; int upperarmstep; //int clawstep switch(cmd){ case 'a' ://base_stepper向左 basestep = base_stepper.currentPosition() - moveSteps; Serial.println("A run command was received"); delay(500); base_stepper.moveTo(basestep); //CellphoneRunCommand('a',basestep); break; case 'd' ://base_stepper向右 basestep = base_stepper.currentPosition() + moveSteps; Serial.println("A run command was received"); delay(500); base_stepper.moveTo(basestep); //CellphoneRunCommand('d',basestep); break; case 'w' ://upperarm_stepper向下 upperarmstep = upperarm_stepper.currentPosition() - moveSteps; Serial.println("A run command was received"); delay(500); upperarm_stepper.moveTo(upperarmstep); //CellphoneRunCommand('w',upperarmstep); break; case 's' ://upperarm_stepper向上 upperarmstep = upperarm_stepper.currentPosition() + moveSteps; Serial.println("A run command was received"); delay(500); upperarm_stepper.moveTo(upperarmstep); //CellphoneRunCommand('s',upperarmstep); break; case '8' ://forearm_stepper向下 forearmstep = forearm_stepper.currentPosition() - moveSteps; Serial.println("A run command was received"); delay(500); forearm_stepper.moveTo(forearmstep); //CellphoneRunCommand('8',forearmstep); break; case '5' ://forearm_stepper向上 forearmstep = forearm_stepper.currentPosition() + moveSteps; Serial.println("A run command was received"); delay(500); forearm_stepper.moveTo(forearmstep); //CellphoneRunCommand('5',forearmstep); break; case '4' ://夹爪打开 Serial.println("Received Command: Claw Open Up"); clawstep = claw.read() - clawMoveStep; servoCmd('c', clawstep, DSD); break; case '6' ://夹爪闭合 Serial.println("Received Command: Claw Close Down"); clawstep = claw.read() + clawMoveStep; servoCmd('c', clawstep, DSD); break; case 'm' : //切换至键盘控制模式 mode = 1; Serial.println("Enter the keyboard control mode"); break; case 'o' ://使机械臂复位 reset_arm(); Serial.println("Receive command"); break; //default : //未知指令反馈 //Serial.println("Unknown Command."); } } void RunCommand(char stepperName,int stepNumber){ switch (stepperName){ case 'b' ://底座电机运行,利用move函数使电机运行相应步数(示例:b1024 - 使电机运行1024步 ) Serial.println("A run command was received"); //delay(500); base_stepper.move(stepNumber); break; case 'f' : Serial.println("A run command was received"); //delay(500); forearm_stepper.move(stepNumber); break; case 'u' : Serial.println("A run command was received"); //delay(500); upperarm_stepper.move(stepNumber); break; default: //未知指令反馈 Serial.println("Unknown Command."); } } void reset_arm(){//机械臂复位函数。 /*runToNewPosition与moveTo函数功能基本相同。唯一区别是runToNewPosition函数将“block”程序运行。 * 即电机没有到达目标位置前,Arduino将不会继续执行后续程序内容。 */ Serial.println("Receive command"); base_stepper.runToNewPosition(0); forearm_stepper.runToNewPosition(0); upperarm_stepper.runToNewPosition(0); claw.write(145); delay(500); Serial.println("The reset command was completed"); } void servoCmd(char servoName, int toPos, int servoDelay){ int fromPos; //建立变量,存储电机起始运动角度值 if(toPos >= clawMin && toPos <= clawMax){ fromPos = claw.read(); // 获取当前电机角度值用于“电机运动起始角度值” } else { Serial.println("+Warning: Claw Servo Value Out Of Limit!"); return; } //指挥夹爪电机运行 if (fromPos <= toPos){ //如果“起始角度值”小于“目标角度值” for (int i=fromPos; i<=toPos; i++){ claw.write(i); delay (15); } }else { //否则“起始角度值”大于“目标角度值” for (int i=fromPos; i>=toPos; i--){ claw.write(i); delay (15); Serial.println("Receive command"); } } }

讯享网

坐标自寻代码: 

讯享网float basepos; float forearmpos; float upperarmpos; float upperarmpos1; float upperarmpos2; float pi=3.14; float touying; const int basehigh=13; int duanbian; int xiebian; int x; float y; float z; #include <AccelStepper.h> // 定义电机控制用常量 const int enablePin = 8; // 使能控制引脚 const int xdirPin = 5; // x方向控制引脚 const int xstepPin = 2; // x步进控制引脚 const int ydirPin = 6; // y方向控制引脚 const int ystepPin = 3; // y步进控制引脚 const int zdirPin = 7; // z方向控制引脚 const int zstepPin = 4; // z步进控制引脚 const int Num=6; const int upperarm=16; const int forearm=14; AccelStepper base_stepper(1,xstepPin,xdirPin); //建立步进电机对象———底座电机 AccelStepper forearm_stepper(1,ystepPin,ydirPin); //建立步进电机对象———前臂电机 AccelStepper upperarm_stepper(1,zstepPin,zdirPin); //建立步进电机对象———后臂电机 void setup() { pinMode(xstepPin,OUTPUT); // Arduino控制A4988x步进引脚为输出模式 pinMode(xdirPin,OUTPUT); // Arduino控制A4988x方向引脚为输出模式 pinMode(ystepPin,OUTPUT); // Arduino控制A4988y步进引脚为输出模式 pinMode(ydirPin,OUTPUT); // Arduino控制A4988y方向引脚为输出模式 pinMode(zstepPin,OUTPUT); // Arduino控制A4988z步进引脚为输出模式 pinMode(zdirPin,OUTPUT); // Arduino控制A4988z方向引脚为输出模式 pinMode(enablePin,OUTPUT); // Arduino控制A4988使能引脚为输出模式 digitalWrite(enablePin,LOW); // 将使能控制引脚设置为低电平从而让 // 电机驱动板进入工作状态 Serial.begin(9600); Serial.println(F("/\\\\\\\\\\\\\\\\\\")); Serial.println(F("The robotic arm serves you*")); Serial.println(F("/\\\\\\\\\\\\\\\\\\")); Serial.println(F("")); Serial.println(F("Please input motor command:")); base_stepper.setMaxSpeed(100); // 设置电机最大速度为500 base_stepper.setAcceleration(50.0); // 初始化电机速度为0 setSpeed(0); forearm_stepper.setMaxSpeed(100); forearm_stepper.setAcceleration(50.0); upperarm_stepper.setMaxSpeed(100); upperarm_stepper.setAcceleration(50.0); base_stepper.setCurrentPosition(0); forearm_stepper.setCurrentPosition(0); upperarm_stepper.setCurrentPosition(0); } void loop() { // put your main code here, to run repeatedly: if (Serial.available()>1){ int data = Serial.parseInt(); x=data/100; y=abs((data-x*100)/10); z=abs(data%10); Serial.println(x); Serial.println(y); Serial.println(z); calculate(); Serial.print("basepos= ");Serial.println(basepos); Serial.print("upperarmpos= ");Serial.println(upperarmpos); Serial.print("forearmpos= ");Serial.println(forearmpos); RunCommand(basepos,upperarmpos,forearmpos); base_stepper.run(); //底座电机运行 forearm_stepper.run(); //后臂电机运行 upperarm_stepper.run(); //前臂电机运行 } } void calculate(){ basepos=atan(x/y)*(180/pi)/1.8; //底角角度 delay(500); touying=sqrt(pow(x,2)+pow(y,2))-Num; delay(500); duanbian=abs(basehigh-z); xiebian=sqrt(pow(duanbian,2)+pow(touying,2)); upperarmpos1=(acos((pow(upperarm,2)+pow(xiebian,2)-pow(forearm,2))/(2*upperarm*xiebian)))*(180/pi); if(basehigh==z){ upperarmpos2=0; }else if(basehigh>z){ upperarmpos2=atan(touying/duanbian)* (180/pi)-90; } else if(basehigh<z){ upperarmpos2=atan(duanbian/touying)-90; } upperarmpos=(upperarmpos1+upperarmpos2-15)/1.8; //前臂角度 forearmpos=(acos((pow(upperarm,2)+pow(forearm,2)-pow(xiebian,2))/(2*upperarm*forearm))*(180/pi)+(upperarmpos-90))/1.8; //后臂角度 } void RunCommand(int b,int u,int f){ Serial.println("Receive command"); Serial.println(b); Serial.println(u); Serial.println(f); upperarm_stepper.runToNewPosition(u); delay(100); forearm_stepper.runToNewPosition(f); delay(500); base_stepper.runToNewPosition(b); delay(500); }

作为一名机械专业学生,实在不想在代码上花费过多时间(哭笑),没有将两个代码合并,并且本人编程能力很弱,代码中可能有许多错误。

本文章仅供个人学习所用。

小讯
上一篇 2025-03-21 14:53
下一篇 2025-03-14 10:03

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/27172.html