在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于RT-Thread的RoboMaster電控框架(三)

冬至子 ? 來源:螺絲松掉的人 ? 作者:螺絲松掉的人 ? 2023-09-20 15:21 ? 次閱讀

背景

使用的開發(fā)板為大疆RoboMaster-C 型開發(fā)板,基礎(chǔ)工程為 rt-thread>bsp>stm32f407-robomaster-c

BMI088模塊開發(fā)

BMI088 為 robomaster-c 開發(fā)板上集成的6軸imu,在此為提高速度陀螺儀和加速度計均使用使用 SPI 通訊方式,

添加 SPI 通信 API

首先將飛控程序中針對 RT-Thread 的 SPI 設(shè)備驅(qū)動封裝的 SPI 讀寫函數(shù)借鑒過來:

#define SPI_DIR_READ 0x80
#define SPI_DIR_WRITE 0x00
/**

This function write a 8 bit reg.

@param device the SPI device attached to SPI bus

@param reg Register address

@param val The value to be written

@return RT_EOK if write successfully.
/
rt_inline rt_err_t spi_write_reg8(rt_device_t spi_device, uint8_t reg, uint8_t val)
{
uint8_t buffer[2];
rt_size_t w_byte;
buffer[0] = SPI_DIR_WRITE | reg;
buffer[1] = val;
w_byte = rt_spi_transfer((struct rt_spi_device
)spi_device, buffer, NULL, 2);
return (w_byte == 2) ? RT_EOK : RT_ERROR;
}
/**
This function read a 8 bit reg.

@param device the SPI device attached to SPI bus

@param reg Register address

@param buffer Buffer of read data

@return RT_EOK if read successfully.
/
rt_inline rt_err_t spi_read_reg8(rt_device_t spi_device, uint8_t reg, uint8_t
buffer)
{
uint8_t reg_addr;
reg_addr = SPI_DIR_READ | reg;
return rt_spi_send_then_recv((struct rt_spi_device*)spi_device, (void*)?_addr, 1, (void*)buffer, 1);
}
/**
This function read multiple contiguous 8 bit regs.

@param device the SPI device attached to SPI bus

@param reg Start register address

@param buffer Buffer of read data

@param len The number of read registers

@return RT_EOK if read successfully.
/
rt_inline rt_err_t spi_read_multi_reg8(rt_device_t spi_device, uint8_t reg, uint8_t
buffer, uint8_t len)
{
uint8_t reg_addr;
reg_addr = SPI_DIR_READ | reg;
return rt_spi_send_then_recv((struct rt_spi_device*)spi_device, (void*)?_addr, 1, (void*)buffer, len);
}
因為C板上 STM32 與 BMI088 是通過 SPI1 相連接,Kconfig 文件中添加 SPI1 部分并使能,并且需要進入到CubeMX 中使能 SPI1,這一步最重要的是選取引腳,這樣 RTT 中的 SPI1 設(shè)備驅(qū)動才能使用:

BMI088 驅(qū)動

主要就是先對 BMI088 上的陀螺儀和加速度計分別進行初始化,設(shè)置相關(guān)采樣參數(shù),需要注意的一點是加速度計上電后默認是 I2C 模式,需要其片選引腳上檢測到電平后才會切換為 SPI 模式并保持,如果沒有正確處理這一步可能會導致這個現(xiàn)象:上電后讀不出來加速度計,reset 后又能讀取。

static rt_err_t accelerometer_init(void)
{
uint8_t accel_id;
/* init spi bus /
rt_device_open(accel_spi_dev, RT_DEVICE_OFLAG_RDWR);
/
dummy read to let accel enter SPI mode /
spi_read_reg8(accel_spi_dev, BMI088_ACC_BGW_CHIPID, &accel_id);
rt_hw_us_delay(1000);
spi_read_reg8(accel_spi_dev, BMI088_ACC_BGW_CHIPID, &accel_id);
/
read accel id /
spi_read_reg8(accel_spi_dev, BMI088_ACC_BGW_CHIPID, &accel_id);
if (accel_id != BMI088_ACC_BGW_CHIPID_VALUE) {
LOG_W("Warning: not found BMI088 accel id: %02x", accel_id);
return RT_ERROR;
}
/
soft reset /
spi_write_reg8(accel_spi_dev, BMI088_ACC_SOFTRESET, 0xB6);
rt_hw_us_delay(2000);
/
dummy read to let accel enter SPI mode /
spi_read_reg8(accel_spi_dev, BMI088_ACC_BGW_CHIPID, &accel_id);
/
enter normal mode /
spi_write_reg8(accel_spi_dev, BMI088_ACC_PWR_CTRL, 0x04);
rt_hw_us_delay(55000);
/
set default range and bandwidth /
accel_set_range(6); /
6g /
accel_set_sample_rate(800); /
800Hz sample rate /
accel_set_bwp_odr(280); /
Normal BW /
/
enter active mode /
spi_write_reg8(accel_spi_dev, BMI088_ACC_PWR_CONF, 0x00);
rt_hw_us_delay(1000);
return RT_EOK;
}
static rt_err_t gyroscope_init(void)
{
uint8_t gyro_id;
/
init spi bus /
rt_device_open(gyro_spi_dev, RT_DEVICE_OFLAG_RDWR);
spi_read_reg8(gyro_spi_dev, BMI088_CHIP_ID_ADDR, &gyro_id);
if (gyro_id != BMI088_GRRO_CHIP_ID) {
LOG_W("Warning: not found BMI088 gyro id: %02x", gyro_id);
return RT_ERROR;
}
/
soft reset /
spi_write_reg8(gyro_spi_dev, BMI088_BGW_SOFT_RST_ADDR, 0xB6);
rt_hw_us_delay(35000); // > 30ms delay
gyro_set_range(2000); /
2000dps /
gyro_set_sample_rate(2000); /
OSR 2000KHz, Filter BW: 230Hz /
/
enable gyroscope /
__modify_reg(gyro_spi_dev, BMI088_MODE_LPM1_ADDR, REG_VAL(0, BIT(7) | BIT(5))); /
{0; 0} NORMAL mode */
rt_hw_us_delay(1000);
return RT_EOK;
}

