极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 240202|回复: 170

2013电子设计竞赛-旋转倒立摆-整体方案-2014.10.26更新

  [复制链接]
发表于 2013-10-7 19:24:32 | 显示全部楼层 |阅读模式
本帖最后由 Malc 于 2015-6-10 13:15 编辑

电赛结束了一段时间了,趁这段时间,总结、整理一下自己的方案

------------------------------------------------------------------------------------------------------------

先来看看题目要求吧:



看完题目,经过一番思索和百度之后,有了大概的方案,于是乎开始准备材料,设计机械(我负责),同时其他队员开始设计tb6560驱动、电源模块等等,当然如果你本来就打算选择控制类题目,步进、直流电机及其驱动最好在比赛之前就有充分的准备,我们是使用现成模块的同时开始制作tb6560(比赛的时候其实评委不看我们做的电路,只看我们能否完成题目要求)
用到的材料大部分都是以前的雕刻机项目剩下的材料,倒是省了不少时间,时间宝贵,当然怎么简单有效怎么来了,编码器连接件等东西是这几天加工出来的,abs材料
来张机械结构渲染图,比赛的时候并没有把全部结果画出来,画出个大概就开始做了,那些细节都是比赛后加上去的:

具体的solidworks文件、工程图全部打包在附件中

接下来是电路部分,由于这是控制类题,所以电路比较简单,24v开关电源供电,2596-5v供系统工作,一块arduino nano,一块tb6560,一个ADC键盘用于现场演示,两个mini绝对型编码器1024线
ADC键盘,一个ADC口检测10个按键,我估计检测16个没问题:

tb6560:

2596稳压:


2014.10.26更新:
系统函数图如下:




在接下来就是程序了
总共写了14个版本程序,最后用的就是PID_1_3、PID_1_4,所以这里就给出这两个版本的注释吧:
///////////PID_1_3/////////
PID_1_3.ino :主程序,开机自动检测0°并计算出180°,之后进入循环功能演示。平衡采用PID控制,第一个PID,以摆杆角度作为作为输入,步进电机速度作为输出。第二个PID,以步进速度作为输入,平衡点作为输出(180°±8°)
当摆杆在-110°~-180°或110°~180°范围内时,进行平衡控制,否则关闭步进输出

编码器读数、PID控制放在Timer2中断中,以保证控制周期精准,控制周期5ms
串口命令读取、状态发送放在主函数循环中

起摆思路1:反复震荡摆杆使其摆角越来越大;步进电机往一个方向运动一点距离,停止,等待摆杆达到最高点,再反向运动,停止,等待摆杆达到反向最高点,如此反复,摆杆进入平衡范围后进行平衡控制(起摆时间太长,不采用)

起摆思路2:步进电机突然给一个方向速度,再急刹车,摆杆由于惯性继续圆周运动,当进入平衡范围时,进行平衡控制(时间基本1s以内)

起摆思路3:步进电机突然给一个方向速度,再急刹车,等待摆杆达到最高点,步进电机再反向快速运动,以提高摆杆动能(杆子太重可用此方法)


Stepp.ino :步进电机驱动,使用了Timer1,setStepperSpeed(long myspeed)用于更新速度,StepperEvent()根据速度值驱动步进,如果有加减速效果会更好

Command.ino :接收命令,更新参数,P100代表参数P=100,etc


Encoder.ino :绝对型编码器读数


Filter.ino :FIR低通滤波、中值滤波

function1~6.ino :分别实现基本要求1~3,提高要求1~3



///////////PID_1_4/////////
PID_1_4.ino : loop中命令值略有更改


Command.ino : 将读取串口数据改为读取ADC键盘值,ADC键盘优点:仅一个AD口可实现10个按键,缺点:读数略复杂,只能单点按键,适合atmega328管脚少的芯片

其他函数同PID_1_3

