風力擺?這是不是太簡單了點


 

關於風力擺

風力擺是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,全在數學公式。

其實只需要一天半的,但是那個畫圓錐的地方出現了問題, 不是公式出了問題,而是想法錯了,就是我說的注意的地方,白白焦躁了半天,日了狗,哎。

 

有問題的可以留言哈

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM