风力摆?这是不是太简单了点

关于风力摆

风力摆是2015年的电子设计大赛题目

关于风力摆的说明啊,实现的功能啊我就不多说了

网上有很多的资料,说难了这是PID调节什么的,但是说简单了这就是一个单摆 和 圆锥摆模型

如果你用PDI一点一点调,你会调死,要是用我的方法,呵呵,往下看吧

废话我就不多说了直接进入正题

所需材料

 材料就简单了

  • 单片机最小系统(最好用stm32 快,开源,资料多)
  • 电机驱动模块2个双通道的(淘宝上很多 几块钱)
  • 液晶显示屏(OLED足够用了)
  • JLink ( 下载程序用的,为了节约成本用串口下载也可以 )
  • 碳杆60cm
  • 万向节
  • 陀螺仪(mpu6050)
  • 空心杯电机(4个)
  • 导线若干
  • 还有就是电池

先来个图片吧

 

 虽然有点抽,但完全不影响功能

风力摆思路

1. 画直线就是单摆思路

  陀螺仪可以测得角加速度,同时经过四元数换算可以得到三轴方向的角度,有了这个基础就简单了。

  

  1.1首先先弄出0°方向的直线

    我选的是roll作为0°轴,这样可以先用此时角度算出此时应该要的角速度,然后写两个环,角度负反馈环 和 角速度负反馈环,就可以平衡了,

  1.2直线长度可设置

    直线长度就和顶点到地面距离L,期望摆起的角度有关

  1.3各个方向

    然后通过希望的方向角度,可以算出,x, y (x,y 可以根据自己的喜好设置) 方向上所期望的角度和角速度(这个角度满足公式 tan(a)= y / x , 不清楚的慢慢推,中学物理),就可以向180度延申。

  1.4停止就只要吧期望线长设为0

2.画圆的思路

  和画直线是一样的,由圆锥摆的性质,可得,摆长一定,摆起的高度和角速度成比例关系,

  要注意的是这里的角速度和mpu6050的角速度不等价,这里mpu6050测出的角速度是旋转时的线速度。这个地方不懂的可以多想想。(我可是吃了亏的,白白延迟了半天的进度)

  这里也可以向上面那样加两个负反馈环,不过我就用了一个角速度环,简单嘛。

然后就没有然后,这样就搞定了,附上控制代码吧

  1 #include "mymath.h"
  2 #include "math.h"
  3 #include "IMU6050.h"
  4 #include "control.h"
  5 
  6 //================================================单摆
  7 //得到此时的偏差值
  8 float Get_Offset(Imu_t* imu_t, ALL_Expect* expect, ALL_OFFSET* offset)
  9 {
 10     float expect_x, expect_y;
 11     float speed;
 12     float speed_x, speed_y;
 13     int dir_x = 0, dir_y = 0;
 14     
 15     dir_x = Get_Direct(expect->angle, imu_t->gyro.x, imu_t->roll, imu_t->pitch, 0);
 16     dir_y = Get_Direct(expect->angle, imu_t->gyro.y, imu_t->roll, imu_t->pitch, 1);
 17     Get_Expect_X_Y(expect->angle, expect->length_to_angle, &expect_x, &expect_y);
 18     
 19     speed = Get_Speed(expect->length_to_angle, imu_t->roll, imu_t->pitch, 60);
 20     Get_Expect_X_Y(expect->angle, speed, &speed_x, &speed_y);
 21     
 22     if(speed>0)
 23     {
 24         if((imu_t->gyro.x)*(imu_t->roll)>0)
 25         {
 26             offset->x_offset = MY_ABS(expect_x - MY_ABS(imu_t->roll))*dir_x*1.0;
 27             offset->y_offset = MY_ABS(expect_y - MY_ABS(imu_t->pitch))*dir_y*1.0;
 28         }
 29         else
 30         {
 31             offset->x_offset = 0;
 32             offset->y_offset = 0;
 33         }
 34     }
 35     else if(speed < 0)
 36     {
 37         
 38         offset->x_offset = -MY_ABS(expect_x - MY_ABS(imu_t->roll))*dir_x*1.0;
 39         
 40         offset->y_offset = -MY_ABS(expect_y - MY_ABS(imu_t->pitch))*dir_y*1.0;    
 41     }
 42     else
 43     {
 44             offset->x_offset = 0;
 45             offset->y_offset = 0;
 46     }
 47     
 48     if(speed>=0)
 49     {
 50             offset->x_gyro_offset = (speed_x - MY_ABS(imu_t->gyro.x))*dir_x*1.0;
 51             offset->y_gyro_offset = (speed_y - MY_ABS(imu_t->gyro.y))*dir_y*1.0;
 52     }
 53     else if(speed < 0)
 54     {
 55         offset->x_gyro_offset = -MY_ABS(imu_t->gyro.x)*dir_x*1.0;
 56         offset->y_gyro_offset = -MY_ABS(imu_t->gyro.y)*dir_y*1.0;
 57     }
 58     
 59     return speed_y;
 60 }
 61 
 62 //得到期望角的方向
 63 int Get_Direct(int angle, float gyro, float roll, float pitch, int x_y)
 64 {
 65     int speed = 0;
 66     
 67     speed = gyro*20;
 68     if(speed>0)
 69     {
 70         return 1;
 71     }
 72     else if(speed == 0)
 73     {
 74         if(MY_ABS(roll)<3 && MY_ABS(pitch)<3)  //判读是否没有动
 75         {
 76             if(x_y == 0)
 77             {
 78                 if(angle<=90)
 79                 {
 80                     return 1;
 81                 }
 82                 else
 83                 {
 84                     return -1;
 85                 }
 86             }
 87             else if(x_y == 1)
 88             {
 89                 return 1;
 90             }
 91         }
 92         return 0;
 93     }
 94     else if(speed<0)
 95     {
 96         return -1;
 97     }
 98 }
 99 
