2015年11月9日 星期一

[Algorithm] 移動平均濾波 Moving Average

平均法是濾波上最容易實現的一種方法之一,常常被拿來應用,像是每 10 筆資料做一次平均值之類的,但這種方式有下面幾個缺點:

1、假設每秒取樣 n 筆資料時,每 m 筆資料做平均值,更新速度會等於 n/m Hz,低於取樣速度。
2、資料曲線不夠平滑,每筆平均數間容易產生落差。


移動平均顧名思義就是移動 + 平均,此方法可以解決上述問題,在不影響更新速度的同時增加平滑度,運算量也不大,下面將介紹簡單的移動平均與加權的移動平均兩種方法。


簡單移動平均 Simple Moving Average, SMA

移動平均顧名思義就是移動 + 平均,在固定的"視窗大小"下取平均值,而這個視窗會移動,其實就是摺積(Convolution)

gif 圖片截自 wikipedia - Convolution https://en.wikipedia.org/wiki/Convolution


下面是一個實際的範例,紅色框框表示視窗,程式上可以理解成 FIFO,大小為 4 筆資料,初值為 0,總共有 8 筆資料,有問號的 8 筆資料是移動平均算出來的資料,一開始因為 FIFO 的資料沒有被填滿,所以誤差比較大。



大致的概念就是現一個長度 N 的 FIFO,最新的資料進去,最舊的資料出來,FIFO 裡面始終保持 N 筆最新的資料,對裡面 N 筆資料做平均值就是移動平均了,N 的大小會影響到訊號的響應速度,N 越大,越容易抗雜訊,但響應速度會變慢,N 越小,越不易抗雜訊,但響應速度越快,當 N = 1 時,其實就是實際的資料。

下面是自己用 MATLAB 撰寫的移動平均,之前也有寫過一個,不過是直接讓 FIFO 的資料移動,也就是頭跟尾始終保持最新和最舊的資料,但在這種方法下,更新 FIFO 的部分運算量會隨著 FIFO 的長度增加而增加,所以就另外寫了一個直接將最舊的資料替代成最新的資料,更新 FIFO 的運算量在不同長度下將不會變,效率應該也高於前者。


簡單移動平均 moveAve_s.m
function [aveData, p_front] = moveAve_s( newData, moveAveFIFO, fifoLens, windowLens )

    p_front = moveAveFIFO(1);
    p_rear  = mod(p_front - windowLens + fifoLens, fifoLens) + 1;

    sumData = 0;
    if p_front > p_rear
        for i = p_front : -1 : p_rear
            sumData = sumData + moveAveFIFO(i + 1);
        end
    else
        for i = p_front : -1 : 1
            sumData = sumData + moveAveFIFO(i + 1);
        end
        for i = fifoLens : -1 : p_rear
            sumData = sumData + moveAveFIFO(i + 1);
        end
    end

    aveData = sumData / windowLens;
    p_front = mod(p_front, fifoLens) + 1;

end


加權移動平均 Weighted Moving Average, WMA

加權移動平均與簡單的移動平均只差在每次做累加的時候會乘上權重,透過權重來調整資料的重要性或影響性。


加權移動平均 moveAve_w.m
function [aveData, p_front] = moveAve_w( newData, moveAveFIFO, weighted, fifoLens, windowLens )

    p_front = moveAveFIFO(1);
    p_rear  = mod(p_front - windowLens + fifoLens, fifoLens) + 1;

    sumData = 0;
    count = 1;
    if p_front > p_rear
        for i = p_front : -1 : p_rear
            sumData = sumData + moveAveFIFO(i + 1) * weighted(count + 1);
            count = count + 1;
        end
    else
        for i = p_front : -1 : 1
            sumData = sumData + moveAveFIFO(i + 1) * weighted(count + 1);
            count = count + 1;
        end
        for i = fifoLens : -1 : p_rear
            sumData = sumData + moveAveFIFO(i + 1) * weighted(count + 1);
            count = count + 1;
        end
    end

    aveData = sumData / weighted(1);
    p_front = mod(p_front, fifoLens) + 1;

end


驗證兩種移動平均方法 testMoveAve.m
clear all;

timeScal = 0.01;
runTimes = 10;

fifoLens = 256;
windowLens = 32;
fifo = zeros(1, fifoLens+1);
fifo(1) = windowLens;

weighted = zeros(1, windowLens + 1);
for i = 1 : windowLens
    weighted(i + 1) = 2^((windowLens - i) / 4);
end
weighted(1) = sum(weighted(2 : end));

