實驗介紹
手機上的“重力感應”想必大家都不陌生,基于重力感應可以實現飛車、輔助瞄準等各種體感非常強的交互功能。所謂的“重力感應”,其實就可以使用“加速度計及陀螺儀傳感器”來實現。 本節實驗中,我們將會基于 MPU-6050 實現一個根據開發板姿態滾動的小球。當我們傾斜 HaaS EDU K1 時,會看見小球根據我們的傾斜方向發生相對應的偏移。
涉及知識點
MPU-6050 的驅動和使用
OLED繪圖
開發環境準備
硬件
開發用電腦一臺
HAAS EDU K1 開發板一塊
USB2TypeC 數據線一根
軟件
開發環境的搭建請參考《AliOS Things集成開發環境使用說明之搭建開發環境》,其中詳細的介紹了AliOS Things 3.3的IDE集成開發環境的搭建流程。
本案例的代碼下載請參考《AliOS Things集成開發環境使用說明之創建工程》,
> 選擇解決方案:“HaaS EDU K1教育開發案例合集”
> 選擇開發板:haaseduk1 board configure
-- 編譯固件可參考《AliOS Things集成開發環境使用說明之編譯固件》。
-- 燒錄固件可參考《AliOS Things集成開發環境使用說明之燒錄固件》。
硬件介紹 - MPU-6050
DataSheet
了解一款IC最快捷和精準的方法是查閱它的DataSheet。這款IC的DataSheet可以在以下鏈接獲取。
硬件規格
MPU-60X0是世界上第一款集成 6 軸MotionTracking設備。它集成了3軸MEMS陀螺儀,3軸MEMS加速度計,以及一個可擴展的數字運動處理器 DMP( DigitalMotion Processor),可用I2C接口連接一個第三方的數字傳感器,比如磁力計。 MPU-6050具有三個用于將陀螺儀輸出數字化的16位模數轉換器(ADC)和三個用于將加速度計輸出數字化的16位ADC。 為了精確跟蹤快速和慢速運動,這些部件具有用戶可編程的陀螺儀滿量程范圍,范圍為±250,±500,±1000和±2000°/ sec(dps),以及用戶可編程的加速度計滿量程范圍,范圍為±2g,±4g,±8g和±16g。使用400kHz的I2C與設備的所有寄存器進行通信。其他功能包括嵌入式溫度傳感器和片上振蕩器,在整個工作溫度范圍內誤差±1%。 更多硬件規格請參考 DataSheet。
傳感原理
陀螺儀由1850年法國物理學家萊昂·傅科在研究地球自傳中獲得靈感而發明出來的,類似像是把一個高速旋轉的陀螺放到一個萬向支架上,靠陀螺的方向來計算角速度,和現在小巧的芯片造型大相徑庭。
| |
早期的機械陀螺儀[1] |
那么如何將這么龐大的機械設備,塞進小小的芯片當中呢?以目前廣泛使用的MPU-6050為例,它屬于傳感MEMS分支。傳感MEMS技術是指用微電子微機械加工出來的、用敏感元件如電容、壓電、壓阻、熱電耦、諧振、隧道電流等來感受轉換電信號的器件和系統。感興趣的同學可以來這里學習亞德諾半導體的公開課 —— MEMS傳感器2:加速,旋轉——陀螺儀工作原理。 我們使用的MPU-6050是一款經典的MEMS陀螺儀,即硅微機電陀螺儀。MEMS(Micro-Electro-Mechanical System)是指集機械元素、微型傳感器、微型執行器以及信號處理和控制電路、接口電路、通信和電源于一體的完整微型機電系統。絕大多數的MEMS陀螺儀依賴于相互正交的振動和轉動引起的交變科里奧利力。在MPU-6050內部,存在一質量塊,當器件上電后,會觸發質量塊以固定頻率橫向運動。當器件遭受外力具備加速度時,就會觸發質量塊的縱向運動,從而改變四周梳齒之間的距離,改變輸出的電容,進而通過ADC將模擬信號轉換為數字信號,輸出給外部[2]。
原理圖
在原理圖中我們可以看出,器件使用I2C通訊接口。并且,器件支持使用過INT引腳,當數據到來時可以在該引腳上觸發中斷。需要注意的是,AD0引腳決定了器件地址的第 0 bit。當AD0連接高電平,即AD0 = 1,此時器件地址為0x69。
驅動方式
通訊接口
由DataSheet可知,MPU-6050采用的通訊方式為I2C。默認7bit設備地址:0x69 (DataSheet P33 9.2) 在 AliOS Things 3.3中,I2C操作方式采用VFS的方式,開發者只需要關心器件的設備地址即可,因為只要知道了設備地址,讀寫地址也可以計算出,AliOS Things 會自動處理這些計算。如果我們需要為了 MPU-6050 初始化I2C接口,那么對應的代碼為:
// solutions/eduk1_demo/drivers/sensor/drv_acc_gyro_inv_mpu6050.c
// 初始化I2C
int32_t ret = sensor_i2c_open (MPU_I2C_PORT, MPU_ADDR, I2C_BUS_BIT_RATES_100K, 0);
if (ret) {
LOGE("SENSOR", "sensor i2c open failed, ret:%d\n", ret);
return -EIO;
}
寄存器
一般,使用I2C通訊的器件,都是通過讀寫寄存器的方式來完成對設備的讀取和配置,因此了解寄存器的分布就非常重要。由于 MPU-6050 的寄存器數量較多,建議讀者們查閱 Regsiter Map 文檔來獲取這些信息。我們進列出部分較為關鍵的寄存器。
0x3B-0x40 三軸加速度寄存器,每軸數據2Byte 0x41-0x42 溫度寄存器,2Byte 0x43-0x48 三軸陀螺儀寄存器,每軸數據2Byte
驅動實現
uint8_t MPU_Init(void)
器件初始化。
// solutions/eduk1_demo/drivers/sensor/drv_acc_gyro_inv_mpu6050.c
uint8_t MPU_Init(void)
{
uint8_t device_id = 0;
MPU_Write_Byte(MPU_PWR_MGMT1_REG, 0X80); // 復位MPU6050
aos_msleep(100);
MPU_Write_Byte(MPU_PWR_MGMT1_REG, 0X00); // 喚醒MPU6050
MPU_Set_Gyro_Fsr(3); // 陀螺儀傳感器,±2000dps
MPU_Set_Accel_Fsr(0); // 加速度傳感器,±2g
MPU_Set_Rate(50); // 設置采樣率50Hz
MPU_Write_Byte(MPU_INT_EN_REG, 0X00); // 關閉所有中斷
MPU_Write_Byte(MPU_USER_CTRL_REG, 0X00); // I2C主模式關閉
MPU_Write_Byte(MPU_FIFO_EN_REG, 0X00); // 關閉FIFO
MPU_Write_Byte(MPU_INTBP_CFG_REG, 0X80); // INT引腳低電平有效
device_id = MPU_Read_Byte(MPU_DEVICE_ID_REG);
if (device_id == MPU_DEV_ID) {
// 器件ID正確
LOGI("SENSOR", "MPU init OK\n");
MPU_Write_Byte(MPU_PWR_MGMT1_REG, 0X01); // 設置CLKSEL,PLL X軸為參考
MPU_Write_Byte(MPU_PWR_MGMT2_REG, 0X00); // 加速度與陀螺儀都工作
MPU_Set_Rate(50); // 設置采樣率為50Hz
} else {
LOGE("SENSOR", "MPU init Error -- %x\n", device_id);
return 1;
}
return 0;
}
void MPU_Get_Gyroscope(short gx, short gy, short *gz)
讀取三軸陀螺儀數據。由Register Map得知,只需要從GYRO_XOUTH向后依次讀出6個寄存器內容即可。
void MPU_Get_Gyroscope(short *gx, short *gy, short *gz)
{
uint8_t buf[6];
MPU_Read_Len(MPU_GYRO_XOUTH_REG, 6, buf);
*gx = ((u16)buf[0] << 8) | buf[1];
*gy = ((u16)buf[2] << 8) | buf[3];
*gz = ((u16)buf[4] << 8) | buf[5];
}
void MPU_Get_Accelerometer(short ax, short ay, short *az)
讀取三軸加速度數據。由Register Map得知,只需要從ACCEL_XOUTH向后依次讀出6個寄存器內容即可。
// solutions/eduk1_demo/drivers/sensor/drv_acc_gyro_inv_mpu6050.c
void MPU_Get_Accelerometer(short *ax, short *ay, short *az)
{
uint8_t buf[6];
MPU_Read_Len(MPU_ACCEL_XOUTH_REG, 6, buf);
*ax = ((u16)buf[0] << 8) | buf[1];
*ay = ((u16)buf[2] << 8) | buf[3];
*az = ((u16)buf[4] << 8) | buf[5];
}
應用開發
本實驗的應用較為簡單,只需要讀出加速度數據,并顯示在屏幕上即可。OLED的相關接口中已經給出了豐富的繪圖函數。具體實現如下。
void gyroscope_task(void)
{
while (1)
{
// 清除屏幕memory
OLED_Clear();
// 獲取三軸加速度信息
MPU_Get_Accelerometer(&r_ax, &r_ay, &r_az);
// 畫出固定的圓形邊框
OLED_DrawCircle(66, 32, 10, 1, 1);
// 畫出填充的圓
OLED_FillCircle(66 - r_ax / 250, 32 + r_ay / 500, 8, 1);
// 將屏幕memory顯示出來
OLED_Refresh_GRAM();
// 暫停20ms
aos_msleep(20);
}
}
更多應用
本實驗展示的僅是六軸傳感器的一個非常簡單的應用。隨著類似傳感器的體積越來越小,精度越來越高,它們也被應用在各種消費類電子產品,如穿戴設備、手機上。 使用它們可以進行一些非常有趣的應用,例如,手環中經常會使用到的計步算法,運動狀態檢測算法,都是基于其中的六軸傳感器數據。近年來,還有很多學術界的工作,使用手環中的六軸傳感器來實現空中寫字的識別。 除此之外,它也廣泛應用于輔助定位、飛行設備的姿態檢測,攝像機云臺的水平保持等等。期待讀者們能夠發掘出更多有價值的使用場景。
引用
[1] Gyroscope invented by Léon Foucault in 1852. Replica built by Dumoulin-Froment for the Exposition universelle in 1867. National Conservatory of Arts and Crafts museum, Paris. By Stéphane Magnenat - Own work by uploader, subject public domain, Public Domain, https://commons.wikimedia.org/w/index.php?curid=4302903[2] 圖片來自 https://www.analog.com/cn/education/education-library/videos/5996766351001.html