程序比较长,这里就贴出PID_1_3的主函数吧,完整代码附在附件中:

  1. #include <TimerOne.h>



  2. #define setBit(val, bitn)    (val |=(1<<(bitn)))
  3. #define clearBit(val, bitn)     (val&=~(1<<(bitn)))
  4. #define getBit(val, bitn)    (val &(1<<(bitn)) )

  5. int functionSpeed=0,functionFlag=0;
  6. int PIDSign=true,SpeedPIDSign=true;;
  7. int function3Sign=false;

  8. /////////////Angle Parameter/////////
  9. long setPoint=0,setPointOpp=0,originPoint=0;
  10. int degree=0,degreeLast=0,setPointDegree=0;


  11. /////////Arm Speed Parameter/////////
  12. #define PULSE_PER_ROUND 1600
  13. #define MAX_SP_SPEED (PULSE_PER_ROUND*1)
  14. #define MIN_SP_SPEED (-PULSE_PER_ROUND*1)
  15. long setPosition=0,position=0,positionLast=0;
  16. long absPositionLast=0,absPosition=0;
  17. int setSpeed=0,armSpeed=0,lastSpeed=0;
  18. int np=500,ni=0,nd=0;
  19. long sp_error_p=0,sp_error_i=0,sp_error_d=0;
  20. int tempSpSpeed=0,tempPosition;
  21. int delta=2,maxDelta=8;

  22. int calcAngle(int x)
  23. {
  24. if(setPointOpp<=x&&x<originPoint)
  25.   return (x-setPointOpp)*-0.352;
  26. else if(0<=x&&x<setPointOpp)
  27.   return (setPointOpp-x)*0.352;
  28. else
  29.   return 180-(x-originPoint)*0.352;
  30.   
  31. }


  32. void setup()
  33. {  

  34.   EncoderInit();
  35.   StepperInit();

  36.   Serial.begin(57600);
  37.   Serial.print("test begin\ndelay 2s\n");
  38.   int i,num=5,temp;
  39.   for(i=0;i<num;i++)
  40.   {
  41.     temp=SSI(0);
  42.     setPointOpp+=temp;//避免编码器0点在摆杆最低点或最高点,简化计算
  43.     Serial.println(temp);
  44.     delay(100);
  45.   }
  46.   Serial.println(setPointOpp);
  47.   setPointOpp/=num;
  48.   Serial.println(setPointOpp);
  49.   if(setPointOpp<512)
  50.     setPoint=setPointOpp+512;
  51.   else
  52.     setPoint=setPointOpp-512;
  53.    originPoint=setPoint;
  54.    setPointDegree=calcAngle(originPoint);
  55.    Serial.print("setPointOpp=");
  56.    Serial.println(setPointOpp);
  57.    Serial.print("setPoint=");
  58.    Serial.println(setPoint);
  59.   delay(2000);
  60.   
  61.   /*--------------------*/
  62.   // for Timer2
  63.   /*--------------------*/
  64.   // interrupts every 1 ms
  65.   
  66.   TIMSK2 &= ~(1<<TOIE2);
  67.   TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
  68.   TCCR2B &= ~(1<<WGM22);
  69.   ASSR &= ~(1<<AS2);
  70.   TIMSK2 &= ~(1<<OCIE2A);
  71.   TCCR2B |= (1<<CS22)  | (1<<CS20);
  72.   TCCR2B &= ~(1<<CS21);
  73.   TCNT2 = 131;
  74.   TIMSK2 |= (1<<TOIE2);
  75.   
  76.   Timer1.attachInterrupt( StepperEvent ); // attach the service routine here

  77. }


  78. int myspeed;
  79. unsigned long timer;

  80. int angle,angleLast;
  81. int error_p,error_i,error_d;
  82. int velocity;

  83. int kp=15,kd=0,ki=20;//p=15,i=15 works!!

  84. unsigned int counter=0;


  85. void loop()
  86. {   
  87.   checkParameter();
  88.   switch(functionFlag)
  89.   {
  90.     case 1:
  91.            function1();
  92.            break;
  93.     case 11:
  94.            function1();
  95.            break;
  96.     case 2:
  97.            function2();
  98.            break;
  99.     case 3:
  100.            function3();
  101.            break;
  102.     case 4:
  103.            function4();
  104.            break;
  105.     case 41:
  106.            function41();
  107.            break;
  108.     case 6:
  109.            function6();
  110.            break;
  111.    
  112.   }
  113.    
  114.   
  115.   
  116.   Serial.print(originPoint);
  117.   Serial.print(',');
  118.   Serial.print(setPoint);
  119.   Serial.print(',');
  120.   Serial.print(angle);
  121.   Serial.print(',');
  122.   Serial.print(degree);
  123.   Serial.print(',');
  124.   Serial.print(armSpeed);//sp_error_i
  125.   Serial.print(',');
  126.   Serial.print(absPosition);
  127.   Serial.print('\n');
  128.   
  129.   //delay(50);
  130. }

  131. int calcSpeed(int pos,int posLast)
  132. {
  133. if(abs(pos-posLast<512))
  134.    return pos-posLast;
  135. int temp;  
  136. if(pos>posLast)//counter clock
  137.   temp=1023-pos-posLast;
  138. else if(pos<posLast)//clock
  139.   temp=pos+(1023-posLast);
  140. if(temp>1000)
  141.    return temp-1023;
  142. else if(temp<-1000)
  143.   return 1023+temp;
  144.   return temp;
  145. }


  146. int controlTimer=0,speedTimer=0;;
  147. int tempPos,tempPosLast;
  148. int armSpeedArr[3]={0};
  149. ISR(TIMER2_OVF_vect) {  
  150.   TIMSK2 |= (0<<TOIE2);
  151.   TCNT2 = 131;  // reload the timer
  152.   controlTimer++;
  153.   speedTimer++;
  154.   // estimate velocity
  155.   if (controlTimer == 5){
  156.      controlTimer = 0;
  157.      ////////////angle PID///////////
  158.     angleLast=angle;
  159.     angle=SSI(0);
  160.     degreeLast=degree;
  161.     degree=calcAngle(angle);
  162.     //angle=FIR2(angle);
  163.     velocity = (angle - angleLast);
  164.     if(abs(angle-setPoint)<=4)
  165.       error_p = 0;
  166.     else
  167.       error_p = setPoint-angle;
  168.     error_d = velocity;
  169.     error_i = error_i + error_p;
  170.    
  171.    if(PIDSign==false||abs(degree)<110)
  172.   {
  173.    error_p=0;
  174.    error_d=0;
  175.    error_i=0;
  176.   }
  177.   myspeed = - (kp*error_p + kd*error_d + ki*error_i/10);
  178.   setStepperSpeed(myspeed + tempSpSpeed+functionSpeed);
  179.   }
  180.   
  181.   
  182.   if(speedTimer==5)
  183.   {
  184.     speedTimer=0;
  185.   ////////Speed PID///////////////
  186.     positionLast=position;
  187.     lastSpeed=armSpeed;
  188.     position=SSI(1);
  189.    
  190.     armSpeed=calcSpeed(position,positionLast);
  191.     armSpeedArr[0]=armSpeedArr[1];
  192.     armSpeedArr[1]=armSpeedArr[2];
  193.     armSpeedArr[2]=armSpeed;
  194.     armSpeed=mid(armSpeedArr[0],armSpeedArr[1],armSpeedArr[2]);
  195.     if(abs(armSpeed)<=1)
  196.      armSpeed=0;
  197.    
  198.     absPositionLast=absPosition;
  199.     absPosition+=armSpeed;
  200.    
  201.     sp_error_p = setSpeed-armSpeed;
  202.     sp_error_d = armSpeed-lastSpeed;
  203.     sp_error_i = sp_error_i + sp_error_p;
  204.     sp_error_i=constrain(sp_error_i,-1000,1000);
  205.    
  206.    
  207.     tempSpSpeed = -(np*sp_error_p/10.0 + nd*sp_error_d/10.0 + ni*sp_error_i/100.0);
  208.     tempSpSpeed=constrain(tempSpSpeed,-delta,delta);
  209.     //if(PIDSign==false||SpeedPIDSign==false||abs(degree)>155)
  210.     if(PIDSign==true&&SpeedPIDSign==true&&abs(degree)>155)
  211.     {
  212.       setPoint+=tempSpSpeed;
  213.       if(setPoint>originPoint+maxDelta)
  214.        setPoint=originPoint+maxDelta;
  215.       else if(setPoint<originPoint-maxDelta)
  216.        setPoint=originPoint-maxDelta;
  217.     }
  218.     else if(SpeedPIDSign==true)
  219.     {
  220.       setPoint=originPoint;
  221.     }
  222.     }
  223.    
  224.     //setStepperSpeed(myspeed + tempSpSpeed);

  225.   TIMSK2 |= (1<<TOIE2);
  226. }