100 //得到期望的x, y 比例
101 void Get_Expect_X_Y(int angle, float self, float *x, float* y)
102 {
103     float p=0;
104     
105     if(self<0)
106     {
107         *x = 0;
108         *y = 0;
109         return;
110     }
111     
112     if(angle<90)
113     {
114         p = tan(ANGLE_TO_RADIAN(angle))*1.0;   //得到比例值
115     }
116     else if(angle == 90)
117     {
118         *x = 0;
119         *y = self;
120         return ;
121     }
122     else if(angle > 90)
123     {
124         p = tan(ANGLE_TO_RADIAN(angle-90))*1.0;   //得到比例值
125     }
126     *x = sqrt(self*self / (1+p*p))*1.0;
127     *y = *x * p;
128 }
129 
130 //得到一定角度时的速度
131 //L是杆子的长度
132 float Get_Speed(float length_to_angle, float roll, float pitch, int L)
133 {
134     float now_angle;
135     float h;
136 
137     now_angle = sqrt((roll*roll)+(pitch*pitch));
138     if(now_angle>length_to_angle)
139     {    
140         return length_to_angle - now_angle;
141     }
142     h = L*(cos(ANGLE_TO_RADIAN(now_angle))-cos(ANGLE_TO_RADIAN(length_to_angle)));
143     return (sqrt(2*980*h))/L*1.0;
144 }
145     
146 
147 //===============================================圆锥摆
148 float Get_Circulat_Offset(Imu_t *imu_t, ALL_Expect* expect, ALL_OFFSET* offset)
149 {
150     float r, speed, a;
151     float speed_x, speed_y;
152     float angle;
153     int dir_x = 0, dir_y = 0;
154     
155 //    dir_x = Get_Direct(expect->angle, imu_t->gyro.x, imu_t->roll, imu_t->pitch, 0);
156 //    dir_y = Get_Direct(expect->angle, imu_t->gyro.y, imu_t->roll, imu_t->pitch, 1);
157     Get_Circulat_Dir(imu_t->roll, imu_t->pitch, &dir_x, &dir_y, 1);
158     
159     r = 0.7 * sin(ANGLE_TO_RADIAN(expect->length_to_angle));
160     a = 9.8 * tan(ANGLE_TO_RADIAN(expect->length_to_angle));  //向心加速度
161     speed = sqrt(r * a)*1.0 + 0.31;
162 
163     if (imu_t->roll != 0 | imu_t->roll != 180)
164         angle = atan2(MY_ABS(imu_t->pitch), MY_ABS(imu_t->roll)) * 57.3;
165     else
166         angle = 90;
167     Get_Expect_X_Y(angle, speed, &speed_y, &speed_x);
168         
169     offset->x_offset = 0;
170     offset->y_offset = 0;
171     offset->x_gyro_offset = (speed_x - MY_ABS(imu_t->gyro.x))*dir_x*1.0;
172     offset->y_gyro_offset = (speed_y - MY_ABS(imu_t->gyro.y))*dir_y*1.0;
173     return speed;;
174 }
175 
176 //根据 旋转方向得到 电机方向
177 void Get_Circulat_Dir(float roll, float pitch, int *dir_x, int *dir_y, int dir)  // 
178 {
179 
180     int clock_dir[2][4][2] = {
181         {
182             {+1,-1},  //一相线
183             {+1,+1},    //二相线
184             {-1,+1},  //三相线
185             {-1,-1},  //四相线
186         },
187         {
188             {-1,+1},  //一相线
189             {-1,-1},    //二相线
190             {+1,-1},  //三相线
191             {+1,+1},  //四相线
192         }
193     }
194     ;
195     //判断象限
196     if(roll>=0 && pitch>=0)
197     {
198         *dir_x = clock_dir[dir][0][0];
199         *dir_y = clock_dir[dir][0][1];
200     }
201     else    if(roll<0 && pitch>=0)
202     {
203         *dir_x = clock_dir[dir][1][0];
204         *dir_y = clock_dir[dir][1][1];
205     }
206     else    if(roll<0 && pitch<0)
207     {
208         *dir_x = clock_dir[dir][2][0];
209         *dir_y = clock_dir[dir][2][1];
210     }
211     else    if(roll>=0 && pitch<0)
212     {
213         *dir_x = clock_dir[dir][3][0];
214         *dir_y = clock_dir[dir][3][1];
215     }
216 }

