2013年6月23日 星期日

[QCopter] 自製四軸飛行器



101年跨修電機系的大學專題,從零開始做了一年的成果,
花了很多的時間,也噴了很多錢,但結果很值得。


目前四軸飛行器可以達到平衡→就是不會摔下來
但無法保持懸停→沒辦法保持在原點不動,會自己飛來飛去的

簡單的講解一下

一個可以操作的四軸飛行器有以下部分:
.機架 → 放置電池、馬達、飛行控制器 ... 等等。... 使用450機架
.電池 → 供電給整個系統。... 使用 2200mAh 25C 鋰電池
.馬達 → 使用無刷馬達,用來提供升力。... 使用 2212 980KV 無刷馬達
.螺旋槳 → 採用正反槳,用來提供升力。... 使用 1045 碳纖混槳
.遙控器 → 操做四軸飛行器及顯示回傳資料。... 自製遙控器
.電子調速器 → 簡稱電調,用來驅動無刷馬達。... 好盈 40A 電調
.飛行控制器 → 簡稱飛控板,做平衡及無線傳輸。... 自製飛控板

遙控器:
.控制器:STM32F407VG
.顯示器:4.3吋屏,SSD1963
.無線傳輸:nRF24L01P + PA + LNA

飛控板:
.控制器:STM32F405RG
.感測器:L3G4200 + LSM303
.無線傳輸:nRF24L01P + PA + LNA

大致的流程:
.MCU的韌體與軟體初始化
.感測器的初始校正 → 電子羅盤使用橢圓擬合
.讀取感測器 → 感測器包含了加速度計、陀螺儀、電子羅盤
.將讀到的資料作濾波 → 使用加權移動平均與互補濾波
.計算當下姿態 → 計算頻率400Hz,採用四元數
.平衡控制 → 計算頻率400Hz,使用PID的PD控制

↓自己做的飛行控制器,買現成的模組&自己洗的MCU,焊在洞洞板上

↓自己做的遙控器,主畫面,右邊是油門

↓顯示的是3D的DEMO程式

↓示波器功能,把飛行器上傳回來的資料顯示出來


↓遙控器說明影片 youtube


更多的相片
PICASA 四軸飛行器相簿

GitHub
GitHub Quadcopter-V1.0

2013年5月29日 星期三

[STM32] 基於 STM32 的 IAP 程式更新

  In Application Programing (IAP),顧名思義就是可以在運行程式時,更新程式。像是手機就是最好的例子,僅需要下載更新程式,不需要送回原廠燒錄,就可以更新手機上的程式了,但要使用這種方法,裝置必須要具備可以程式讀寫裝置上的 ROM 的功能,像是 FLASH。

  以意法半導體 (STMicroelectronics) 公司所出產的 STM32 系列為例,搭配自己設計的開發板來實現 IAP 的功能。

運作原理:
  程式分 BOOTLOAD 以及 USER 兩部分,BOOTLOAD 負責接收、讀取編譯後的 bin 檔案,並將 bin 檔案寫入已知 FLASH 起始地址的 USER 部分,並跳耀至該 FLASH 地址執行,若啟動時不需更新程式,則直接跳至 USER 起始地址執行,不更新該段程式碼。





實際實現:
  實際使用 STM32F103CBT,擁有 128KBytes 的 FLASH,一頁訂為 1KBytes,共分成 128 頁,FLASH 的起始位置為 0x8000_0000。bootloadSize 設定為 12KBytes,所以實際 USER 可以使用的大小 userSize + un-Use 為 116Kbytes,STM32 的 Bootloader 透過 UART 從電腦下載及接收 bin 檔案,電腦端使用自己所撰寫的 Python 程式,可以讀取 bin 檔案,並透過 UART 傳送至 STM32 上面,當 STM32 確定要更新程式,則會從電腦端讀取 bin 檔案,並更新至已知的 USER 起始位置 0x8000_0000 + bootloadSize,寫入完成則跳至該 FLASH 起始地址上執行。




相關資料
GitHub BSR_IAP

2013年3月30日 星期六

[Algorithm] 高斯消去法 解線性方程組

最近在校正電子羅盤,需要解線性方程組,在 MATLAB 上求反矩陣很容易,但要在單晶片上實現就變得麻煩了,所以就寫了個高斯消去法,來求解線性方程組的解。

高斯消去法過程很直覺,先將左下三角消成 0,在將中間對角線消成 1,最後將右上三角消成 0,此時方程組之解就在矩陣最右邊,詳細說明可以參考 高斯消去法 | 線代啟示錄

目前沒有加入 nonsingular matrix 的判斷,當方程組有多個解或無解時,此程式會有問題,所以正確的方法應該要在運算前判斷矩陣是否非奇異。

/* 高斯消去法 Gaussian Elimination */
int8_t GaussianElimination( uint8_t col, uint8_t row, float *arr )
{
  float tmp;
  int8_t i = 0, j = 0, k = 0;

  /* check nonsingular */
  // if matrix is nonsingular
  // return ERROR;

  /* left-down to zero */
  for(i = 0; i < col; i++) {
    for(j = i + 1; j < row; j++) {
      for(k = col; k > i - 1; k--) {
        arr[j*row+k] = arr[j*row+k] - arr[j*row+i] / arr[i*row+i] * arr[i*row+k];
      }
    }
  }

  /* diagonal to one */
  for(i = 0; i < col; i++) {
    tmp = arr[i*row+i];
    for(j = i; j < row; j++) {
      arr[i*row+j] = arr[i*row+j] / tmp;
    }
  }

  /* right-up to zero */
  for(j = row - 2; j > 0; j--) {
    for(i = 0; i < j; i++) {
      arr[i*row+row-1] = arr[i*row+row-1] - arr[i*row+j] * arr[j*row+row-1];
    }
  }

  return SUCCESS;
}

/* 主程式 */
#define col_n 4
#define row_n 5

float arr[col_n][row_n] = {
  {1.0f,3.0f,-5.0f,2.0f, 94.0f}, // 1*x1 + 3*x2 - 5*x3 + 2*x4 =  94
  {4.0f,-3.0f,1.0f,5.0f, 58.0f}, // 4*x1 - 3*x2 + 1*x3 + 5*x4 =  58
  {6.0f,-2.0f,2.0f,4.0f, 72.0f}, // 6*x1 - 2*x2 + 2*x3 + 4*x4 =  72
  {0.0f,2.0f,3.0f,-7.0f, -69.0f} // 0*x1 + 2*x2 + 3*x3 - 7*x4 = -69
};

int main()
{
  uint8_t i = 0;
  float *ptr = arr;

  GaussianElimination(col_n, row_n, arr);

  for(i = 0; i < col_n; i++) {
    printf("%.1f\n", ptr[i*row_n+(row_n-1)]);
  }
}