复制代码



视频、图片在这里:



附件:




115:
http://115.com/lb/5lbawy4ygq2#
倒立摆1.rar
115网盘礼包码:5lbawy4ygq2

TB6560 资料:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

 楼主| 发表于 2014-8-4 14:16:57 | 显示全部楼层
gyq 发表于 2014-8-4 10:40
你说的用502固定在步进电机的轴上么,还是底座上,要是在底座上的话,编码器怎么采集转轴的速度数据呀,这 ...

用502来粘合步进电机的轴与编码器的轴,用胶带固定编码器,防止自转
回复 支持 1 反对 0

使用道具 举报

发表于 2013-10-7 21:04:09 | 显示全部楼层
{:soso_e102:}终于看到源码了。。。仔细学习
回复 支持 反对

使用道具 举报

发表于 2013-10-7 21:15:30 | 显示全部楼层
这效果图让我想起了那个小蜘蛛
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-10-7 22:16:25 | 显示全部楼层
弘毅 发表于 2013-10-7 21:04
终于看到源码了。。。仔细学习

时间紧迫,代码写的比较乱,算法有待改进。。
ps:那两个nano偷偷拆下来自己用了{:soso_e113:}
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-10-7 22:17:22 | 显示全部楼层
幻生幻灭 发表于 2013-10-7 21:15
这效果图让我想起了那个小蜘蛛