這里為了減小陀螺儀的零飄影響,可以對陀螺儀進行校準,得出補償?shù)闹怠?/p>

static void bmi088_calibrate(void){
static float start_time;
static uint16_t cali_times = 5000; // 需要足夠多的數(shù)據(jù)才能得到有效陀螺儀零偏校準結(jié)果
float accel[3], gyro[3];
float gyroMax[3], gyroMin[3];
float gNormTemp, gNormMax, gNormMin;
static float gyroDiff[3], gNormDiff;
int16_t acc_raw[3];
start_time = dwt_get_time_s();
do
{
if (dwt_get_time_s() - start_time > 20)
{
// 校準超時
gyro_offset[0] = GxOFFSET;
gyro_offset[1] = GyOFFSET;
gyro_offset[2] = GzOFFSET;
bmi088_g_norm = gNORM;
break;
}
dwt_delay_s(0.005);
// 開始時先置零,避免對數(shù)據(jù)讀取造成影響
bmi088_g_norm = 0;
gyro_offset[0] = 0;
gyro_offset[1] = 0;
gyro_offset[2] = 0;
for (uint16_t i = 0; i < cali_times; i++)
{
accel_read_raw(acc_raw);
accel[0] = accel_range_scale * acc_raw[0];
accel[1] = accel_range_scale * acc_raw[1];
accel[2] = accel_range_scale * acc_raw[2];
gNormTemp = sqrtf(accel[0] * accel[0] +
accel[1] * accel[1] +
accel[2] * accel[2]);
bmi088_g_norm += gNormTemp;
gyro_read_rad(gyro);
for(uint8_t j = 0; j < 3; j++){
gyro_offset[j] += gyro[j];
}
// 記錄數(shù)據(jù)極差
if (i == 0)
{
gNormMax = gNormTemp;
gNormMin = gNormTemp;
for (uint8_t j = 0; j < 3; j++)
{
gyroMax[j] = gyro[j];
gyroMin[j] = gyro[j];
}
}
else
{
if (gNormTemp > gNormMax)
gNormMax = gNormTemp;
if (gNormTemp < gNormMin)
gNormMin = gNormTemp;
for (uint8_t j = 0; j < 3; j++)
{
if (gyro[j] > gyroMax[j])
gyroMax[j] = gyro[j];
if (gyro[j] < gyroMin[j])
gyroMin[j] = gyro[j];
}
}
// 數(shù)據(jù)差異過大認為收到外界干擾,需重新校準
gNormDiff = gNormMax - gNormMin;
for (uint8_t j = 0; j < 3; j++)
gyroDiff[j] = gyroMax[j] - gyroMin[j];
if (gNormDiff > 0.6f ||
gyroDiff[0] > 1.0f ||
gyroDiff[1] > 1.0f ||
gyroDiff[2] > 1.0f)
break;
LOG_I("gyroDiff: %f",gNormDiff);
for(uint8_t j = 0; j < 3; j++){
LOG_D("gyroDiff%d: %f",j ,gyroDiff[j]);
}
dwt_delay_s(0.0005);
}
// 取平均值得到標定結(jié)果
bmi088_g_norm /= (float)cali_times;
LOG_W("bmi088_g_norm: %f",bmi088_g_norm);
for (uint8_t i = 0; i < 3; i++)
{
gyro_offset[i] /= (float)cali_times;
LOG_W("gyro_offset: %f",gyro_offset[i]);
}
cali_count++;
} while (gNormDiff > 0.3f ||
fabsf(bmi088_g_norm - 9.8f) > 0.5f ||
gyroDiff[0] > 1.0f ||
gyroDiff[1] > 1.0f ||
gyroDiff[2] > 1.0f ||
fabsf(gyro_offset[0]) > 0.01f ||
fabsf(gyro_offset[1]) > 0.01f ||
fabsf(gyro_offset[2]) > 0.01f);
// 根據(jù)標定結(jié)果校準加速度計標度因數(shù)
accel_scale = 9.81f / bmi088_g_norm;
}

