四轮全向底盘工训纪实1 工程训练纪实前言2 组装过程2.1 结构说明2.2 具体步骤3 调整电控3.1 伺服电机初始化3.2 步进电机控制3.2.1 抬笔与落笔3.2.2 修改绘图范围3.2.3 控制全向底盘移动1 工程训练纪实前言这是南京理工大学暑期工程训练金工实习机器人项目第二天的记录博客记录了四轮全向底盘的全过程细节在此先向这一个月中的各位老师表达感谢尤其感谢张小兵教授的教导。先叠个甲以后的学弟学妹请勿完全照抄本文本人方案仅为我个人记录吾技术浅薄仅供参考。2 组装过程2.1 结构说明四福来轮全向移动底盘采用四个全向福来轮作为执行轮这四个轮成正方形分布且每个轮在斜45°方向安装。全向福来轮由主轮和副轮组成主轮和副轮成垂直分布。驱动系统采用精度较高的42步进电机执行末端为伺服电机。通过四个步进电机运动的相互配合四个步进电机驱动将圆周转动转化为直线运动从而实现全向移动。四福来轮全向移动底盘具有结构简单、运动灵活等特点可以用于实现各种复杂的移动和定位任务。例如它可以用于机器人、自动化设备、无人驾驶车辆等领域实现精确的定位、移动和操控。2.2 具体步骤总体上难度不大拼起来很快直接上PPT。注意要先调试电机再安装。安装电机时接线头应朝向侧面不得朝向下面。接线的时候要注意线材颜色否则电机易烧毁可以给助教看看。其中笔架需要自己设计完善可以通过螺丝去固定也可以用透明胶带进行捆绑无论用什么方法笔要稳不能抖。3 调整电控3.1 伺服电机初始化在上课之前老师会提前发一个压缩包里面有各种各样的工具软件还有半成品代码这里就要用到arduino和controller。先将以下命名为servo_bigfish.ino的代码通过arduino烧录进开发板中。/* * Bigfish扩展板舵机口; 4, 7, 11, 3, 8, 12, 14, 15, 16, 17, 18, 19 * 使用软件调节舵机时请拖拽对应序号的控制块 */#includeServo.h#defineANGLE_VALUE_MIN0#defineANGLE_VALUE_MAX180#definePWM_VALUE_MIN500#definePWM_VALUE_MAX2500#defineSERVO_NUM12Servo myServo[SERVO_NUM];intdata_array[2]{0,0};//servo_pin: data_array[0], servo_value: data_array[1];intservo_port[SERVO_NUM]{4,7,11,3,8,12,14,15,16,17,18,19};intservo_value[SERVO_NUM]{};String data;boolean dataCompletefalse;voidsetup(){Serial.begin(9600);}voidloop(){while(Serial.available()){intB_flag,P_flag,T_flag;dataSerial.readStringUntil(\n);data.trim();for(inti0;idata.length();i){//Serial.println(data[i]);switch(data[i]){case#:B_flagi;break;caseP:{String pin;P_flagi;for(intiB_flag1;iP_flag;i){pindata[i];}data_array[0]pin.toInt();}break;caseT:{String angle;T_flagi;for(intiP_flag1;iT_flag;i){angledata[i];}data_array[1]angle.toInt();servo_value[pin2index(data_array[0])]data_array[1];}break;default:break;}}/* Serial.println(B_flag); Serial.println(P_flag); Serial.println(T_flag); for(int i0;i2;i) { Serial.println(data_array[i]); } */dataCompletetrue;}if(dataComplete){for(inti0;iSERVO_NUM;i){ServoGo(i,servo_value[i]);/*********************************串口查看输出***********************************/// Serial.print(servo_value[i]);// Serial.print( );}// Serial.println();/********************************************************************/dataCompletefalse;}}voidServoStart(intwhich){if(!myServo[which].attached()(servo_value[which]!0))myServo[which].attach(servo_port[which]);elsereturn;pinMode(servo_port[which],OUTPUT);}voidServoStop(intwhich){myServo[which].detach();digitalWrite(servo_port[which],LOW);}voidServoGo(intwhich,intwhere){ServoStart(which);if(whereANGLE_VALUE_MINwhereANGLE_VALUE_MAX){myServo[which].write(where);}elseif(wherePWM_VALUE_MINwherePWM_VALUE_MAX){myServo[which].writeMicroseconds(where);}}intpin2index(int_pin){intindex;switch(_pin){case4:index0;break;case7:index1;break;case11:index2;break;case3:index3;break;case8:index4;break;case12:index5;break;case14:index6;break;case15:index7;break;case16:index8;break;case17:index9;break;case18:index10;break;case19:index11;break;}returnindex;}代码烧录后进入controller选择端口号及波特率进行连接在对应模块中拖动控制条使电机转动最终置于90°的位置伺服电机初始化调整成功。3.2 步进电机控制步进电机控制这一段是整体最有趣的地方看起来有些难但仅需有一些C语言程序设计基础即可完成无需理解全部的代码只需要看懂位移如何控制的就行。下面是一个现成的画六边形的代码仅供参考。#includeServo.h/* * en定义步进电机使能引脚 * servo_pin定义舵机引脚 * stepper_count定义步进电机数量 * stepperPulse_delay定义步进电机脉冲生成间隔 * LINE_BUFFER_LENGTH定义串口接收数据长度 */#defineen8#defineservo_pin11#definestepper_count4#definestepperPulse_delay850#defineLINE_BUFFER_LENGTH512/* * positive_x定义正向 X 轴 * positive_y定义正向 Y 轴 * negative_x定义负向 X 轴 * negative_y定义负向 Y 轴 */#definepositive_x0#definepositive_y1#definenegative_x2#definenegative_y3/* * stepperDir_pin定义步进电机方向引脚数组 * stepperStp_pin定义步进电机步进引脚数组 * dir: x: 5, y: 6, z: 7, a: 13 * stp: x: 2, y: 3, z: 4, a: 12 */intstepperDir_pin[4]{5,6,7,13};intstepperStp_pin[4]{2,3,4,12};Servo myServo;constintstepsPerRevolution3200;//定义步进电机每圈转动的步数此处为16细分每圈 3200 步intpenZup145;//定义舵机抬起角度intpenZdown180;//定义舵机放下角度floatLEADsqrt(2)*58*PI;//定义步进电机转动 1 圈小车前进的距离单位 mmfloatl60;//定义六边形边长//定义六边形顶点坐标数组floatcoords[7][2]{-l*1/2,-sqrt(3)/2*l,l*1/2,-sqrt(3)/2*l,l,0,l*1/2,sqrt(3)/2*l,-l*1/2,sqrt(3)/2*l,-l,0,-l*1/2,-sqrt(3)/2*l};floatXmin-60;//定义绘图范围floatXmax60;floatYmin-60;floatYmax60;floatXpos0;floatYpos0;voidsetup(){Serial.begin(9600);//开启串口通信波特率为 9600myServo.attach(servo_pin);myServo.write(penZup);for(inti0;istepper_count;i){pinMode(stepperDir_pin[i],OUTPUT);pinMode(stepperStp_pin[i],OUTPUT);}pinMode(en,OUTPUT);digitalWrite(en,LOW);delay(1000);}voidloop(){draw_sexangle();while(1){};}//六边形绘制函数voiddraw_sexangle(){drawLine(coords[0][0],coords[0][1]);delay(200);for(inti0;isizeof(coords)/sizeof(coords[0]);i){penDown();delay(200);drawLine(coords[i][0],coords[i][1]);penUp();}}//直线插补函数参数为点坐标值voiddrawLine(floatx1,floaty1){intdx,dy,n,k,i,f,stepInc;if(x1Xmax){x1Xmax;}if(x1Xmin){x1Xmin;}if(y1Ymax){y1Ymax;}if(y1Ymin){y1Ymin;}x1(int)(x1/LEAD*stepsPerRevolution);y1(int)(y1/LEAD*stepsPerRevolution);floatx0Xpos;floaty0Ypos;dxabs(x1-x0);dyabs(y1-y0);nabs(dxdy);if(x1x0){ky1y0?1:4;}else{ky1y0?2:3;}for(i0,f0;in;i1){if(f0){switch(k){case1:stepper_move(positive_x,1);ff-dy;//Serial.println(x);break;case2:stepper_move(negative_x,1);ff-dy;//Serial.println(-x);break;case3:stepper_move(negative_x,1);ff-dy;//Serial.println(-x);break;case4:stepper_move(positive_x,1);ff-dy;//Serial.println(x);break;default:break;}}else{switch(k){case1:stepper_move(positive_y,1);ffdx;//Serial.println(y);break;case2:stepper_move(positive_y,1);ffdx;//Serial.println(y);break;case3:stepper_move(negative_y,1);ffdx;//Serial.println(-y);break;case4:stepper_move(negative_y,1);ffdx;//Serial.println(-y);break;default:break;}}}Xposx1;Yposy1;}//小车行进方向控制函数voidstepper_dir(intpositiveDir_x,intpositiveDir_y,intnegativeDir_x,intnegativeDir_y){intdir_value[]{positiveDir_x,positiveDir_y,negativeDir_x,negativeDir_y};for(inti0;istepper_count;i){//Serial.print(dir_value[i]);//Serial.print(,);digitalWrite(stepperDir_pin[i],dir_value[i]);}//Serial.println();for(intj0;jstepper_count;j){digitalWrite(stepperStp_pin[j],HIGH);}delayMicroseconds(stepperPulse_delay);for(intj0;jstepper_count;j){digitalWrite(stepperStp_pin[j],LOW);}delayMicroseconds(stepperPulse_delay);}//步进电机转动函数参数 dir_xy步进电机转动方向steps步进电机转动步数voidstepper_move(intdir_xy,intsteps){for(inti0;iabs(steps);i){switch(dir_xy){case0:stepper_dir(1,1,0,0);break;case1:stepper_dir(1,0,1,0);break;case2:stepper_dir(0,0,1,1);break;case3:stepper_dir(0,1,0,1);break;default:break;}}}//舵机抬笔函数voidpenUp(){myServo.write(penZup);}//舵机落笔函数voidpenDown(){myServo.write(penZdown);}3.2.1 抬笔与落笔角度需要自己用controller一次一次去尝试而且由于安装不同penZup可能不一定是抬笔penZdown也可能不一定是落笔。intpenZup145;//定义舵机抬起角度intpenZdown180;//定义舵机放下角度3.2.2 修改绘图范围建议增大绘图范围超范围就会在那里描边。floatXmin-60;//定义绘图范围floatXmax60;floatYmin-60;floatYmax60;3.2.3 控制全向底盘移动下面截取了画六边形的移动控制方法以此为例。floatLEADsqrt(2)*58*PI;//定义步进电机转动 1 圈小车前进的距离单位 mmfloatlen60;//定义六边形边长//定义六边形顶点坐标数组floatcoords[7][2]{-len*1/2,-sqrt(3)/2*len,len*1/2,-sqrt(3)/2*len,len,0,len*1/2,sqrt(3)/2*len,-len*1/2,sqrt(3)/2*len,-len,0,-l*1/2,-sqrt(3)/2*len};在float coords二维数组中存储了每次移动的目标点位的坐标在修改时可以将len作为一单位长度这样方便修改。如果要控制全向底盘写字的话不一定要按照正常的笔画进行运动。