【ART-Pi作品秀】瞎轉(zhuǎn)悠
作者: 樊曉杰
概述
簡單介紹項目應(yīng)用產(chǎn)生的背景 ,所產(chǎn)生的軟硬件方案 及主要實現(xiàn)的功能。
應(yīng)用產(chǎn)生背景
在和娃玩老鷹轉(zhuǎn)小雞時候,突然就想做個小車,可以和孩子互動,就想到人擋在小車前面,然后轉(zhuǎn)向,就一直這么循環(huán)下去,一個很簡單的功能。就是漫無目的 瞎轉(zhuǎn)悠,這就是名字的由來。也是一個提醒,尤其到冬天了還是在疫情期間,沒事別瞎轉(zhuǎn)悠,老實在家呆著沒事 就玩玩rt-thread,多參加參加電路城的活動。
所采用的硬件方案
硬件方案采用 : 主控板 ART-Pi + SR04 超聲波 測距儀 + 小車套件。
1.ART-Pi 簡介
ART-Pi是 RT-Thread 團隊經(jīng)過半年的精心準(zhǔn)備,專門為嵌入式軟件工程師、開源創(chuàng)客設(shè)計的一款極具擴展功能的 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)
擴展接口:
-
- 4路UART(LPUART) - 3路SPI - 2路hardware iic
-
- 1路USB-FS - 1路ETH - 1路SAI
-
- 1路DCMI - 2路CANFD - 超過5路ADC (支持查分輸入ADC)
驅(qū)動支持:
-
- UART - SPI - SDMMC - CAN - QSPI
-
- ADC - PWM - DCMI - SAI - LTDC
-
- USB - ETH - SDRAM - HRTIM - I2C
2.SR04 超聲波測距傳感器
超聲波測距 我們這里采用很常見的一個模塊 SR04 。HC-SR04超聲波模塊常用于機器人避障、物體測距、液位檢測、公共安防、停車場檢測等場所。HC-SR04超聲波模塊主要是由兩個通用的壓電陶瓷超聲傳感器,并加外圍信號處理電路構(gòu)成的。
3. 小車套件
小車基礎(chǔ)平臺采購慧凈電子四驅(qū)智能小車底盤 及驅(qū)動板。
4.電機驅(qū)動模塊:
每一路需要3個信號控制,一路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)已是大勢所趨。終端聯(lián)網(wǎng)使得軟件復(fù)雜性大幅增加,傳統(tǒng)的 RTOS 內(nèi)核已經(jīng)越來越難滿足市場的需求,在這種情況下,物聯(lián)網(wǎng)操作系統(tǒng)(IoT OS)的概念應(yīng)運而生。物聯(lián)網(wǎng)操作系統(tǒng)是指以操作系統(tǒng)內(nèi)核(可以是 RTOS、Linux 等)為基礎(chǔ),包括如文件系統(tǒng)、圖形庫等較為完整的中間件組件,具備低功耗、安全、通信協(xié)議支持和云端連接能力的軟件平臺,RT-Thread 就是一個 IoT OS。
RT-Robot 是 RT-Thread 的機器人框架,希望能夠支持智能小車、機械臂、無人機等各種不同類型的機器人。
當(dāng)前以智能車為主要目標(biāo),希望支持兩輪差分驅(qū)動、四輪差分驅(qū)動、麥克納姆輪驅(qū)動、經(jīng)典 Ackerman (兩輪差分,一方向連桿) 的小車底盤。
當(dāng)前功能特點:
-
支持兩輪差分驅(qū)動、四輪差分驅(qū)動、麥克納姆輪驅(qū)動的小車底盤
-
支持增量、位置式 PID
-
支持單相、AB 相編碼器
-
支持 PS2 遙控器
-
支持 ANO_TC 匿名科創(chuàng)地面站
SR04 軟件包工作流程 ultrasonic sensor v2.0 a.單片機引腳觸發(fā)Trig測距,給至少 10us 的高電平信號; b.模塊自動發(fā)送 8 個 40khz 的方波,自動檢測是否有信號返回; c.有信號返回,通過 IO 輸出一高電平,并單片機定時器計算高電平持續(xù)的時間; d.超聲波從發(fā)射到返回的時間. 計算公式:測試距離=(高電平時間*聲速(340M/S))/2;
目前 程序使用如下線程:
線程 | 功能 | 優(yōu)先級 |
---|---|---|
按鍵處理線程 | 處理按鍵響應(yīng) | 20 |
小車控制線程 | 控制小車四輪驅(qū)動 | 23 |
測距線程 | 處理距離數(shù)據(jù)處理 | 16 |
led 線程 | 程序正常運行指示 | 10 |
FinSH線程 | 命令行組件,方便調(diào)試 | 20 |
實現(xiàn)功能
-
按鍵按下,小車功能啟動;
-
小車一直測量前方距離,當(dāng)距離小于30cm 時,左拐,然后前進
-
然后一直循環(huán)上述判斷過程
-
按鍵再次按下,小車停止。
RT-Thread 使用情況概述
應(yīng)用中RT-Thread 使用情況:
內(nèi)核部分:
1.使用到四個線程:按鍵處理線程,超聲波測距線程,小車控制線程,led 狀態(tài)顯示線程。
2.線程間通信使用:郵箱在超聲波測距線程中將距離數(shù)據(jù)發(fā)送給小車控制線程,
3.線程間同步使用:信號量作為按鍵 處理線程 和 電機控制線程之間 啟動停止的信號 同步。
設(shè)備驅(qū)動部分:
1.PWM 設(shè)備及驅(qū)動-------電機驅(qū)動部分用到
2.定時器設(shè)備及驅(qū)動-------超聲波測距 部分用到
組件部分:
1.FinSH控制臺 ----------------調(diào)試用到
軟件包部分:
-
SR04 超聲波測距 軟件包 ,一貫的好用,方便集成;地址如下:
-
robot RT-Thread 的機器人框架軟件包 ,數(shù)據(jù)結(jié)構(gòu)優(yōu)美的一個軟件包 .地址如下:
硬件框架說明
主控芯片 | STM32H750XBH6 | Cortex-M系列高性能處理器,M7內(nèi)核,主頻400MHz |
---|---|---|
超聲波測距模塊 | SR04 | 可提供 2cm - 400cm 的非接觸式距離感測功能 |
電機驅(qū)動板 | L298P直流電機驅(qū)動模塊 | 4路直流電機驅(qū)動模塊 |
小車車架 | 4輪驅(qū)動 | 智能小車底盤套件 |
供電模塊 | 2節(jié) 18650 | 3.7V 大容量鋰電池 |
硬件方案 直接使用 ART-Pi開發(fā)板,使用的外設(shè)說明如下:
-
按鍵用來啟動小車,停止小車;
-
測距模塊使用定期器來換算 距離;
-
直流電機驅(qū)動模塊使用PWM 驅(qū)動;
-
led 顯示系統(tǒng)正常運行;
接線說明:這個系統(tǒng)使用到的引腳如下
超聲波 ? TRIG PB1 ? ECHO PB2 ? 定時器13. ? PWM: 有網(wǎng)友說用到 time2 --- 2,3 tim5 兩個引腳 。 ? 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 ? ?
軟件流程:
-
上電開機 led 顯示系統(tǒng)正常運行;
-
電機控制線程 接收按鍵信號 啟動信號量 ,啟動電機 直行,;
-
sr04 超聲波測距模塊線程 接收到啟動信號后 ,開始測距,并將測量數(shù)據(jù)發(fā)給 通過郵箱 發(fā)給 電機控制線程;
-
電機控制線程通過郵箱 接收到距離數(shù)據(jù)判斷有障礙物,就左轉(zhuǎn),直行;
-
電機控制線程接收到按鍵 停止信號 停止信號量 ,然后停車。
軟件模塊說明
(介紹應(yīng)用軟件關(guān)鍵部分的邏輯、采用的實現(xiàn)方式等)
1.電機控制模塊處理
電機控制模塊,主要控制電機的直行 轉(zhuǎn)向 ,停止 及對接收到的距離數(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); /* 永久方式等待信號量,獲取到信號量,則執(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(); } /* 延時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 是否可以正常輸出波形。
可以通過命令:來測試。遇到過 有下面波形,但和電機程序結(jié)合起來的話,沒有輸出波形。
msh />pwm_set pwm5 2 1000 500
msh />pwm_e
pwm_enable
msh />pwm_enable pwm5 2
msh />pwm_disable pwm5 2
② 有個電機控制引腳,PA15,初始就是高電平,導(dǎo)致一上電就轉(zhuǎn),換一個其他引腳。
③先把幾個引腳都先調(diào)通,對應(yīng)起來,可以通過直接將引腳接高電平的方式,來測試,因為線不一定接的對??梢韵雀鶕?jù)引腳的分布,初步先列出來控制引腳序號。然后再通過調(diào)試,進行調(diào)整。
④ 通過第一步調(diào)試,證明pwm 驅(qū)動沒有問題,但任然出現(xiàn)過 robot 程序 沒有輸出pwm 波形,原因分析如下:
通過單步調(diào)試,發(fā)現(xiàn)最終只是設(shè)置了速度,并沒有最后的運行。也就是這句 chassis_update(chas);
⑤ 有波形 但占空比很低的話,電機也跑不起來,可以在
rt_pwm_set(mot_sub->pwm_dev, mot_sub->channel, MOTOR_PWM_PERIOD, pluse + 28000 );//50 000 在一半的 基礎(chǔ)上增加。
⑥ 調(diào)試其他幾個方向,比如不動的話,可以實時調(diào)整參數(shù)。比如下面幾個:
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ā)送開始 和停止信號。
關(guān)鍵代碼:
#define USER_KEY_1 GET_PIN(H,4) static rt_uint8_t flag_start = 0; /* 指向信號量的指針 */ 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ā)給電機控制模塊。關(guān)鍵代碼分析:
為什么這里選擇郵箱作為兩個線程間通信的方式?
(1)郵箱的開銷比較低,效率高;
(2)非阻塞方式的郵件發(fā)送過程能夠安全地應(yīng)用于中斷服務(wù)中,是線程,中斷服務(wù),定期器想線程發(fā)送消息的有效手段。
如何用郵箱來發(fā)送一個傳感器接收的數(shù)據(jù)?
(1)
為什么這里選擇郵箱作為兩個線程間通信的方式?
(1)郵箱的開銷比較低,效率高;
(2)非阻塞方式的郵件發(fā)送過程能夠安全地應(yīng)用于中斷服務(wù)中,是線程,中斷服務(wù),定期器想線程發(fā)送消息的有效手段。
如何用郵箱來發(fā)送一個傳感器接收的數(shù)據(jù)?
(1) 就是如何發(fā)送這個數(shù)據(jù)結(jié)構(gòu)的地址,然后接收線程可以解析這個數(shù)據(jù)接收,也就是通過郵箱發(fā)送指定數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)。直接取這個數(shù)據(jù)結(jié)構(gòu)的地址,接收線程,定義一個 對應(yīng)數(shù)據(jù)結(jié)構(gòu)的指針,然后取 & 這個地址,取出數(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)正常運行指示。
關(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ù)會在這個地址添加完整版。
(1)小車
(2) 超聲波測距
電機控制演示
完整視頻
第一次下地視頻
比賽感悟
雖然實現(xiàn)的功能很簡單,但是完全利用時間搞要搞成功,還是挺不容易的,還是整體的時間安排不好。主要收獲是對rt-thread 的線程間的同步和通信增強了認(rèn)識和體驗,實踐出真知,多多參與這樣的活動。給主辦方點個贊。
主要克服的難點:
(1)是之前pwm 驅(qū)動一直卡著,沒有進展,最后在網(wǎng)友的支援下順利解決,主要是初始化時候,沒有使能相應(yīng)的時鐘,陷在完全按照之前添加bsp 的方式搞,沒明白這其中的細(xì)節(jié),感謝網(wǎng)友支持;
(2)還有就是郵箱發(fā)送 結(jié)構(gòu)體數(shù)據(jù)的正確的接收和發(fā)送處理。
主要收獲:
(1)第一次使用H7 高性能MCU, 很多處理方式跟之前不一樣,比如燒錄方式,也折騰了好幾天,這個過程中,收獲不少
(2) 這個art pi 開發(fā)板 很不錯的學(xué)習(xí)平臺,也開源了挺多好的擴展板項目,后續(xù)希望可以搞一個專門的小車方面的擴展板,應(yīng)該挺不錯的,很好玩。