由于校準時間較長,并且需要處于穩(wěn)定的環(huán)境下,定期或更換開發(fā)板時進行一次校準即可,校準成功后手動修改 GxOFFSET 等宏;通過在 menuconfig 中使能 BSP_BMI088_CALI 進行校準;在串口終端可以查看校準進度,如多次校準失敗,適當調(diào)大誤差范圍。

抽象設(shè)備

為提高程序的模塊化,選用不同傳感器時的靈活性,將 bmi088 抽象為 imu一類設(shè)備,抽象出 imu_init 、 gyro_read 、 gyro_config、accel_read、accel_config、temp_read 6個操作方法。

struct imu_ops{
rt_err_t (*imu_init)(void);
rt_err_t (*gyro_read)(float data[3]);
rt_err_t (*gyro_config)(struct gyro_configure cfg);
rt_err_t (*accel_read)(float data[3]);
rt_err_t (*accel_config)(struct accel_configure cfg);
float (*temp_read)(void);
};

項目選用不同的磁力計傳感器時,對接這些個接口即可,以 bmi088 為例:

struct imu_ops imu_ops = {
.imu_init = bmi088_init,
.gyro_read = bim088_gyro_read,
.gyro_config = bim088_gyro_config,
.accel_read = bim088_accel_read,
.accel_config = bim088_accel_config,
.temp_read = bmi088_temp_read,
};

應用層需要使用磁力計時,調(diào)用 imu_ops 中的操作方法即可:

