四軸飛行器1.1 Matlab 姿態顯示
開始做四軸了,一步一步來,東西實在很多,比較雜。先做matlab上位機,主要用來做數據分析,等板子到了可以寫飛控的程序了,從底層一層一層開始寫。。希望能好好的完成它。。。關於matlab上位機,首先做個姿態顯示,然后等板子來了,把板子底層程序寫好后,加上matlab的串口接收部分,基本的環境就算搭建好了。。。。
這個代碼寫了一天,寫到最后出現戲劇性的一幕,實在是太惡心了哈。。開始自己的想法就是通過輸入pitch roll yaw三個歐拉角,然后在空間中現實飛機的姿態,為了學習matlab翻了matlab的書,還看了線性代數,為了畫這個姿態圖,看了高中的立體解析幾何,向量運算等。。。都是淚啊,說回正題,首先計算xOy平面中的轉動,也就是yaw軸,這個相對比較簡單,讓三角形的三個點分別在圖中的大圓和小圓上,如圖所示:
yaw解決了之后就需要解決pitch了,就是俯仰角,約定是以坐標的(0 0 0)點進行旋轉的,也是兩個圓的圓心,所以算pitch只需要在xOz平面內計算,通過sin(pitch)可以算出來A B C三個點在Z軸上的坐標了,這里需要注意下,A點變換后,相對應的X軸變化是cos(pitch),y軸也是,算到這里會發現一個問題,用matlab算B C連個點的時候,只需算B或者C,解出來是有兩個解的,一個B一個C,B和C必須分辨清楚,否則在計算roll的時候因為 B C沒有分清楚會導致roll旋轉方向不確定,后面再說B C怎么分辨。
接下來是計算 roll了,需要計算B 點和C點在Z軸上的坐標,因為我們是繞着(0 0 0)轉的,而不是繞着BC的終點轉,所以無法通過BC的長度乘以sin(roll)計算,所以通過圓心做一條直線與BC平行,假設與AC交與F點,
% A
% E O F
% B D C
無論pitch和yaw怎么轉,OF都是在xOy平面的,方便計算,通過sin(roll)*OF的長度就可以得到F在Z軸的變化,從而通過等比可以的到C在Z軸的變化,B點變化和C是一樣的,方向相反,之后將B C的坐標在xOy平面做cos(roll)縮放就可以的到最終的三角形的三個坐標了。
接着講BC的分辨問題,想來想去只想到一個比較簡單的方法,我們算出來BC並不知道哪個是B,哪個是C,不過我們可以制定一個B‘ 點,那就是我們取一個DB方向的方向向量n,跟隨三角形旋轉,讓它始終指向定義的DB方向,然后可以計算OB OC分別和向量n的內積,
因為n與OB為銳角,與OB為鈍角,so,n 與OB點乘為負數,與OC點乘為正數,從而區分出B點和C點 。
上面想法看起來不錯,但是怎么讓向量n隨着yaw角轉動呢,靈機一閃,線性代數書的矩陣里面有個旋轉矩陣啊,立馬拿過來驗證,發現可以很好的運行,然后想到一個問題,如果某種情況三角形roll為90度,DB的分量在xOy平面為0,這個方法就無效了啊(其實這個問題應該不會出現,因為我們是線計算yaw 然后計算pitch,在計算pitch的時候分辨BC亮點,壓根就還沒開始計算roll),那用三維旋轉矩陣就可以解決這個問題啊,嗯嗯,又靈機一閃,之前看過捷聯慣性導航書上講了方向旋轉矩陣啊,應該可以用。把方向余弦拿過來計算一下,和用xOy平面的旋轉舉證效果一樣,到此忽然想到一個非常十分傻逼的事情,媽蛋,三角形三個點全部用這個方向余弦矩陣旋轉就可以了啊,立馬改程序,不到十分鍾就改完了,程序運行良好,都是淚。。。。。。不過自己的算法不能半途而廢啊,后面還是把自己的算法完成,並且也可以很好的運行。。。不過因為用了matlab的符號運算,速度和用方向余弦計算比起來慢很多,后面還是用方向余弦算吧。。。。。。。
下面貼代碼:
1 %% 2 %2014.7.19 由 sky.zhou 編寫 3 function DrawAttitude(pitch,roll,yaw) 4 %% 5 %用於顯示飛機姿態,輸入為pitch,roll,yaw。 6 %自己的2B算法算的太慢了,我勒個去。。。還是用方向余弦吧 7 mode = 2 %標記用那種方法進行計算,1:表示用自己寫的2B算法進行計算,2表示用方向余弦矩陣進行計算 8 9 %pitch = 60; 10 %roll = 45; 11 %yaw = 35; 12 r1 =3; %大圓半徑 13 r2 = 0.618*r1; %小圓半徑 14 15 if mode == 2 16 pitch = -pitch; %角度定義不一樣,改一下 17 roll = -roll; %角度定義方式不一樣,自己習慣改就好,看你希望是以怎樣的方向轉 18 end 19 dc = [cosd(yaw)*cosd(pitch)-sind(yaw)*sind(roll)*sind(pitch) sind(yaw)*cosd(pitch)+cosd(yaw)*sind(roll)*sind(pitch) cosd(roll)*(-sind(pitch)); 20 sind(yaw)*(-cosd(roll)) cosd(yaw)*cosd(roll) sind(roll) ; 21 cosd(yaw)*sind(pitch)+sind(yaw)*sind(roll)*cosd(pitch) sind(yaw)*sind(pitch)-cosd(yaw)*sind(roll)*cosd(pitch) cosd(roll)*cosd(pitch) ] 22 %三角形規約:A為定點,B C為兩邊的角,具體方位如下 23 % A 24 % B C 25 t_fpa = 35; %三角形定點角度設置為40度,fpa On behalf of Fixed point angle 26 t_b = (180 - t_fpa) / 2; 27 t_c = t_b; 28 29 if t_fpa > asind((r2/r1))*2 30 t_fpa = asind((r2/r1))*2 31 end 32 33 %xd,yd,zd存放真是數值,與符號xyz區分開來 34 %約定 xd yd zd 第 1 2 3 4位分別代表三角形ABC的 A、B、A、C坐標 35 if mode == 2 36 xd=[3 -1.2735;3 -1.2735]; 37 yd=[0 1.3474;0 -1.3474]; 38 zd=[0 0;0 0]; 39 %上面幾個初始化的點是根據 定義的。 40 %pitch = 0; 41 %roll = 0; 42 %yaw = 0; 43 %r1 =3; %大圓半徑 44 %r2 = 0.618*r1; %小圓半徑 45 else 46 xd=[]; 47 yd=[]; 48 zd=[]; 49 tempA =[]; %保存中間計算角度,目前之用來保存角BOA 50 end 51 temp = []; 52 if mode == 2 53 temp = [xd(1,1) yd(1,1) zd(1,1); 54 xd(1,2) yd(1,2) zd(1,2); 55 xd(2,2) yd(2,2) zd(2,2)]; 56 temp = temp*dc; 57 xd = [temp(1:2,1)';temp(1,1),temp(3,1)] 58 yd = [temp(1:2,2)';temp(1,2),temp(3,2)] 59 zd = [temp(1:2,3)';temp(1,3),temp(3,3)] 60 %到此位置,方向余弦矩陣已經計算完畢,可以直接用后面的函數進行顯示 61 end 62 63 if mode == 1 %執行自己的2B算法 64 %xs ys zs分別問記錄方程的解 xs 為sysm縮寫 65 syms x y z r xs ys zs; %x y z 慣性坐標系中三個正交基,r為xOy平面中的大圓和小圓半徑 66 %定義各點的坐標符號參數 67 syms xa ya za xb yb zb za zb zc ; 68 69 %% 70 c1 = sym('x^2+y^2 = r^2'); %大圓方程 71 c1 = subs(c1,'r',r1) %換成實際數值 72 73 c2 = sym('x^2+y^2 = r^2'); %校園方程,可以表達為:c2 = 'x^2+y^2 = r^2',效果是一樣的 74 c2 = subs(c2,'r',r2) 75 76 l1 = sym('cosd(yaw)*y=sind(yaw)*x') 77 %l1 = sym('y=tand(yaw)*x') %不用這個公式是因為這個公式有零點,90和-90無法使用 78 %l1 = subs(l1, 'yaw', yaw) %換成實際數值,這里不要轉成實際數值,為了方便subs的運算 79 %% 80 [xs ys] = solve(c1,l1,'x','y') %注意,這里算出來的xd yd是符號變量,matlab自動轉換了,下面重新對其賦值,可以變回數值變量 81 82 %雙百分號還可以類似於分類的作用,挺好。 83 temp = subs([xs;ys]) 84 85 %% 86 %計算A點坐標 87 if yaw > -90 && yaw < 90 %判斷角度的范圍,用來選擇在坐標中三角形的頂點是正還是負 88 %這個可能有點難理解,角度確定了,就可以知道焦點在x軸的正負,從前兩個數值中取對應的X解后,然后取對應的Y的解 89 temp = temp([temp(1:2)>0;temp(1:2)>0]) 90 elseif yaw == -90 91 temp = [ 0 ;temp(temp<0)] 92 elseif yaw == 90 93 temp = [ 0 ;temp(temp>0)] 94 else 95 temp = temp([temp(1:2)<0;temp(1:2)<0]) 96 end 97 98 %得到在XOY平面中三角形定點的第一個解 99 xd = [xd temp(1)] 100 yd = [yd temp(2)] 101 102 %% 103 %計算B點坐標 104 105 %temp計算出來表示的是 AB段的長度, 106 % A 107 % O 108 % B D C 109 %其中 sind(t_b/2)*r2 表示的是OD段的長度,cosd(t_b/2)*r2是BD段的長度, 110 %temp計算的最終結果是AB的長度 111 %利用三角形邊與對面角正弦成比例進行運算 112 % AB BC A0 B0 113 % ----- = ----- ----- = --------- 114 % sin(C) sin(A) sin(角ABO) sin(角OAB)(ps:A的一半) 115 % 可以求出角ABO,然后通過內角和可以求出角AOB 116 % AB BO 117 % ----- = -------- 可以求出AB長度,簡化代碼如下 118 % sin(角AOB) sin(角OAB) 119 % (180 - asind((r1/r2)*sind(t_fpa/2)) - (t_fpa/2)) 為角BOA的大小 120 tempA = sym('(180 - asind((r1/r2)*sind(t_fpa/2)) - (t_fpa/2))'); 121 temp = sym('(r2/sind(t_fpa/2))*sind(tempA)'); 122 tempA = subs(tempA); 123 temp = subs(temp); 124 125 126 %temp = subs(sym('sqrt(((sind(t_b/2)*r2)+r1)^2 + (cosd(t_b/2)*r2)^2)')); 127 128 %假設 符號 xa ya 為 A點的坐標,x,y為要求的B點坐標 129 temp = subs(sym('(x-xa)^2 + (y-ya)^2 = temp^2'),'temp',temp); 130 %將xa和ya換成數值xa和ya,嵌套換的 131 temp = subs(subs(temp,'xa',xd(1)),'ya',yd(1)) 132 [xs ys] = solve(temp,c2,'x','y') 133 134 %通過下面的計算就已經可以得到 B C的坐標了 135 temp = subs([xs;ys]) 136 137 %下面需要做的是區別哪個點是A,哪個點是B。 138 %% 139 % 下面是在xOy平面內的旋轉 140 % B 141 % D O A yaw=0度的時候三角型在X0Y平面的方位,其中水平位置為x軸豎直方向為Y軸 142 % C 143 % 取一個與DB方向一樣的方向向量n(0,1) 144 % 用旋轉矩陣讓它跟三角形同步旋轉 145 % 因為n與OB為銳角,與OB為鈍角,so,n與OB點乘為負數,與OC點乘為正數,從而區分出B點和C點 146 %% 147 % 為了避免roll為90度的時候按照之前的定義方向向量n=(0,0),區分不出來B和C點,所以用方向余弦矩陣進行計算 148 %方向余弦矩陣定義 149 %dc = [cosd(yaw)*cosd(pitch)-sind(yaw)*sind(roll)*sind(pitch) sind(yaw)*cosd(pitch)+cosd(yaw)*sind(roll)*sind(pitch) cosd(roll)*(-sind(pitch)); 150 % sind(yaw)*(-cosd(roll)) cosd(yaw)*cosd(roll) sind(roll) ; 151 % cosd(yaw)*sind(pitch)+sind(yaw)*sind(roll)*cosd(pitch) sind(yaw)*sind(pitch)-cosd(yaw)*sind(roll)*cosd(pitch) cosd(roll)*cosd(pitch) ] 152 %%算到這里的時候我發現只要在xOy平面內將三角形的初始化坐標ABC三個點輸入后,用方向余弦矩陣算就可以了,然后花了10分鍾不到的時間就實現了 153 %不過這里還是決定把這個方法寫完。。。都是淚。。。。。。。。。。。。。。。。。 154 %% 155 n = [0 1 0] %方向向量 156 n = n*dc %對方向向量進行旋轉 157 %約定 xd yd zd 第 1 2 3 4位分別代表三角形ABC的 A、B、A、C坐標 158 n = n*[temp(1);temp(3);0] 159 if n > 0 %說明夾角是銳角,該角是B點 160 xd = [ xd temp(1) xd temp(2)] 161 yd = [ yd temp(3) yd temp(4)] 162 else 163 xd = [ xd temp(2) xd temp(1)] 164 yd = [ yd temp(4) yd temp(3)] 165 end 166 167 %處理成變成矩陣形式 168 xd = [xd(1:2);xd(3:4)] 169 yd = [yd(1:2);yd(3:4)] 170 171 %當存在pitch角度的時候,X坐標做相印調整 172 xd = xd.*cosd(pitch) 173 yd = yd.*cosd(pitch) 174 175 176 %% 177 %約定 xd yd zd 第 1 2 3 4位分別代表三角形ABC的 A、B、A、C坐標 178 %計算z中A的坐標,其中B和C是相等的 179 zd = [zd sind(pitch)*r1] 180 181 %下面OD的長度,然后可以計算出B和C在Z軸上的坐標,也就是D點的坐標 182 od = (sind(tempA - 90)*r2) 183 %zd = [zd temp;zd temp] 184 185 %計算roll狀態下B和C的坐標 186 % A 187 % E O F 188 % B D C 189 % 先計算在roll下OF的長度,然后算F在Z軸的高度,然后等比后算B和C在Z軸的高度 190 %下面計算OF的長度 191 l2 = tand(t_fpa/2)*r1 192 %下面計算F在Z軸上的變化高度 193 l2 = sind(roll)*l2 194 %下面計算C點在Z軸上的變化高度,通過相似三角形計算 195 l2 = l2*(r1+od)/r1 196 197 zd = [zd -l2;zd l2] 198 %x,y軸根據picth角度縮放 199 yd(:,2) = yd(:,2).*cosd(roll) 200 xd(:,2) = xd(:,2).*cosd(roll) 201 202 %額。。這方法寫的心力交瘁。。。。。。。還是方向余弦好。。。四元素再學。。。。。。 203 204 205 end 206 surf(xd,yd,zd) 207 axis([-3 3 -3 3 -3 3]) 208 xlabel('X') 209 ylabel('Y') 210 zlabel('Z') 211 text(xd(1,1),yd(1,1),zd(1,1),'A點') 212 text(xd(1,2),yd(1,2),zd(1,2),'B點') 213 text(xd(2,2),yd(2,2),zd(2,2),'C點') 214 %% 215 %測試用圓 216 hold on 217 alpha=0:pi/20:2*pi; 218 x=r1*cos(alpha); 219 y=r1*sin(alpha); 220 plot(x,y); 221 222 hold on 223 x=r2*cos(alpha); 224 y=r2*sin(alpha); 225 plot(x,y); 226 227 hold off 228 end