【ART-Pi作品秀】瞎轉(zhuǎn)悠
作者: 樊曉杰
概述
簡單介紹項(xiàng)目應(yīng)用產(chǎn)生的背景 ,所產(chǎn)生的軟硬件方案 及主要實(shí)現(xiàn)的功能。
應(yīng)用產(chǎn)生背景
在和娃玩老鷹轉(zhuǎn)小雞時(shí)候,突然就想做個(gè)小車,可以和孩子互動(dòng),就想到人擋在小車前面,然后轉(zhuǎn)向,就一直這么循環(huán)下去,一個(gè)很簡單的功能。就是漫無目的 瞎轉(zhuǎn)悠,這就是名字的由來。也是一個(gè)提醒,尤其到冬天了還是在疫情期間,沒事別瞎轉(zhuǎn)悠,老實(shí)在家呆著沒事 就玩玩rt-thread,多參加參加電路城的活動(dòng)。
所采用的硬件方案
硬件方案采用 : 主控板 ART-Pi + SR04 超聲波 測距儀 + 小車套件。
1.ART-Pi 簡介
ART-Pi是 RT-Thread 團(tuán)隊(duì)經(jīng)過半年的精心準(zhǔn)備,專門為嵌入式軟件工程師、開源創(chuàng)客設(shè)計(jì)的一款極具擴(kuò)展功能的 DIY 開源硬件。
板載資源:
-
- STM32H750XBH6 - On-board ST-LINK/V2.1 - USB OTG with Type-C connector
-
- SDIO TF Card slot - SDIO WIFI:AP6212 - HDC UART BuleTooth:AP6212
-
- RGB888 FPC connector - 32-Mbytes SDRAM - 16-Mbytes SPI FLASH
-
- 8-Mbytes QSPI FLASH - D1(blue) for 3.3 v power-on - Two user LEDs:D2 (blue),D2 (red)
-
- Two ST-LINK LEDs: D4(blue),D4 (red) - Two push-buttons (user and reset)
擴(kuò)展接口:
-
- 4路UART(LPUART) - 3路SPI - 2路hardware iic
-
- 1路USB-FS - 1路ETH - 1路SAI
-
- 1路DCMI - 2路CANFD - 超過5路ADC (支持查分輸入ADC)
驅(qū)動(dòng)支持:
-
- UART - SPI - SDMMC - CAN - QSPI
-
- ADC - PWM - DCMI - SAI - LTDC
-
- USB - ETH - SDRAM - HRTIM - I2C
2.SR04 超聲波測距傳感器
超聲波測距 我們這里采用很常見的一個(gè)模塊 SR04 。HC-SR04超聲波模塊常用于機(jī)器人避障、物體測距、液位檢測、公共安防、停車場檢測等場所。HC-SR04超聲波模塊主要是由兩個(gè)通用的壓電陶瓷超聲傳感器,并加外圍信號(hào)處理電路構(gòu)成的。
3. 小車套件
小車基礎(chǔ)平臺(tái)采購慧凈電子四驅(qū)智能小車底盤 及驅(qū)動(dòng)板。
4.電機(jī)驅(qū)動(dòng)模塊:
每一路需要3個(gè)信號(hào)控制,一路pwm ,一路正傳一路反轉(zhuǎn)。
所采用軟件方案
軟件方案 基于 RT-Thread IoT RTOS 此方案中使用SR04 超聲波測距軟件包,RT-Robot 軟件包。
開發(fā)環(huán)境:
使用的是rt-thread 4.0.3 版本軟件,使用mdk 結(jié)合env 工具 開發(fā)。
分別簡介如下:
RT-Thread 的架構(gòu)簡介:
近年來,物聯(lián)網(wǎng)(Internet Of Things,IoT)概念廣為普及,物聯(lián)網(wǎng)市場發(fā)展迅猛,嵌入式設(shè)備的聯(lián)網(wǎng)已是大勢(shì)所趨。終端聯(lián)網(wǎng)使得軟件復(fù)雜性大幅增加,傳統(tǒng)的 RTOS 內(nèi)核已經(jīng)越來越難滿足市場的需求,在這種情況下,物聯(lián)網(wǎng)操作系統(tǒng)(IoT OS)的概念應(yīng)運(yùn)而生。物聯(lián)網(wǎng)操作系統(tǒng)是指以操作系統(tǒng)內(nèi)核(可以是 RTOS、Linux 等)為基礎(chǔ),包括如文件系統(tǒng)、圖形庫等較為完整的中間件組件,具備低功耗、安全、通信協(xié)議支持和云端連接能力的軟件平臺(tái),RT-Thread 就是一個(gè) IoT OS。
RT-Robot 是 RT-Thread 的機(jī)器人框架,希望能夠支持智能小車、機(jī)械臂、無人機(jī)等各種不同類型的機(jī)器人。
當(dāng)前以智能車為主要目標(biāo),希望支持兩輪差分驅(qū)動(dòng)、四輪差分驅(qū)動(dòng)、麥克納姆輪驅(qū)動(dòng)、經(jīng)典 Ackerman (兩輪差分,一方向連桿) 的小車底盤。
當(dāng)前功能特點(diǎn):
-
支持兩輪差分驅(qū)動(dòng)、四輪差分驅(qū)動(dòng)、麥克納姆輪驅(qū)動(dòng)的小車底盤
-
支持增量、位置式 PID
-
支持單相、AB 相編碼器
-
支持 PS2 遙控器
-
支持 ANO_TC 匿名科創(chuàng)地面站
SR04 軟件包工作流程 ultrasonic sensor v2.0 a.單片機(jī)引腳觸發(fā)Trig測距,給至少 10us 的高電平信號(hào); b.模塊自動(dòng)發(fā)送 8 個(gè) 40khz 的方波,自動(dòng)檢測是否有信號(hào)返回; c.有信號(hào)返回,通過 IO 輸出一高電平,并單片機(jī)定時(shí)器計(jì)算高電平持續(xù)的時(shí)間; d.超聲波從發(fā)射到返回的時(shí)間. 計(jì)算公式:測試距離=(高電平時(shí)間*聲速(340M/S))/2;
目前 程序使用如下線程:
線程 | 功能 | 優(yōu)先級(jí) |
---|---|---|
按鍵處理線程 | 處理按鍵響應(yīng) | 20 |
小車控制線程 | 控制小車四輪驅(qū)動(dòng) | 23 |
測距線程 | 處理距離數(shù)據(jù)處理 | 16 |
led 線程 | 程序正常運(yùn)行指示 | 10 |
FinSH線程 | 命令行組件,方便調(diào)試 | 20 |
實(shí)現(xiàn)功能
-
按鍵按下,小車功能啟動(dòng);
-
小車一直測量前方距離,當(dāng)距離小于30cm 時(shí),左拐,然后前進(jìn)
-
然后一直循環(huán)上述判斷過程
-
按鍵再次按下,小車停止。
RT-Thread 使用情況概述
應(yīng)用中RT-Thread 使用情況:
內(nèi)核部分:
1.使用到四個(gè)線程:按鍵處理線程,超聲波測距線程,小車控制線程,led 狀態(tài)顯示線程。
2.線程間通信使用:郵箱在超聲波測距線程中將距離數(shù)據(jù)發(fā)送給小車控制線程,
3.線程間同步使用:信號(hào)量作為按鍵 處理線程 和 電機(jī)控制線程之間 啟動(dòng)停止的信號(hào) 同步。
設(shè)備驅(qū)動(dòng)部分:
1.PWM 設(shè)備及驅(qū)動(dòng)-------電機(jī)驅(qū)動(dòng)部分用到
2.定時(shí)器設(shè)備及驅(qū)動(dòng)-------超聲波測距 部分用到
組件部分:
1.FinSH控制臺(tái) ----------------調(diào)試用到
軟件包部分:
-
SR04 超聲波測距 軟件包 ,一貫的好用,方便集成;地址如下:
-
robot RT-Thread 的機(jī)器人框架軟件包 ,數(shù)據(jù)結(jié)構(gòu)優(yōu)美的一個(gè)軟件包 .地址如下:
硬件框架說明
主控芯片 | STM32H750XBH6 | Cortex-M系列高性能處理器,M7內(nèi)核,主頻400MHz |
---|---|---|
超聲波測距模塊 | SR04 | 可提供 2cm - 400cm 的非接觸式距離感測功能 |
電機(jī)驅(qū)動(dòng)板 | L298P直流電機(jī)驅(qū)動(dòng)模塊 | 4路直流電機(jī)驅(qū)動(dòng)模塊 |
小車車架 | 4輪驅(qū)動(dòng) | 智能小車底盤套件 |
供電模塊 | 2節(jié) 18650 | 3.7V 大容量鋰電池 |
硬件方案 直接使用 ART-Pi開發(fā)板,使用的外設(shè)說明如下:
-
按鍵用來啟動(dòng)小車,停止小車;
-
測距模塊使用定期器來換算 距離;
-
直流電機(jī)驅(qū)動(dòng)模塊使用PWM 驅(qū)動(dòng);
-
led 顯示系統(tǒng)正常運(yùn)行;
接線說明:這個(gè)系統(tǒng)使用到的引腳如下
超聲波 ? TRIG PB1 ? ECHO PB2 ? 定時(shí)器13. ? PWM: 有網(wǎng)友說用到 time2 --- 2,3 tim5 兩個(gè)引腳 。 ? PH10 CH1 TIME5 正轉(zhuǎn) PB12 反轉(zhuǎn) PG10 ? PH11 CH2 TIME5 正轉(zhuǎn) PA15 反轉(zhuǎn) PH15 ? PH12 CH3 TIME5 正傳PH13 反轉(zhuǎn) 反轉(zhuǎn) PI3 ? PI0 CH4 TIME5 正轉(zhuǎn) PH7 反轉(zhuǎn) PH9 ? led: ? RED: PC15 ? BLUE: PI8 ? 按鍵: ? PH4 低電平有效。
軟件框架說明
【主要介紹應(yīng)用所采用的軟件方案框圖、流程圖等】
最終的使用的線程情況如下:
msh />ps thread pri status sp stack size max used left tick error -------- --- ------- ---------- ---------- ------ ---------- --- sr04 16 suspend 0x00000118 0x00000400 27% 0x00000002 000 tshell 20 running 0x00000108 0x00001000 12% 0x00000004 000 keythrea 20 suspend 0x00000080 0x00000200 25% 0x00000005 000 motor_ru 23 suspend 0x00000150 0x00000400 32% 0x00000004 000 tidle0 31 ready 0x00000044 0x00000100 32% 0x0000000a 000 timer 4 suspend 0x00000060 0x00000200 18% 0x00000009 000 main 10 suspend 0x0000008c 0x00000800 16% 0x00000004 000 ? ?
軟件流程:
-
上電開機(jī) led 顯示系統(tǒng)正常運(yùn)行;
-
電機(jī)控制線程 接收按鍵信號(hào) 啟動(dòng)信號(hào)量 ,啟動(dòng)電機(jī) 直行,;
-
sr04 超聲波測距模塊線程 接收到啟動(dòng)信號(hào)后 ,開始測距,并將測量數(shù)據(jù)發(fā)給 通過郵箱 發(fā)給 電機(jī)控制線程;
-
電機(jī)控制線程通過郵箱 接收到距離數(shù)據(jù)判斷有障礙物,就左轉(zhuǎn),直行;
-
電機(jī)控制線程接收到按鍵 停止信號(hào) 停止信號(hào)量 ,然后停車。
軟件模塊說明
(介紹應(yīng)用軟件關(guān)鍵部分的邏輯、采用的實(shí)現(xiàn)方式等)
1.電機(jī)控制模塊處理
電機(jī)控制模塊,主要控制電機(jī)的直行 轉(zhuǎn)向 ,停止 及對(duì)接收到的距離數(shù)據(jù)的處理,關(guān)鍵代碼具體如下:
static void motor_entry(void *parameter) { rt_uint32_t count = 0; motor_t letf_moto = RT_NULL; motor_t right_moto = RT_NULL; //chassis_t chas; struct velocity target_vel; // 1. Initialize two wheels - left and right wheel_t* c_wheels = (wheel_t*) rt_malloc(sizeof(wheel_t) * 4); if (c_wheels == RT_NULL) { LOG_D("Failed to malloc memory for wheels"); } ? // 1.1 Create two motors //motor_t left_motor = motor_create(left_motor_init, left_motor_enable, left_motor_disable, left_motor_set_speed, DC_MOTOR); //motor_t right_motor = motor_create(right_motor_init, right_motor_enable, right_motor_disable, right_motor_set_speed, DC_MOTOR); single_pwm_motor_t left_forward_motor = single_pwm_motor_create(LEFT_FORWARD_PWM,LEFT_FORWARD_PWM_CHANNEL, LEFT_FORWARD_STRAIGHT_PIN, LEFT_FORWARD_BACK_PIN); single_pwm_motor_t left_backward_motor = single_pwm_motor_create(LEFT_BACKWARD_PWM,LEFT_BACKWARD_PWM_CHANNEL, LEFT_BACKWARD_STRAIGHT_PIN, LEFT_BACKWARD_BACK_PIN); single_pwm_motor_t right_forward_motor = single_pwm_motor_create(RIGHT_FORWARD_PWM,RIGHT_FORWARD_PWM_CHANNEL, RIGHT_FORWARD_STRAIGHT_PIN, RIGHT_FORWARD_BACK_PIN); single_pwm_motor_t right_backward_motor = single_pwm_motor_create(RIGHT_BACKWARD_PWM,RIGHT_BACKWARD_PWM_CHANNEL, RIGHT_BACKWARD_STRAIGHT_PIN, RIGHT_BACKWARD_BACK_PIN); ? ? // 1.2 Create two encoders //encoder_t left_encoder = encoder_create(LEFT_ENCODER_PIN, PULSE_PER_REVOL); //encoder_t right_encoder = encoder_create(RIGHT_ENCODER_PIN, PULSE_PER_REVOL); single_phase_encoder_t left_forward_encoder = single_phase_encoder_create(LEFT_ENCODER_PIN,PULSE_PER_REVOL,SAMPLE_TIME ); single_phase_encoder_t right_forward_encoder = single_phase_encoder_create(RIGHT_ENCODER_PIN,PULSE_PER_REVOL,SAMPLE_TIME); ? // 1.3 Create two pid contollers //pid_control_t left_pid = pid_create(); //pid_control_t right_pid = pid_create(); inc_pid_controller_t left_pid = inc_pid_controller_create(kp,ki,kd,SAMPLE_TIME); inc_pid_controller_t right_pid = inc_pid_controller_create(kp, ki,kd,SAMPLE_TIME); // 1.4 Add two wheels //wheel_t wheel_create(motor_t w_motor, encoder_t w_encoder, controller_t w_controller, float radius, rt_uint16_t gear_ratio) ? c_wheels[0] = wheel_create((motor_t)left_forward_motor, (encoder_t)left_forward_encoder,(controller_t)left_pid, WHEEL_RADIUS, GEAR_RATIO);//left_pid c_wheels[2] = wheel_create((motor_t)left_backward_motor, (encoder_t)left_forward_encoder,(controller_t)left_pid, WHEEL_RADIUS, GEAR_RATIO);//left_pid c_wheels[1] = wheel_create((motor_t)right_forward_motor, (encoder_t)right_forward_encoder,(controller_t)right_pid, WHEEL_RADIUS, GEAR_RATIO);//left_pid c_wheels[3] = wheel_create((motor_t)right_backward_motor, (encoder_t)right_forward_encoder,(controller_t)right_pid, WHEEL_RADIUS, GEAR_RATIO);//left_pid ? ? // 2. Iinialize Kinematics - Two Wheel Differential Drive kinematics_t c_kinematics = kinematics_create(FOUR_WD, WHEEL_DIST_X, WHEEL_DIST_Y, WHEEL_RADIUS); ? // 3. Initialize Chassis chas = chassis_create(c_wheels, c_kinematics); ? // 4. Enable Chassis //chassis_enable(chas); ? // Set Sample time encoder_set_sample_time(chas->c_wheels[0]->w_encoder, SAMPLE_TIME); encoder_set_sample_time(chas->c_wheels[1]->w_encoder, SAMPLE_TIME); encoder_set_sample_time(chas->c_wheels[2]->w_encoder, SAMPLE_TIME); encoder_set_sample_time(chas->c_wheels[3]->w_encoder, SAMPLE_TIME); //pid_set_sample_time(chas->c_wheels[0]->w_pid, PID_SAMPLE_TIME); //pid_set_sample_time(chas->c_wheels[1]->w_pid, PID_SAMPLE_TIME); ? // 4. Enable Chassis chassis_enable(chas); // Turn left **struct rt_sensor_data *sensor_data;//關(guān)鍵地方** while(1) { //chassis_update(chas); /* 永久方式等待信號(hào)量,獲取到信號(hào)量,則執(zhí)行number自加的操作 */ result = rt_sem_take(start_sem, RT_WAITING_FOREVER); if (result != RT_EOK) { rt_kprintf("thread2 take a start semaphore, failed.n"); rt_sem_delete(start_sem); return; } else { number++; rt_kprintf("thread2 take a start semaphore. number = %dn", number); while(1) { run();//直行 /* 從郵箱中收取郵件 */ if (rt_mb_recv(&mb, (rt_uint32_t *)&sensor_data, RT_WAITING_FOREVER) == RT_EOK) { // rt_kprintf("thread1: get a mail from mailbox, the content:%sn", ); if (sensor_data.data.proximity/10 < 30) { rt_kprintf("distance:%3d.%dcm, timestamp:%5d turn left n", sensor_data.data.proximity / 10, sensor_data.data.proximity % 10, sensor_data.timestamp); left(); } /* 延時(shí)100ms */ rt_thread_mdelay(100); } result = rt_sem_take(stop_sem, RT_WAITING_NO); if (result == RT_EOK) { //rt_kprintf("thread2 take a start semaphore, failed.n"); //rt_sem_delete(stop_sem); stop(); break; } } } rt_thread_mdelay(1500); ? } ? }
調(diào)試說明:
①主要看pwm 是否可以正常輸出波形。
可以通過命令:來測試。遇到過 有下面波形,但和電機(jī)程序結(jié)合起來的話,沒有輸出波形。
msh />pwm_set pwm5 2 1000 500
msh />pwm_e
pwm_enable
msh />pwm_enable pwm5 2
msh />pwm_disable pwm5 2
② 有個(gè)電機(jī)控制引腳,PA15,初始就是高電平,導(dǎo)致一上電就轉(zhuǎn),換一個(gè)其他引腳。
③先把幾個(gè)引腳都先調(diào)通,對(duì)應(yīng)起來,可以通過直接將引腳接高電平的方式,來測試,因?yàn)榫€不一定接的對(duì)。可以先根據(jù)引腳的分布,初步先列出來控制引腳序號(hào)。然后再通過調(diào)試,進(jìn)行調(diào)整。
④ 通過第一步調(diào)試,證明pwm 驅(qū)動(dòng)沒有問題,但任然出現(xiàn)過 robot 程序 沒有輸出pwm 波形,原因分析如下:
通過單步調(diào)試,發(fā)現(xiàn)最終只是設(shè)置了速度,并沒有最后的運(yùn)行。也就是這句 chassis_update(chas);
⑤ 有波形 但占空比很低的話,電機(jī)也跑不起來,可以在
rt_pwm_set(mot_sub->pwm_dev, mot_sub->channel, MOTOR_PWM_PERIOD, pluse + 28000 );//50 000 在一半的 基礎(chǔ)上增加。
⑥ 調(diào)試其他幾個(gè)方向,比如不動(dòng)的話,可以實(shí)時(shí)調(diào)整參數(shù)。比如下面幾個(gè):
void stop(void)
{
struct velocity target_vel;
target_vel.linear_x = 0.0; // m/s
target_vel.linear_y = 0; // m/s
target_vel.angular_z = 0; // rad/s
chassis_set_velocity(chas, target_vel);
chassis_update(chas);
rt_thread_mdelay(500);
}
MSH_CMD_EXPORT(stop, moto stop);
void left(void)
{
struct velocity target_vel;
// Turn left
target_vel.linear_x = 0.8;//0.06; // m/s
target_vel.linear_y = 0; // m/s
target_vel.angular_z = PI / 4; // rad/s
chassis_set_velocity(chas, target_vel);
chassis_update(chas);
rt_thread_mdelay(800);
stop();
}
MSH_CMD_EXPORT(left, moto left);
void right(void)
{
struct velocity target_vel;
// Turn right
target_vel.linear_x = 0.8;//0.06; // m/s
target_vel.linear_y = 0; // m/s
target_vel.angular_z = - PI / 4; // rad/s
chassis_set_velocity(chas, target_vel);
chassis_update(chas);
rt_thread_mdelay(400);
stop();
}
MSH_CMD_EXPORT(right, moto right);
void run(void)
{
rt_kprintf("runrn");
struct velocity target_vel;
// Go straight
target_vel.linear_x = 1.0;//0.08; // m/s
target_vel.linear_y = 0; // m/s
target_vel.angular_z = 0;
chassis_set_velocity(chas, target_vel);
chassis_update(chas);
rt_thread_mdelay(500);
}
MSH_CMD_EXPORT(run, moto straight);
void back(void)
{
struct velocity target_vel;
// Go straight
target_vel.linear_x = -1.0;//-0.08; // m/s
target_vel.linear_y = 0; // m/s
target_vel.angular_z = 0;
chassis_set_velocity(chas, target_vel);
chassis_update(chas);
rt_thread_mdelay(500);
}
MSH_CMD_EXPORT(back, moto back);
2.按鍵處理模塊
按鍵處理模塊,主要 是 發(fā)送開始 和停止信號(hào)。
關(guān)鍵代碼:
#define USER_KEY_1 GET_PIN(H,4) static rt_uint8_t flag_start = 0; /* 指向信號(hào)量的指針 */ rt_sem_t start_sem = RT_NULL; rt_sem_t stop_sem = RT_NULL; ? void process_key(void *args) { rt_thread_mdelay(50); if (rt_pin_read(USER_KEY_1) == 0) { if (flag_start == 0) { flag_start = 1; rt_sem_release(start_sem); } else { flag_start = 0; rt_sem_release(stop_sem); } } } static void key_entry(void *parameter) { rt_pin_mode(USER_KEY_1, PIN_MODE_INPUT_PULLUP); rt_pin_attach_irq(USER_KEY_1, PIN_IRQ_MODE_FALLING, process_key, RT_NULL); while(1) { rt_thread_mdelay(1000); } }
3. SR04 超聲波測距模塊
超聲波測距模塊,完成距離測量,并將數(shù)據(jù)通過郵箱發(fā)給電機(jī)控制模塊。關(guān)鍵代碼分析:
為什么這里選擇郵箱作為兩個(gè)線程間通信的方式?
(1)郵箱的開銷比較低,效率高;
(2)非阻塞方式的郵件發(fā)送過程能夠安全地應(yīng)用于中斷服務(wù)中,是線程,中斷服務(wù),定期器想線程發(fā)送消息的有效手段。
如何用郵箱來發(fā)送一個(gè)傳感器接收的數(shù)據(jù)?
(1)
為什么這里選擇郵箱作為兩個(gè)線程間通信的方式?
(1)郵箱的開銷比較低,效率高;
(2)非阻塞方式的郵件發(fā)送過程能夠安全地應(yīng)用于中斷服務(wù)中,是線程,中斷服務(wù),定期器想線程發(fā)送消息的有效手段。
如何用郵箱來發(fā)送一個(gè)傳感器接收的數(shù)據(jù)?
(1) 就是如何發(fā)送這個(gè)數(shù)據(jù)結(jié)構(gòu)的地址,然后接收線程可以解析這個(gè)數(shù)據(jù)接收,也就是通過郵箱發(fā)送指定數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)。直接取這個(gè)數(shù)據(jù)結(jié)構(gòu)的地址,接收線程,定義一個(gè) 對(duì)應(yīng)數(shù)據(jù)結(jié)構(gòu)的指針,然后取 & 這個(gè)地址,取出數(shù)據(jù),就可以。這是取到正確數(shù)據(jù)最關(guān)鍵的地方。
struct rt_sensor_data { rt_uint32_t timestamp; /* The timestamp when the data was received */ rt_uint8_t type; /* The sensor type of the data */ union { struct sensor_3_axis acce; /* Accelerometer. unit: mG */ struct sensor_3_axis gyro; /* Gyroscope. unit: mdps */ struct sensor_3_axis mag; /* Magnetometer. unit: mGauss */ rt_int32_t temp; /* Temperature. unit: dCelsius */ rt_int32_t humi; /* Relative humidity. unit: permillage */ rt_int32_t baro; /* Pressure. unit: pascal (Pa) */ rt_int32_t light; /* Light. unit: lux */ rt_int32_t proximity; /* Distance. unit: centimeters */ rt_int32_t hr; /* Heart rate. unit: bpm */ rt_int32_t tvoc; /* TVOC. unit: permillage */ rt_int32_t noise; /* Noise Loudness. unit: HZ */ rt_uint32_t step; /* Step sensor. unit: 1 */ rt_int32_t force; /* Force sensor. unit: mN */ rt_uint32_t dust; /* Dust sensor. unit: ug/m3 */ rt_uint32_t eco2; /* eCO2 sensor. unit: ppm */ } data; };
struct rt_sensor_data sensor_data; static void sr04_read_distance_entry(void *parameter) { rt_device_t dev = RT_NULL; rt_size_t res; ? dev = rt_device_find(parameter); if (dev == RT_NULL) { rt_kprintf("Can't find device:%sn", parameter); return; } ? if (rt_device_open(dev, RT_DEVICE_FLAG_RDWR) != RT_EOK) { rt_kprintf("open device failed!n"); return; } rt_device_control(dev, RT_SENSOR_CTRL_SET_ODR, (void *)100); ? while (1) { res = rt_device_read(dev, 0, &sensor_data, 1); if (res != 1) { rt_kprintf("read data failed!size is %dn", res); rt_device_close(dev); return; } else { rt_mb_send(&mb, (rt_uint32_t)&sensor_data);//發(fā)送 數(shù)據(jù) rt_kprintf("distance:%3d.%dcm, timestamp:%5dn", sensor_data.data.proximity / 10, sensor_data.data.proximity % 10, sensor_data.timestamp); } rt_thread_mdelay(2000); } }
4. LED顯示模塊
主要就是系統(tǒng)正常運(yùn)行指示。
關(guān)鍵代碼如下:
#define LED_PIN GET_PIN(I, 8) int main(void) { rt_uint32_t count = 1; ? rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT); while(count++) { rt_thread_mdelay(500); rt_pin_write(LED_PIN, PIN_HIGH); rt_thread_mdelay(500); rt_pin_write(LED_PIN, PIN_LOW); } return RT_EOK; } ?
演示效果
視頻播放地址:目前只有超聲波測距部分視頻,后續(xù)會(huì)在這個(gè)地址添加完整版。
(1)小車
(2) 超聲波測距
電機(jī)控制演示
完整視頻
第一次下地視頻
比賽感悟
雖然實(shí)現(xiàn)的功能很簡單,但是完全利用時(shí)間搞要搞成功,還是挺不容易的,還是整體的時(shí)間安排不好。主要收獲是對(duì)rt-thread 的線程間的同步和通信增強(qiáng)了認(rèn)識(shí)和體驗(yàn),實(shí)踐出真知,多多參與這樣的活動(dòng)。給主辦方點(diǎn)個(gè)贊。
主要克服的難點(diǎn):
(1)是之前pwm 驅(qū)動(dòng)一直卡著,沒有進(jìn)展,最后在網(wǎng)友的支援下順利解決,主要是初始化時(shí)候,沒有使能相應(yīng)的時(shí)鐘,陷在完全按照之前添加bsp 的方式搞,沒明白這其中的細(xì)節(jié),感謝網(wǎng)友支持;
(2)還有就是郵箱發(fā)送 結(jié)構(gòu)體數(shù)據(jù)的正確的接收和發(fā)送處理。
主要收獲:
(1)第一次使用H7 高性能MCU, 很多處理方式跟之前不一樣,比如燒錄方式,也折騰了好幾天,這個(gè)過程中,收獲不少
(2) 這個(gè)art pi 開發(fā)板 很不錯(cuò)的學(xué)習(xí)平臺(tái),也開源了挺多好的擴(kuò)展板項(xiàng)目,后續(xù)希望可以搞一個(gè)專門的小車方面的擴(kuò)展板,應(yīng)該挺不錯(cuò)的,很好玩。