/* read data /
float gyro[3],acc[3],temp;
imu_ops.gyro_read(gyro);
imu_ops.accel_read(acc);
temp = imu_ops.temp_read();
/
config */
struct gyro_configure usr_conf_g = GYRO_CONFIG_DEFAULT;
struct acc_configure usr_conf_a = ACCEL_CONFIG_DEFAULT;

到此就可以使用imu模塊獲取傳感器原始數(shù)據(jù)啦。

存在問題及優(yōu)化方向

目前為了提高性能,imu設(shè)備的注冊對接形式是比較簡陋的;
目前對 imu 設(shè)備的抽象只考慮到6軸 imu;
需要注意陀螺儀校準處理部分。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 傳感器
    +關(guān)注

    關(guān)注

    2551

    文章

    51099

    瀏覽量

    753606
  • 驅(qū)動器
    +關(guān)注

    關(guān)注

    52

    文章

    8236

    瀏覽量

    146369
  • 加速度計
    +關(guān)注

    關(guān)注

    6

    文章

    702

    瀏覽量

    45897
  • STM32F407
    +關(guān)注

    關(guān)注

    15

    文章

    187

    瀏覽量

    29463
  • RT-Thread
    +關(guān)注

    關(guān)注

    31

    文章

    1289

    瀏覽量

    40135