saveLens = 0;
for t = 0 : timeScal : runTimes
    newData = sin(t) + randn();

    p_front = fifo(1);
    fifo(p_front + 1) = newData;
    [sma_data, p_front] = moveAve_s(newData, fifo, fifoLens, windowLens);
    [wma_data, p_front] = moveAve_w(newData, fifo, weighted, fifoLens, windowLens);
    fifo(1) = p_front;

    saveLens = saveLens + 1;
    save_org(saveLens)  = sin(t);
    save_orgn(saveLens) = newData;
    save_sma(saveLens)  = sma_data;
    save_wma(saveLens)  = wma_data;
end

hold on;
grid on;
plot([0 : timeScal : runTimes], save_org,  'g');
plot([0 : timeScal : runTimes], save_orgn, 'r');
plot([0 : timeScal : runTimes], save_sma,  'b');
plot([0 : timeScal : runTimes], save_wma,  'c');

xlabel('t(s)');
ylabel('data');
legend('org', 'org + noise', 'sma', 'wma');


Github→https://github.com/Hom-Wang/MATLAB/tree/master/moveAve

2015年11月3日 星期二

[Algorithm] Cholesky 正定矩陣分解

最近在搞 UKF,需要求解 P 矩陣的開跟號,所以找了一篇文章線代啟示錄 - Cholesky 分解參考,賺寫一個 Cholesky 矩陣分解的程式,暫時先用 MATLAB 實現,方便之後再移植到單晶片上做處理。


簡單講一下原理,假定有一個正定矩陣 A,我們希望他可以被分解成一個 P 矩陣乘上自己的轉置,而這個 P 矩陣是一個下三角矩陣,也就是我們想要求得的分解結果,如下圖所示,


如果 A 矩陣是一個正定矩陣,則可以表示成下面形式,L 和 U 分別為上三角和下三角矩陣(U 和 L 打反了,將就下),X 為對角矩陣,並且 A 矩陣的轉置會等於 A 矩陣,


藉由 A 矩陣的轉置會等於 A 矩陣的條件,可以得到下列關係,並且帶回前式整理,


可以得到 A 矩陣和 P 矩陣的關係,這裡以 3x3 的矩陣做展開,再過歸納,



上式反推得到下列關係,


透過上述關係可歸納出在 n x n 的正定矩陣分解出來的 P 矩陣如下。



最後透過 MATLAB 來做驗證,MATLAB 有一個 Chol() 的指令,用來做 cholesky 分解的,下面自己撰寫好 cholesky 分解後,透過 A = P P' 來驗證結果,當然也可以透過 Chol() 來判斷是否正確,程式沒有很完善,在正定矩陣的判斷等等沒有處理,如果要實際應用,建議需要另外加入一些條件處理特殊狀況。


cholesky 分解, cholesky.m
function sqrt_matrix = cholesky( pdMatrix )

    [n, m] = size(pdMatrix);
 sqrt_matrix = zeros(n);
 for j = 1 : n
        for i = j : n
            if i == j
                tempSum = 0;
                for k = 1 : i - 1
                    tempSum = tempSum + sqrt_matrix(i, k)^2;
                end
                sqrt_matrix(i, j) = sqrt(pdMatrix(i, j) - tempSum);
            else
                tempSum = 0;
                for k = 1 : j - 1
                    tempSum = tempSum + sqrt_matrix(i, k) * sqrt_matrix(j, k);
                end
                sqrt_matrix(i, j) = (pdMatrix(i, j) - tempSum) / sqrt_matrix(j, j);
            end
        end
    end

end

cholesky 驗證, testCholesky.m
n = 10;
X = diag(rand(n, 1));
U = orth(rand(n, n));

pdMatrix = U' * X * U;

P_U = chol(pdMatrix, 'upper');
P_L = chol(pdMatrix, 'lower');

P   = cholesky(pdMatrix);