也就简单的两百行

要不你再看看我的PID调节代码,看看简单不简单???

 1 int P1_1=1, P1_2=1, P1_3=1, P1_4=1;
 2 int P2_1=50, P2_2=50, P2_3=50, P2_4=50;
 3 void PID_Judge(ALL_OFFSET offset)
 4 {
 5     uint16_t pwm1=0, pwm2=0, pwm3=0, pwm4=0;
 6     
 7     if(offset.x_offset>=0) 
 8     {
 9         pwm1 += P1_1*offset.x_offset;
10     }
11     else
12     {
13         pwm2 += P1_2*(-offset.x_offset);
14     }
15     /////
16     if(offset.x_gyro_offset>=0)
17     {
18         pwm1 += P2_1*offset.x_gyro_offset;
19     }
20     else
21     {
22         pwm2 += P2_2*(-offset.x_gyro_offset);
23     }
24     /////
25     if(offset.y_offset>=0)
26     {
27         pwm3 += P1_3*offset.y_offset;
28     }
29     else
30     {
31         pwm4 += P1_4*(-offset.y_offset);
32     }
33     /////
34     if(offset.y_gyro_offset>=0)
35     {
36         pwm3 += P2_3*offset.y_gyro_offset;
37     }
38     else
39     {
40         pwm4 += P2_4*(-offset.y_gyro_offset);
41     }
42     
43     pwm1 = LIMIT_MAX(pwm1, 80);
44     pwm2 = LIMIT_MAX(pwm2, 80);
45     pwm3 = LIMIT_MAX(pwm3, 80);
46     pwm4 = LIMIT_MAX(pwm4, 80);
47     
48     TIM_SetCompare1(TIM10,pwm1);    //修改比较值,修改占空比
49     TIM_SetCompare1(TIM11,pwm2);    //修改比较值,修改占空比
50     TIM_SetCompare1(TIM13,pwm3);    //修改比较值,修改占空比
51     TIM_SetCompare1(TIM14,pwm4);    //修改比较值,修改占空比
52 }

总结

这个题目说起来很难,其实想成物理模型就很简单了,也就那样吧

可惜不附上视频不然肯定秀一波,和大神做的差不了多少,照样是乱动 5s 内就能恢复

这个东西加搭硬件写程序只用了2天,因为我不用怎么调PID,全在数学公式。

其实只需要一天半的,但是那个画圆锥的地方出现了问题, 不是公式出了问题,而是想法错了,就是我说的注意的地方,白白焦躁了半天,日了狗,哎。

有问题的可以留言哈

猜你喜欢

转载自www.cnblogs.com/kaixindexiaocao/p/11290266.html