收藏 人收藏

    評論

    相關(guān)推薦

    基于RT-ThreadRoboMaster電控框架設(shè)計

    由于 RT-Thread 穩(wěn)定高效的內(nèi)核,豐富的文檔教程,積極活躍的社區(qū)氛圍,以及設(shè)備驅(qū)動框架、Kconfig、Scons、日志系統(tǒng)、海量的軟件包……很難不選擇 RT-Thread 進行項目開發(fā)。
    發(fā)表于 09-06 15:21 ?705次閱讀

    RT-Thread編程指南

    RT-Thread編程指南——RT-Thread開發(fā)組(2015-03-31)。RT-Thread做為國內(nèi)有較大影響力的開源實時操作系統(tǒng),本文是RT-Thread實時操作系統(tǒng)的編程指南
    發(fā)表于 11-26 16:06 ?0次下載

    RT-Thread全球技術(shù)大會:RT-Thread上的單元測試框架與運行測試用例

    RT-Thread全球技術(shù)大會:RT-Thread上的單元測試框架與運行測試用例 ? ? ? ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 16:21 ?1629次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會:<b class='flag-5'>RT-Thread</b>上的單元測試<b class='flag-5'>框架</b>與運行測試用例

    RT-Thread設(shè)備模型框架及創(chuàng)建注冊設(shè)備的實現(xiàn)

    RT-Thread設(shè)備模型框架及創(chuàng)建注冊設(shè)備的實現(xiàn)方式介紹如下:
    的頭像 發(fā)表于 05-28 10:38 ?2188次閱讀
    <b class='flag-5'>RT-Thread</b>設(shè)備模型<b class='flag-5'>框架</b>及創(chuàng)建注冊設(shè)備的實現(xiàn)

    RT-Thread文檔_RT-Thread 簡介

    RT-Thread文檔_RT-Thread 簡介
    發(fā)表于 02-22 18:22 ?5次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> 簡介

    RT-Thread文檔_RT-Thread SMP 介紹與移植

    RT-Thread文檔_RT-Thread SMP 介紹與移植
    發(fā)表于 02-22 18:31 ?9次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> SMP 介紹與移植

    RT-Thread文檔_utest 測試框架

    RT-Thread文檔_utest 測試框架
    發(fā)表于 02-22 18:43 ?2次下載
    <b class='flag-5'>RT-Thread</b>文檔_utest 測試<b class='flag-5'>框架</b>

    淺析RT-Thread設(shè)備驅(qū)動框架

    RT-Thread 設(shè)備框架屬于組件和服務層,是基于 RT-Thread 內(nèi)核之上的上層軟件。設(shè)備框架是針對某一類外設(shè),抽象出來的一套統(tǒng)一的操作方法及接入標準,可以屏蔽硬件差異,為應用
    的頭像 發(fā)表于 08-07 15:39 ?1979次閱讀

    基于 RT-ThreadRoboMaster 電控框架(一)

    。但也正是因為這些優(yōu)點的覆蓋面較廣,很多初學者會覺得無從下手,但只要步入 RT-Thread 的大門,你就發(fā)現(xiàn)她的美好。這系列文檔將作為本人基于 RT-Thread 開發(fā) RoboMaster
    的頭像 發(fā)表于 09-19 19:55 ?770次閱讀

    基于RT-ThreadRoboMaster電控框架(二)

    由于 RT-Thread 穩(wěn)定高效的內(nèi)核,豐富的文檔教程,積極活躍的社區(qū)氛圍,以及設(shè)備驅(qū)動框架、Kconfig、Scons、日志系統(tǒng)、海量的軟件包
    的頭像 發(fā)表于 09-20 15:16 ?758次閱讀

    基于RT-ThreadRoboMaster電控框架(四)

    使用的開發(fā)板為大疆的 RoboMaster-C 型開發(fā)板,基礎(chǔ)工程為 rt-thread>bsp>stm32f407-robomaster-c
    的頭像 發(fā)表于 09-20 15:28 ?729次閱讀

    RT-Thread框架下的SMP支持

    使其支持 RT-Thread 框架下的 SMP,最近就一直在研究 SMP,并在 Raspberry-Pico 上做了一些實驗。
    的頭像 發(fā)表于 10-11 10:34 ?1135次閱讀
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>框架</b>下的SMP支持

    基于rt-thread的socket通信設(shè)計

    最近再研究 rt-thread 的通信 ,想設(shè)計出 eps8266(多個) rt-thread(作為中控) 服務器的通信框架,使用的開發(fā)板是 潘多拉
    的頭像 發(fā)表于 10-13 15:02 ?1369次閱讀
    基于<b class='flag-5'>rt-thread</b>的socket通信設(shè)計

    基于RT-ThreadRoboMaster電控框架(五)

    使用的開發(fā)板為大疆的 RoboMaster-C 型開發(fā)板,基礎(chǔ)工程為 rt-thread>bsp>stm32f407-robomaster-c
    的頭像 發(fā)表于 10-30 17:10 ?1200次閱讀

    基于RT-ThreadRoboMaster電控框架(六)

    使用的開發(fā)板為大疆的 RoboMaster-C 型開發(fā)板,基礎(chǔ)工程為 rt-thread>bsp>stm32f407-robomaster-c
    的頭像 發(fā)表于 10-30 17:41 ?494次閱讀
    主站蜘蛛池模板: 四虎影院最新| 欧美xxxx性特级高清| 看黄在线| 五月婷婷丁香六月| 国产女人视频| 成年大片免费播放视频人| 久久99爱爱| 亚洲伊人久久大香线蕉综合图片| 久久狼人综合| 久久大综合| 一级片 在线播放| 国产美女免费观看| 8050网| 年下攻高h好涨| 免费黄色地址| 综合天天| 一区二区三区无码高清视频| 日韩福利一区| 天天草夜夜骑| 在线天堂资源| 欧美伦理一区二区三区| www.五月婷婷| 国产精品福利午夜一级毛片| 性欧美video视频另类| 久久久久久综合| 国产高清网站| 色综合久久一区二区三区| 新版天堂资源中文8在线| 啪啪网站色大全免费| 久久性| 欧美极品在线观看| 欧美黄色片在线观看| 国产美女一级片| 色综合天天综合网国产成人网| 天天做天天做天天综合网| lsj老司机精品视频在线观看| 国产片翁熄系列乱在线视频| 91成人免费| 激情网网站| 91日本在线观看亚洲精品| 免费观看a黄一级视频|