check = roundn(pdMatrix, -10) == roundn(P * P', -10);
if sum(sum(check)) == n * n
    sprintf('Equal')
else
    sprintf('Not Equal')
end

Github → https://github.com/Hom-Wang/MATLAB/tree/master/cholesky

2015年10月8日 星期四

[QCopter] 從零開始做四軸 (五) - 感測器原理

在四軸飛行器上面常會使用一些感測器做為回授,來取得飛行器的姿態、航向或是高度等資訊,常見有陀螺儀、加速度計、磁力計以及氣壓計這四種,由於微機電系統(Micro Electro Mechanical System, MEMS) 技術的發達,把機械系統縮小到微米(10E-6)或是奈米(10E-9)等級,使的這些感測器得以封裝起來,變成小的 IC。

慣性測量元件(Inertial Measurement Unit, IMU)是一個用來測量姿態角、方向、速度等等的裝置,通常由陀螺儀與加速度計組成,有時候也會加入磁力計與氣壓計來輔助計算,常常使用在載具的導航上面。

上述四種感測器的種類與型號眾多,但依輸出可以分成數位與類比兩種,數位輸出通常使用像是 SPI、I2C 等通訊介面來獲取感測器資料,電路處理上較簡單,功能較多,可能包含濾波器等,而另一種則是類比的輸出,輸出的資料大小會與電壓成正比,會把原始感測到的資訊直接輸出,雖然原始,但比較靈活,通常使用 ADC 來讀取電壓資訊。

在感測器選型時,常常會看到一軸陀螺儀、三軸加速度計等等,其軸數表示為可以感測到物理量的分量,沒有方向的物理量像是溫度、氣壓等,都是單軸就可以得到完整的資訊,但有方向的物理量像是角速度、加速度等,會將物理量投影到軸上,投影就像是把一個建築物(三維)畫在紙(二維)上一樣,在紙上你看不到建築物的後面,但實際上你可以走到建築物後面看,所以軸越多,可以感測到的資訊就越完整。

一直生存在一維空間的生物,就像活在線上,他們只知道前後走,沒有左右的概念,一直生存在二維空間的生物,就像活在紙上,只知道前後左右走,沒有上下的概念,一直生存在三維空間的生物,不只可以前後左右走,還可以上下移動,能做的、能看到的東西都比一維、二維生物來的多,那四維空間的生物會看到甚麼?能做甚麼?這我也不知道,畢竟大部分的人都已經習慣三維空間了,要往高維度的空間去思考是困難的。

這裡以三軸陀螺儀、三軸加速度計、三軸磁力計和氣壓計做說明,首先要先了解三軸之間的關係,假設有三個向量 X、Y、Z,其方向分別為三個軸的方向,那這三個向量會互相垂直、正交(Orthogonality),也就像是 X dot product Y = 0 或 X cross product Y = Z,實心點垂直於螢幕出來,叉叉點垂直於螢幕進入,可以用右手定則來了解。



陀螺儀(Gyroscope or Gyro)

陀螺儀是測量角速度的元件,陀螺儀有短時間準確、靈敏的特性,但用來計算角度時,長時間下的誤差累積會使其變的不可靠,通常我們以 dps(degree per second)來表示角速度,角速度與速度不同,角速度是單位時間內旋轉的角度,而速度則是單位時間內移動的距離,所以若是沒有旋轉是沒有角速度的,若只對 X 軸旋轉,則 Y 軸與 Z 軸的輸出為 0,X 軸的輸出為旋轉的角速度。


下面一張圖是角度、角速度、角加速度的關係,紅線是角速度綠線是角加速度,角速度的一階微分,藍線是角度,角速度的一階積分,所以只要知道取樣時間以及角速度,就可以對其作積分得到當下的角度了。


但是實並非如此,原因就在於感測器都會有誤差與雜訊,如何把誤差與噪音雜訊給濾除掉也是一門學問,下面的數學式子表示從感測器讀到的角速度 w_measure 會等於矩陣 R_gyro 乘上理想的角速度 w_ideal 加上偏移 w_bias 與雜訊 n_noise,矩陣 R_gyro 包含未對準誤差(Misalignment)以及單位轉換(dps/LBS),若感測器與載具完全對準的情況(大部份安裝不准等情況會造成未對準誤差),矩陣 R_gyro 會是一個對角矩陣(Diagonal Matrix),偏移 w_bias、雜訊 n_noise 則由溫度、感測器內部等干擾引起。


理想的角速度 w_ideal 是我們想要的,所以校正的動作其實就是把 R_gyro、w_bias 與 n_noise 求出來並去除。


加速度計(Accelerometer or G-Sensor)

加速度計是測量加速度的元件,除了運動加速度外,也包含地球質量所產生的重力加速度,也就是當感測器自由落體時,運動加速度與重力加速度會剛好抵銷,有輸出都會變成 0,通常以 g 或是 m/s^2 來表示,因為可以感測到重力加速度,所以在有重力的環境中加速度計也常用來做傾斜計,透過重力在三軸上的投影來計算角度。

加速度計常常會搭配陀螺儀來應用,因為重力加速度並不會隨時間快速變化,長時間具有可靠性,所以通常透過此特性來較正陀螺儀,防止誤差的累積。

下圖是在靜止下(僅存在 1g 的重力加速度),不同角度的加速度計,角度 1~8 的 Z 軸因為垂直於重力加速度,所以皆為 0g,


角度 1 (    0 deg)的輸出(0, +g, 0)
角度 2 (  45 deg)的輸出(+0.707g, +0.707g, 0)
角度 3 (  90 deg)的輸出(+g, 0, 0)
角度 4 (135 deg)的輸出(+0.707g, -0.707g, 0)
角度 5 (180 deg)的輸出(0, -g, 0)
角度 6 (225 deg)的輸出(-0.707g, -0.707g, 0)
角度 7 (270 deg)的輸出(-g, 0, 0)
角度 8 (315 deg)的輸出(-0.707g, +0.707g, 0)

歸納出 → X = g*sin(theta), Y = g*cos(theta) → theta = atan(X / Y)

表示在 Z 軸垂直於重力時,輸出的 X, Y 值相除,並取 atan 則可以得到傾斜角度,但需要注意的,這僅限於靜止下,當有運動加速度的影響,得到的角度會是不準確的。

下面是一個加速度計的簡單數學模型,與陀螺儀類似(其實大家都長得差不多),加速度計的輸出 a_measure 會等於矩陣 K_accel 乘上理想的加速度 a_ideal 加上偏移 a_bias 與雜訊 n_noise,理想的加速度 a_ideal 包含運動加速度 a_motion 以及重力加速度 a_gravity,矩陣 K_accel 包含未對準的誤差以及單位的轉換(g/LBS),若感測器與載具完全對準的情況,矩陣 K_accel 也是一個對角矩陣,偏移 a_bias、雜訊 n_noise 則也會由溫度、感測器內部等干擾引起。



磁力計(Magnetometer or Compass

磁力計電子羅盤是用來測量磁場的元件,通常以高斯(Gauss)或特斯拉(Tesla)來表示磁場大小,因為地球本身存在磁場,所以磁力計可以藉由磁場在三軸上的投影來計算出航向角度,但事實上環境中的磁場不僅僅只有地球磁場,還包含了許多的干擾源,依特性可以分成硬磁(Hard Iron)干擾與軟磁(Soft Iron)干擾,硬磁干擾是像永久磁鐵、電池這些指固定強度的干擾,軟磁干擾則是指像電磁鐵、電量變化等,當磁力來源消失時,磁力會變弱,會改變磁力線強度或方向的干擾。

下圖是將以磁力計 X 軸與 Y 軸為座標在不同影響下畫出來的圖,紅色是理想、不受干擾的磁場,是一個圓心在原點的圓形,綠色是受到硬磁干擾的磁場, 也是圓形的磁場,但圓心會編離中心,深藍色是受到軟磁干擾的磁場,會讓圓形變形成橢圓形,但圓心仍在中心,淺藍色是同時受到硬磁與軟磁干擾的形況,偏離中心的橢圓形,這也是大部分磁力計測到的圖形,如果不校正成圓形的話,在行像的計算就會產生誤差,導致問題出現。


下面是一個磁力計的簡單數學模型,磁力的輸出 h_measure 會等於矩陣 M_mag 乘上理想的磁場 h_ideal 加上偏移 h_bias 與雜訊 n_noise,矩陣 M_mag 包含未對準的準誤、單位的轉換(gauss/LBS)、硬磁干擾、軟磁干擾,偏移 h_bias、雜訊 n_noise 則也會由溫度、感測器內部等干擾引起。




氣壓計(Barometer)

氣壓計是用來測量氣壓的元件,通常使用帕(Pa)或百帕(hPa)來表示,一個大氣壓力大約是 1013.25 hPa,大氣壓會隨著高度的提升而下降,其關係為每上升 9 公尺,大氣壓力降低 100 Pa,透過此關係可以使用氣壓計計算出目前的海拔高度,以目前 MEMS 氣壓計可以做到 1 Pa RMS 的高解析度情況下,大約可以檢測到 9 公分的高度變化,但這都在是比較理想的情況下,實際上還會有空氣的流動、溫度與濕度的影響,使得計算、測量的誤差產生。



詳細的感測器校正方法之後會再說明,這一章只先說明感測器的一些原理與模型。

下面這篇文章也值得參考:
A Guide To using IMU (Accelerometer and Gyroscope Devices) in Embedded Applications
http://www.starlino.com/imu_guide.html

下一篇→從零開始做四軸 (六) - 數學模型

2015年10月3日 星期六

[QCopter] 從零開始做四軸 (四) - 飛行器組成

一台可以操作的簡單四軸飛行器大致架構如下,由兩對正反槳、四顆無刷馬達、四個電子調速器、一顆電池、一個飛行控制以及一個接收機與遙控器所組成,這裡不探討額外的設備像是 GPS、FPV 等裝置。



四軸飛行器機身(Frame)

用來放置控制器、馬達、電池…等等的平台。通常我們會用對角馬達的軸距(M2M)來敘述機身的大小,如果對角馬達的兩個轉軸相距 250mm 的距離,則稱為 250 機身。

機身的大小,會影響螺旋槳的長度與馬達的選擇,進而影響到負載的大小,而機身的剛性(Stiffness),也會影響到馬達所產生的震動大小以及運動效能方面的影響。

Thingiverse 上的一個 250 機身的 3D 模型:http://www.thingiverse.com/thing:34552

 


螺旋槳(Propeller)

安裝在馬達上,並透過馬達旋轉來產生推力的裝置。四軸中有兩對螺旋槳,一對螺旋槳順時針旋轉,另一對螺旋槳則是逆時針旋轉,並不是所有螺旋槳都一樣的,所以在購買的時候都會選擇正反槳。通常會用像 1045 或 10x4.5 的方式來分別不同規格的螺旋槳,其意思為直徑10 inch,螺距 4.5 inch。

在相同轉速下,螺旋槳越長,攻角越大,所提供的升力就越大,但所受到的阻力亦會越大,所以轉動大的槳需要扭力大的馬達。

 


無刷馬達(Brushless DC, BLDC)

轉動螺旋槳的裝置,與有刷馬達相比,無刷馬達具有扭力大、低耗損的優點,但由於其結構設計,必須加上一些電路與較為複雜的方法控制(換相),線圈的匝數,會影響到馬達的扭力與轉速,匝數越多扭力越大、轉速越低;匝數越少,扭力越小、轉速越快。

通常會使用 KV(No-load rpm per volt) 來表示一顆無刷馬達的匝數,KV 值表示電壓每升高 1V,空載轉速增加的數值,KV 越小匝數越多,KV 越大匝數越少,所以大的螺旋槳通常都會搭配低 KV 的馬達,小的螺旋槳會搭配高 KV 的馬達。

 


電子調速器(Electronic Speed Controller)

用來驅動無刷馬達的裝置,藉由此裝置可以簡化無刷馬達的控制,通常市售的電調只需輸入 PWM,並透過調整 PWM 的占空比即可控制無刷馬達轉速,但也有像是 I2C、CAN Bus 等方式控制的電子調速器。

 


鋰聚電池(Lithium polymer battery, Li-Po Battery)

提供控制板與馬達電源的來源,鋰聚合物本身的化學材料特性在正負極的跨壓大約 3.3~4.2V左右,使的單節(one cell)鋰聚電池的電壓平均大約為 3.7V 左右,若串聯兩節鋰電池,則有 7.4V 的電壓,我們通常會用 11.1V 3S 2200mAh 25C/35C,  來敘述一個鋰聚電池的規格,其表示輸出 11.1 V 電壓、最大放電 25C(2.2 * 25 = 55A)、瞬間放電 35C(2.2 * 35 = 77A)。

其實鋰聚電池雖然是一個很棒的電源來源,但從上速規格的電池,瞬間輸出可以達到 77 安培的電流,當電池充飽後瞬間輸出功率快達到 1000W,在安全性上面不容小覷,使用上需要小心,下面有一個影片在實驗不同外力下鋰聚電池的冒煙、膨脹、燃燒等情況。

Youtube - Lipo battery combustion test鋰聚合物(手機)電池燃燒實驗 by RC Mania
https://www.youtube.com/watch?v=eZxDC-whz14

 


飛行控制器(Flight Controller)

控制飛行器平衡、運動的裝置,這裡簡稱飛控板,飛控板是一個集成微控制器、感測器... 等的裝置,以人來比喻,就像是大腦和中樞神經,絕大部分的訊息都在這裡做處理,這也是四軸飛行器的核心控制部分。

 


遙控器(Remote Controller)

遙控飛行器、給予飛行器控制指令的裝置,需要與接收機做搭配傳輸訊號。

 


2015年10月1日 星期四

[QCopter] 從零開始做四軸 (三) - 運動原理

四軸飛行器具有以下優點:

1、體積小、重量輕

2、機構簡單
四軸飛行器與直升機最大的不同處在於,直升機透過主旋翼的傾斜與葉片攻角來實現不同的運動,並且靠尾旋翼來抵銷主旋翼產生的反作用力,這種設計使得直升機的機構較為複雜,同時當主旋翼無法工作時即無法飛行,產生升力,而四軸飛行器則透過四個旋翼來互相抵銷反作用力,並且透過不同的升力,來實現不同的運動,詳細會面會在說明,下面有一個影片,可以告訴你四軸飛行器的結構可以多簡單。

Youtube - diy drone it yourself v1 0
https://www.youtube.com/watch?v=TQhHO7UvazA

影片中可以看出來,飛行器只需要四個螺旋槳,放置間距與位置不要太誇張,基本上都可以平衡與飛行,一個四邊對稱的機構(正方形)與非對稱的機構(這裡指的是非正方形,像是梯形、長方形、平行四邊形)差別僅在於飛行器的模型複雜程度,將對稱機構的模型用在非對稱的機構上只是容易在控制上產生誤差,說白了就是不容易達到你想要的結果,非對稱的程度越大、就越效果就越差,所以大部分的四軸為了在控制上簡單,通常都會使用對稱的機構來簡化控制上的問題。

3、機動性高
下面有一個影片,可以告訴你四軸飛行器機動性如何,最高時速應該有超過 100 km/hr。

Youtube - minicp120 x2208 2000kv 6x4.5 hqprop kiss esc 18a nanowii 4s1800 40c
https://www.youtube.com/watch?v=8p5uDf9i_Yc

RC Groups - quadmovr's blog
http://www.rcgroups.com/forums/member.php?u=534985

4、演算法核心
並不是說其他都不重要,機構、螺旋槳等都會影響飛行器的效能,只是合理設計的簡單機構、螺旋槳等即可提供一個穩定飛行的平台,所以飛控板上的核心演算法就成主宰飛行器運動與平衡的主要部分,而任何的應用實現也在於此部分,這個人認為也是在學術上的一個研究優勢。


四軸飛行器飛行的原理:

飛行器的螺旋槳配置示意圖如下圖的左上角所示(本文默認使用 "x" 形配置,而非 "+" 形),兩兩對角的螺旋槳轉向剛好相反,透過這種配置,來互相抵銷旋轉上的力矩,在已經平衡的情況下,同時增加或減少四個旋翼的推力的話,可以做出上升與下降的動作,同時增加或減少相鄰的兩個旋翼的推力,可以做出前後左右運動的動作,若同時增加或減少對角旋翼的推力時,則可以做出順逆時針旋轉的動作,而任何的飛行運動都可以由上升、下降、前後左右、順逆時針旋轉的運動所組成。



2015年9月28日 星期一

[QCopter] 從零開始做四軸 (二) - 相關資訊


在說原理之前,要先了解知道四個螺旋槳的飛行器的中文、英文名稱,有助於找資料或文獻,中文說法大致有這些,四旋翼、四旋翼飛行器、四軸飛行器甚至是四軸,英文的話則是 Quadcopter、Quadrotor、Quadrocopter、Quadrotor Helicopter ...等等,可以 Vertical Take-Off and Landing(VTOL)的旋翼飛行器,其實就只是在強調有四個螺旋槳的直升機而已。

Wikipedia - Quadcopter 上看到,最初的四軸飛行器是在 1907 由 Louis Breguet 設計的(天知道是真是假,有興趣自己去考證吧),假設訊息無誤的話,到現在也有百年的歷史了。

近十年的四軸飛行器發展迅速成長,個人認為很大部分都歸功於微機電(MEMS)與積體電路製程技術的提升,從原本高成本、大體積的感測器變成幾微米、低成本的 IC,使得飛行器體積縮小、造價降低,才得以廣泛研究。(此部分為個人想法,若有誤可以提出來)

第一次看到四軸相關的研究是 2012 年 Vijay Kumar 教授在 TED 上的演說,也是我開始做四軸的時候,Vijay Kumar 教授任教於美國的賓州大學,他的實驗室也做了很多有趣的東西。


Vijay Kumar 教授:http://www.kumarrobotics.org/
GRASP 實驗室:https://www.grasp.upenn.edu/




與 Lexus 合作的影片
Amazing in Motion - 'Swarm' https://www.youtube.com/watch?v=5ofbd05pKuA

幕後花絮
Swarm : 'Crafting Motion' https://www.youtube.com/watch?v=noyXqbqYyJo



之後也有另一位教授在 TED 上演講四軸飛行器,任職於瑞士蘇黎世聯邦理工的 Raffaello D'Andrea 教授,不過知名度似乎是這位教授較高,可能觀眾靠的比較近印象比較深刻吧... 哈哈。





也有與太陽馬戲團合作的影片,感覺這種合作方式頗不錯的,可以增加資金、增加研究內容、同時也增加知名度。

SPARKED: A Live Interaction Between Humans and Quadcopters

幕後花絮 SPARKED: Behind the Technology


Raffaello D'Andrea 教授也做了很多有趣的專案,其中印象最深刻的是叫 Cubli 的專案,透過角動量平衡,這種技術在很多機器人平衡上都會用到。


還有很多影片沒有放上來,因為真的是太多了,只放舊一點的影片,有興趣可以自己找找,最後,看了這麼多,其實只是想說明,四軸不是只能拿來空拍而已...,兩間頂級大學的研究室研究的東西真的很好,值得學習,想研究相關方向的人,可以多看兩間實驗室所發表的學術論文,畢竟已經累積了幾十年的成果。


"從零開始做四軸"除了是記錄自己的過程,方便自己再查閱,同時也提供分享給想研究四軸的人、想自己做一台而不是裝一台四軸的 Maker,這裡的 Maker 指的是了解電路、焊接、寫微控制器等多領域的人,畢竟一台四軸飛行器是跨了許多領域的結晶,像是控制、電子電路、數位邏輯、程式語言、機構、數學、物理、運動學 ... 等等,已經數不勝數了,還有最重要的"藝術"!沒錯,就是藝術!


以下有幾個 Github 上不錯的開源專案:

使用空心杯馬達(微型四軸)

使用無刷馬達

值得參考的資訊:
Build A Quadcopter From Scratch – Hardware Overview

2015年9月26日 星期六

[QCopter] 從零開始做四軸 (一) - 構想


說是從零開始做四軸其實也不太算,因為之前已經做過,

很久了,對四軸的最初印象是在寶萊塢電影"三個傻瓜"裡,但有想做的想法應該是2011年(大二下)時,在自控社辦跟其他朋友討論比賽可以拿甚麼作品參加,當時打算做一個可以作室內規劃路徑與空間定位的四軸,不過說歸說,比賽也沒參加,最後自己也跑去玩 FPGA、學計組,忘記甚麼原因,2012年(大三下)打算跨系參加電機系的專題競賽,就把這個想法再搬出來,最後實作一年的結果離一開始預期的功能相當遙遠,但在物理系背景下,看了不少書與不斷 try & error 的調 PID,一年內還是可以做出一台免強平衡的四軸,

之前做的四軸,詳細可以參考下面連結
GitHub Quadcopter
[QCopter] 自製四軸飛行器

從陽春的洞洞板做起,自己設計電路、焊接、驅動、通訊、姿態算法、平衡控制,到之後把洞洞版本的飛控板、遙控器設計成 PCB 版本送廠打樣,不斷的改版,不斷的更新,當時就有想做一台全部自己設計的四軸飛行器,從最基本的機構、算法到電調、飛控、遙控器等(馬達、電池、螺旋槳就算了),一台全部開源、適合做研究、學習、實現演算法的四軸飛行器 QCopter

最初的構想是以小型四軸加上無刷馬達為主,而且馬達、螺旋槳需要取得容易,所以設計了一台 160mm 軸距的四軸,雖然設計圖畫好,但口袋一直空空,一直沒有試過... 畢竟買一個商品價格跟開發一個的成本是天差地遠。



雖然到現在已經過了快兩年了,不過一個人要做完全部還是需要不少時間的,可能幾年後才有機會面市吧... 哈哈,反正先把之前與現在的構想紀錄下來,一步一步的實現。

以研究與學習方面,以下幾點是設計的考量:
  • 硬體、軟體、基本演算法必須開源,方便模仿、學習、修改、重製。
  • 製作成本與門檻盡量低,以具備基本手做能力與開發能力的對象為主。
  • 一個高效能、資源豐富的控制器對實現演算法的可能性與種類有很大的幫助。
  • 飛行器先以小型、室內為主,減少危險以及增加開發、實驗方便性(坐著也可以開發)。
  • 容易擴充、新增硬體、應用,畢竟研究、學習也是要跟上時代的。
  • 演算法相關的有數學流程與軟體模擬更好。

下面是 QCopter 預計要實現的部分,目前先以飛行器和遙控器這兩部分為主。



飛行器部分:
打算以 200mm 軸距與 5-inch 的槳為主,與之前設計大了些,但相對的負載也增加了,在飛行器底下預留相機腳架的接口,方便連接攝影用萬向雲台,使在調整參數與測試時的難度減少、便利性增加,另外會設計一個 2 維的雲台來固定 QCopterMV。

飛控板 QCopterFC
實現運動、平衡方面的演算法,最重要的核心裝置,上面裝載 SmartIMU 與 SmartBLE,SmartBLE 尚未設計,天線與功率放大部分尚在實驗,預計以 nRF51 或 nRF52 系列做為主控器,主要用來做 BLE 或 2.4G 傳輸,目前預計透過 CAN Bus 來做為 QCopterESC 與 QCopterPM 之間的溝通方法,但沒用過 CAN Bus 所以可行性還未知。

電子調速器 QCopterESC
驅動無刷馬達的裝置,預計採用 Field Oriented Control (FOC) 技術,透過採樣電流來找出轉子位置做控制,並且可以回授轉速、電流、溫度等資訊到 QCopterFC 和 QCopterPM 上面,基本功能都有完成的話,再加入自適應控制,可以自動補償電機參數。

電源管理 QCopterPM
飛行器的電源管理裝置,除了管理、監控與檢測飛行器上的電池電量、用量、電流與狀況外,也打算具備無線充電的功能。

機械視覺 QCopterMV
實現影像處理的裝置,預計採用 MT9V034 攝像頭,具有灰階與彩色兩種版本,可以針對不同的處理需求做替換,實現光流、特徵辨識等演算法。


遙控器部分:

遙控器 QCopterRC
遙控飛行器的裝置,最重要的是具有螢幕,可以直接將飛行器上回傳的資料顯示出來,遙控器上打算加入加速度計與陀螺儀,用來實現體感控制。


地面站:

地面站 QCopterGS
這部分偏向室外的應用,室內的部分預計以矩陣燈搭配影像處理為主(如下述的應用),其實在想室內的部分要不要分出來,畢竟不太像地面站。



目前有幾個想實現的四軸應用:

空間定位
這是最一開始想做的,可靠的實現方法都是加載高速攝影機,但這缺點就是照價高,自己打算以低成本的 IMU / RSSI 方案來實現飛行器的空間定位,因為室內定位也是自己的研究的題目,所以這部分已算是進行中了,整個最大的難點應該是飛行器產生的噪音與干擾,誤差若可以在限制在 30cm 內覺得就很不錯了。

飛行器間通訊
之前過一篇透過聲波傳遞訊息的病毒 badBIOS (詳細文章),除了RF,聲波確實是一個非常有效的交換訊息方法,每天都在說話,每天都在用嘴巴和耳朵傳遞與接收訊息,但在飛行器上自己卻常常忽略,若是飛行器有聽與說的能力,那在協同合作方面的肯定會有許多應用。

最直覺的想法是喇叭和麥克風,喇叭依照想傳遞的範圍傳出不同頻率與振幅的訊號來夾帶資料,若只要濾除螺旋槳聲,整體難度應該不大,但真的想做看看的是自己的指導教授隨口講的一個想法,透過螺旋槳或馬達轉速來發出不同頻率的聲音,跟電調讓無刷發聲的概念類似,若資訊量不大應該是不會影響到平衡和飛行,而且也可以有效的減少成本。

飛行器導引
這是之前參加比賽所想的一個慨念,最初的想法是結合GPS在不同的塔台間自動的移動與起降,主要是為了降低和解決飛行器續航力不足的問題,塔台透過矩陣燈與飛行器上的機械視覺來實現起降定位的功能,不過之後想到了一個延伸的有趣應用,一組矩陣燈可以用來傳遞訊息給飛行器,實現上下運動甚至空翻的指令,若多組的矩陣燈,就可以讓飛行器前後左右移動,或許意義不大,但在室內展示上卻有不錯的視覺效果,藉由電腦來控制矩陣燈圖案,就可以讓飛行器依自己想走的路徑運動或是做出特定動作。


下一篇→從零開始做四軸 (二) - 相關資訊

2015年9月3日 星期四

[C語言] 在 Windows 上透過 C 語言實現 RS232 接收和發射

最近單晶片需要用到 IAP 的功能(可以參考基於 STM32 的 IAP 程式更新),不過之前電腦端是透過自己寫 Python 實現 .bin 檔案的傳輸,有時候重灌電腦後 Python 就被刪掉了,之後後還要再找符合相對應版本的 pySerial,蠻麻煩的,所以就想說直接用 C 語言來取代之前寫的 Python 功能。

STEP 1
先下載 RS232 for Windows Librery → http://www.teuniz.net/RS-232/
將 RS-232.tar.gz 解壓縮,只需要 rs232.c 和 rs232.h 即可。


STEP 2
建立一個 C 語言的專案,來撰寫程式,個人是使用 Code::Blocks



選擇 Empty project 即可




新增一個 .c 檔,存在專案目錄下,
我是命名成 main.c,然後加入 main.c, rs232.c rs232.h 到專案。





在 main 裡面加入 #include "rs232.h" 後,就可以使用 rs232 library 的功能了

STEP 3
下面程式是 main.c 裡面寫的內容,做簡單的字串接收並顯示出來,
另一端用自己設計的開發板 RedBeanSprout 實現,一直發送 5 個不同的字串到電腦。

#include "rs232.h"

#define RECV_BUF_SIZE 5

int main()
{
    int state = 0;

    int com_port = 6;       /* COM7 */
    int baudrate = 115200;  /* 115200 */
    char mode[]  = {'8', 'N', '1', 0};

    int i = 0, n = 0;
    unsigned long count = 2000000;

    unsigned char recv_buf[RECV_BUF_SIZE + 1] = {0};

    /* Open COM Port */
    state = RS232_OpenComport(com_port, baudrate, mode);
    if(!state)
        printf("Open COM Port Success\n\n");

    /* Recv Data */
    do {
        n = RS232_PollComport(com_port, recv_buf, RECV_BUF_SIZE);
        if(n == RECV_BUF_SIZE) {
            printf("count = %7i, n = %i, recv data = ", count, n);
            recv_buf[n] = '\0';
            printf("%s", (char *)recv_buf);
        }
        else if(n > 0) {
            printf("count = %7i, n = %i, recv data = ", count, n);
            printf("*****\n");
        }
       Sleep(1);
    } while(--count);

    /* Close COM Port */
    RS232_CloseComport(com_port);
    printf("\nClose COM Port\n");

    return(0);
}

發射部分使用 RS232_SendByte 或 RS232_SendBuf 就可以了,
這邊沒有放上來測試,主要是因為官網都已經解釋得很詳細了。

使用 C 語言來做 RS232 的好處主要在於可以有更多的變化,像是傳檔案、模擬部分 UART 裝置等,不像終端機只能做字串或字元的傳輸。

最後完整的專案可以在 github 上下載
https://github.com/Hom-Wang/C-Language/tree/master/serial