不玩蜘蛛了,雕刻机更好玩~
回复 支持 反对

使用道具 举报

发表于 2013-10-7 22:21:29 | 显示全部楼层
关注你很久了,好喜欢你的文章,终于知道你的倒立摆是咋做的的啦~学习,谢谢~~~
回复 支持 反对

使用道具 举报

发表于 2013-10-8 10:54:19 来自手机 | 显示全部楼层
Uno的话程序能用么
回复 支持 反对

使用道具 举报

发表于 2013-10-9 11:34:45 | 显示全部楼层
我们做的也是这个,不过跟您的比起来简直就是个渣啊,这会真的学习了,膜拜啊
回复 支持 反对

使用道具 举报

发表于 2013-10-9 21:42:59 | 显示全部楼层
这架势应该有国一吧。我们的学生一组国一一组国二。没有您这位大神做得好。
回复 支持 反对

使用道具 举报

发表于 2013-10-11 15:51:16 | 显示全部楼层
大神。。。。肯定是国一,一个地区三等奖给跪了
回复 支持 反对

使用道具 举报

发表于 2013-10-11 15:52:04 | 显示全部楼层
做D题的孩纸快要被吓死了
回复 支持 反对

使用道具 举报

发表于 2013-10-11 21:52:58 | 显示全部楼层
编码器放在哪儿了?硬件及机械部分是不是没讲完整,我个人理解是放到倒立摆转轴那块了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-10-12 16:40:45 | 显示全部楼层
wisology 发表于 2013-10-11 21:52
编码器放在哪儿了?硬件及机械部分是不是没讲完整,我个人理解是放到倒立摆转轴那块了。

两个编码器,一个装在摆臂末端,检测摆杆的转角,另一个装在步进底下,步进没有闭环的话摆杆会一直在水平方向移动停不下来,跟平衡车一样
回复 支持 反对

使用道具 举报

发表于 2013-10-12 23:17:53 | 显示全部楼层
这个厉害。。。。。想都没想过。。
回复 支持 反对

使用道具 举报

发表于 2013-10-14 13:51:56 | 显示全部楼层
太赞了!!!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-20 21:36 , Processed in 0.043190 second(s), 30 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表