資料介紹
描述
概述
讓你的草坪在夏日的陽光下煥然一新對于房主來說通常是一件可怕的家務(wù)事。機(jī)器人割草機(jī)可以消除夏季最令人生畏的家務(wù)之一。它看起來類似于機(jī)器人吸塵器。你可以看著它在你的草坪上飛來飛去,讓你的草坪保持最佳狀態(tài)。為割草機(jī)配備支持物聯(lián)網(wǎng)的功能,例如藍(lán)牙或 Wi-Fi 連接、GPS 導(dǎo)航和靈活的調(diào)度功能,可以讓您在任何地方使用移動應(yīng)用程序控制割草機(jī)并跟蹤割草進(jìn)度。
特征
- 割草機(jī)由鋰電池供電,非常安靜,可以發(fā)送低電量警報。
- 測量割草路徑。
- 調(diào)整切割高度。
- 自動路線規(guī)劃。
- 使用移動應(yīng)用程序進(jìn)行遠(yuǎn)程控制。
?
腳步
第 1 步:硬件設(shè)計
割草機(jī)包括四個硬件部件。
- 無線連接系統(tǒng):涂鴉的網(wǎng)絡(luò)模塊允許在任何地方在移動應(yīng)用程序上遠(yuǎn)程控制和查看割草機(jī)狀態(tài)。
- 動力系統(tǒng):12V鋰電池組配合減速電機(jī)推動橡膠輪胎車輪前進(jìn)。
- 割草控制系統(tǒng):兩個伺服系統(tǒng)可調(diào)節(jié)切割高度,切割刀片和驅(qū)動輪采用無刷直流電機(jī)。
- 定位導(dǎo)航系統(tǒng):集成GNSS模塊和磁傳感器,實現(xiàn)導(dǎo)航定位能力。
無線連接系統(tǒng)
將您的 MCU 與涂鴉的網(wǎng)絡(luò)模塊對接,讓您的產(chǎn)品支持物聯(lián)網(wǎng)并連接到云端。
涂鴉提供一站式物聯(lián)網(wǎng)開發(fā)服務(wù),包括典型物聯(lián)網(wǎng)產(chǎn)品的三大要素,即網(wǎng)絡(luò)模塊、移動應(yīng)用和云服務(wù)。借助涂鴉MCU SDK、一體機(jī)APP和控制面板,您可以輕松專注于應(yīng)用開發(fā),輕松將您的產(chǎn)品接入涂鴉IoT平臺,快速享受云服務(wù)。
MCU SDK 是根據(jù)您在涂鴉物聯(lián)網(wǎng)平臺上定義的產(chǎn)品特性自動生成的。為了方便與協(xié)議的接口,MCU SDK 內(nèi)置了對通信和協(xié)議解析的支持。您可以將此 SDK 添加到現(xiàn)有項目中并完成所需的配置以實現(xiàn) MCU 程序開發(fā)。
硬件資源要求
MCU 的 SDK 要求如下。如果你的 MCU 沒有足夠的資源,你可以參考 SDK 中的函數(shù)來對接涂鴉的協(xié)議。
- 內(nèi)存:4 KB
- RAM:需要大約 100 字節(jié)的 RAM,具體取決于數(shù)據(jù)點 (DP) 的數(shù)據(jù)長度。如果啟用 OTA 更新,它必須大于 260 字節(jié)。
- 嵌套函數(shù):9 級。
選擇網(wǎng)絡(luò)模塊
涂鴉針對物聯(lián)網(wǎng)項目的各種需求,提供了一系列不同協(xié)議的模塊,如Wi-Fi 模塊、Wi-Fi 和藍(lán)牙 LE 模塊。
為了簡化開發(fā)過程,您可以選擇涂鴉三明治評估套件。
電源系統(tǒng)
電源
通常,市場上的割草機(jī)由氣體或電池供電。
燃?xì)飧畈輽C(jī)只要有足夠的燃料并且比電池供電的割草機(jī)更強(qiáng)大,就可以跑很遠(yuǎn)。然而,它比電池選項產(chǎn)生更多的噪音,并在整個氣體燃燒過程中產(chǎn)生排放。
我們選擇環(huán)保鋰電池組為我們的割草機(jī)供電,以減輕噪音和污染影響。
電池
建議使用 3S 或 4S 12V 鋰離子電池。鋰離子電池的充放電倍率可以達(dá)到15C甚至超過20C,保證了強(qiáng)大的動力推動車輪前進(jìn)。如果您不選擇鋰離子電池,請選擇使用壽命長且最大輸出電流大于 5A 的電池。
我們需要一個降壓轉(zhuǎn)換器來為不同的系統(tǒng)提供輸出電壓。
降壓轉(zhuǎn)換器LM2596提供 3.3V、5V、12V 的固定輸出電壓和可調(diào)輸出版本。它具有以下特點。
- 輸入電壓范圍高達(dá) 40 V。
- 可調(diào)版本輸出電壓范圍:在線路和負(fù)載條件下最大為 1.2V 至 37V ±4%。
- 3A 輸出負(fù)載電流。
- 高效率。
- 熱關(guān)斷和限流保護(hù)。
齒輪馬達(dá)
減速電機(jī)可以定義為直流電機(jī)的延伸。它有一個連接到電機(jī)的齒輪組件,以增加扭矩并降低速度。
減速電機(jī)的額定電壓必須與電池的額定電壓相匹配。12V 電機(jī)的電源電壓范圍為 11V 至 16V。
我們選用MG513直流12V減速電機(jī),額定輸出電流0.36A。其減速比為1/60,空載轉(zhuǎn)速為183 RPM。電機(jī)可提供 2 kgf.cm 的扭矩和 6 kg 的最大負(fù)載。使用 65 mm 橡膠輪,割草機(jī)的速度可以達(dá)到 0.5 m/s。
電機(jī)具有內(nèi)置霍爾效應(yīng)傳感器。基于磁感應(yīng),我們可以得到電機(jī)的轉(zhuǎn)速,然后測量所經(jīng)過的速度和距離。
電機(jī)驅(qū)動器
東芝的TB6612FNG驅(qū)動器是一款基于 MOSFET 的雙通道 H 橋集成電路。它具有以下特點。
- 電源電壓:VM = 15V(最大值)。
- 輸出電流:I = 1.2A(平均)/3.2A(峰值)。
- 輸出低導(dǎo)通電阻:0.5Ω。
- 內(nèi)置熱關(guān)斷電路和低電壓檢測電路。
- PWM信號的開關(guān)頻率:100 kHz。
TB6612FNG 不需要散熱器,因為它比基于雙極結(jié)型晶體管 (BJT) 的驅(qū)動器(如 L298N)效率更高。外圍電路簡單,加電源濾波電容即可驅(qū)動電機(jī)。
TB6612FNG有一對驅(qū)動器,可以獨立控制兩個電機(jī)。因此,四個電機(jī)只需要兩個 TB6612FNG IC。
當(dāng)STBY
引腳為高電平時,兩個輸入信號IN1
和IN2
可以是順時針(CW)、逆時針(CCW)、短制動和停止模式等四種模式之一。
示意圖如下。
割草控制系統(tǒng)
割草控制系統(tǒng)可以調(diào)節(jié)割草高度并控制割草操作。
無刷直流電機(jī)
無刷電機(jī)沒有電刷,因此在有刷電機(jī)運行時不會產(chǎn)生電火花,大大降低了電火花對射頻遙控設(shè)備的干擾。無刷,運行時摩擦力大大降低,運行平穩(wěn),噪音低很多。這一優(yōu)勢是對穩(wěn)定性和長使用壽命的巨大支持。
我們使用 900 Kv 的無刷電機(jī)。選擇電機(jī)時,請考慮 Kv 額定值和扭矩兩個因素。無刷電機(jī)的 Kv 額定值是電機(jī)的空載轉(zhuǎn)速與連接到線圈的導(dǎo)線上的峰值電壓之比。一般來說,電機(jī)的Kv越大,電機(jī)所能產(chǎn)生的扭矩就越小。
尺寸方面,推薦使用2212電機(jī)。
電子速度控制器 (ESC)
電子速度控制器 (ESC) 是一種控制和調(diào)節(jié)電動機(jī)速度的電子電路。
我們使用 20A 電調(diào)。確保 ESC 的輸出電流與無刷電機(jī)的輸出電流匹配。
它具有以下特點。
- 用于多旋翼控制器的特殊核心程序大大提高了油門響應(yīng)。
- 特別優(yōu)化的軟件,與盤式電機(jī)具有出色的兼容性。
- 除定時外的所有設(shè)置都是預(yù)設(shè)的,使用簡單,高度智能,自適應(yīng)。
- 油門信號線采用雙絞線設(shè)計,有效降低信號傳輸中產(chǎn)生的串?dāng)_,使飛行更加平穩(wěn)。
- 專用驅(qū)動芯片的MOSFET驅(qū)動效果比由分立元件組成的普通驅(qū)動電路要好得多。
- 具有超低電阻的 MOSFET 帶來高性能和大電流耐受性。
伺服
伺服系統(tǒng)包含直流電機(jī)、控制電路、減速器、反饋機(jī)構(gòu)和其他電路。它可以根據(jù)輸入信號轉(zhuǎn)到特定位置。其內(nèi)部的電位器或角度傳感器可以感應(yīng)輸出軸的位置,從而使控制板據(jù)此準(zhǔn)確控制輸出軸的轉(zhuǎn)動。
通常,舵機(jī)有三根線:棕色或黑色一根是地線,紅色一根是電源線,橙色或白色一根是信號線。
舵機(jī)可以工作在 4V 到 6V 之間,推薦使用 5V 電壓。伺服旋轉(zhuǎn)的角度是通過調(diào)整PWM信號的占空比來實現(xiàn)的。標(biāo)準(zhǔn) PWM 信號的周期固定為 20 ms (50 Hz)。脈沖寬度在 0.5 ms 到 2.5 ms 之間,對應(yīng)伺服旋轉(zhuǎn)角度 0° 到 180°。
兩個舵機(jī)和一些金屬圓盤組成一個升降結(jié)構(gòu)來調(diào)整切割高度。
定位導(dǎo)航系統(tǒng)
定位導(dǎo)航系統(tǒng)可實現(xiàn)定位和定向。
全球?qū)Ш叫l(wèi)星系統(tǒng)定位
全球?qū)Ш叫l(wèi)星系統(tǒng) (GNSS) 是一個衛(wèi)星網(wǎng)絡(luò),用于廣播時間和軌道信息,用于導(dǎo)航和定位測量。目前,美國的全球定位系統(tǒng)(GPS)、俄羅斯的全球?qū)Ш叫l(wèi)星系統(tǒng)(GLONASS)、中國的北斗衛(wèi)星導(dǎo)航系統(tǒng)(BDS)和歐盟的伽利略系統(tǒng)都是全面運行的全球?qū)Ш叫l(wèi)星系統(tǒng)。
我們使用涂鴉的GUC300 GNSS 模塊進(jìn)行定位和導(dǎo)航。
- GUC300由高度集成的GNSS芯片UFirebird-UC6226NIS和外圍電路組成。它具有內(nèi)置SAW濾波器、低噪聲放大器(LNA)、26 MHz溫度補(bǔ)償晶體振蕩器(TCXO)等元件。它同時支持 GPS 和 BDS 衛(wèi)星導(dǎo)航系統(tǒng)。
GUC300 具有以下特點。
- 定位引擎:
64個同步跟蹤通道
熱啟動時間:<1.2秒
冷啟動靈敏度:-145 dBm。跟蹤靈敏度:-158 dBm
數(shù)據(jù)更新率:高達(dá) 10 Hz
- 定位引擎:
RF子系統(tǒng)采用寬帶設(shè)計。輸入信號的中心頻率約為 1575 MHz。
接收和跟蹤 GPS 的 1575.42 MHz L1 信號
接收和跟蹤北斗衛(wèi)星導(dǎo)航系統(tǒng)1561.098 MHz B1信號
GUC300默認(rèn)接收GPS和BDS信號,可定制為GPS+BDS、GPS+GLONASS或單GNSS系統(tǒng)。您可以提交服務(wù)單以請求所需的 GNSS 固件。
GUC300 默認(rèn)每秒輸出$GNRMC
, $GNGGA
, 和$GPGSV
句子。串口波特率為9600。我們可以解析$GNGGA
句子。
$GNGGA,071520.00,3018.12971,N,12003.84423,E,1,20,1.47,60.5,M,,M,,\*61
上述句子的字段描述如下。$GNGGA, <1>, <2>, <3>, <4>, <5>, <6>, <7>, <8>, <9>, M, <10>, M, <11> , <12>*xx
-
\$GNGGA
:句子類型標(biāo)識符。此示例指示 GGA 協(xié)議頭。 -
<1>:UTC時間,格式為
hhmmss.sss
. -
<2>:緯度,格式為
ddmm.mmmm
. 插入前導(dǎo)零。 - <3>:緯度半球,N或S(北緯或南緯)。
-
<4>:經(jīng)度,格式為
dddmm.mmmm
. 插入前導(dǎo)零。 - <5>:半球經(jīng)度,E或W(東經(jīng)或西經(jīng))。
-
<6>:GPS定位狀態(tài)。
0
: 初始化。1
: 單點定位。2
: 差別。3
: 無效的 PPS。4
: 固定解決方案。5
: 浮點解。6
: 估計。7
:手動輸入的固定值。8
:模擬模式。9
: WAAS different.xx: 從$
to開始的所有 ASCII 字符的 XOR 校驗值\*
。 - <7>:使用的衛(wèi)星數(shù),范圍從00到12。插入前導(dǎo)零。
- <8>:水平精度稀釋度(HDOP),范圍從0.5到99.9。HDOP越小,衛(wèi)星分布越好。
- <9>:海平面高度,范圍從-9999.9到9999.9。
- 以米為單位。
- <10>:地球橢球體相對于大地水準(zhǔn)面的高度,范圍從-9999.9到9999.9。
- 以米為單位。
- <11>:距離上次接收到差分 GPS 信號的秒數(shù)。如果不采用差分定位,則該字段為空。
- <12>:差分參考基站標(biāo)簽,范圍從0000到1023。插入前導(dǎo)零。
- :回車,結(jié)束標(biāo)記。
- :換行,結(jié)束標(biāo)簽。
電路原理圖
電子羅盤傳感器
我們選擇了 3 軸電子羅盤傳感器QMC5883L 。
電子羅盤由一個 3D 磁阻傳感器、一個 2 軸傾角儀和一個 MCU 組成。3D磁阻傳感器用于監(jiān)測地磁場的變化,傾角儀可以測量感應(yīng)方向與地平面之間的角度(相對于重力)。MCU 處理輸入信號并輸出??數(shù)據(jù)以補(bǔ)償硬鐵和軟鐵失真。磁力計包括 x、y 和 z 方向的三個磁阻傳感器,以相應(yīng)地測量地磁場強(qiáng)度。傳感器在每個方向上的靈敏度已根據(jù)地磁場矢量進(jìn)行了最佳校準(zhǔn)。交叉軸靈敏度已降至最低。來自傳感器的模擬輸出信號將被放大,然后發(fā)送到 MCU 進(jìn)行處理。
我們可以使用下面的公式來計算方向。
方向.x=atan2((double)Mag_data.y, (double)Mag_data.x)*57.3+180;
Mag_data.x
分別是 X 軸和Mag_data.y
Y 軸的數(shù)據(jù)。atan2
是平面的正 x 軸與其上坐標(biāo) (x, y) 給定的點之間的弧度角。將弧度值乘以 57.3 以將弧度轉(zhuǎn)換為度數(shù)。最后,將轉(zhuǎn)換后的值加上 180 度。
對于計算結(jié)果,真南為0或360,西為90,北為180,東為270。
組裝設(shè)備
設(shè)計一個安裝輪子、伺服系統(tǒng)和其他組件的底板。下載底板結(jié)構(gòu)文件。
整個組件看起來像這樣。
我們需要設(shè)計一個PCB布局來放置電機(jī)驅(qū)動器和電源等組件。確保為舵機(jī)、電機(jī)和電子羅盤的接口預(yù)留空間,以保持項目整潔。您還可以添加一些功能,例如用于警報的蜂鳴器和用于信號的 LED。
電路原理圖
最后,將 GPS、微控制器和電源單元安裝在 PCB 上,PCB 組裝完成。
第 2 步:創(chuàng)建產(chǎn)品
1.登錄涂鴉IoT平臺。
2.點擊創(chuàng)建。
3.向下滾動頁面并單擊找不到類別?在左下角。
4.填寫所需信息并點擊創(chuàng)建。
- Product Name 、Product Description和Product Model是用戶定義的。
- 選擇Wi-Fi-Bluetooth作為協(xié)議,然后單擊Create 。
5.在自定義函數(shù)部分,單擊添加以創(chuàng)建所需的函數(shù)。在函數(shù)定義步驟中,您可以根據(jù)需要添加標(biāo)準(zhǔn)函數(shù)或創(chuàng)建自定義函數(shù)。
我們設(shè)置了以下功能。
- 標(biāo)準(zhǔn)功能:方向控制
- 自定義功能:刀片位置、刀片轉(zhuǎn)速、切割長度、切割寬度、鋸齒割草模式。
6. 在設(shè)備面板選項卡的第二步中,選擇所需的面板。在設(shè)備面板的第二步,可以選擇調(diào)試友好的DIY風(fēng)格面板。
7.在硬件開發(fā)的第三步,選擇涂鴉標(biāo)準(zhǔn)模塊SDK 。
8.向下滾動頁面并找到下載文檔。點擊全部下載,下載MCU SDK開發(fā)所需的全部文件。
- 平臺上的操作就完成了。您可以使用涂鴉智能 App 使用虛擬設(shè)備進(jìn)行遠(yuǎn)程控制。
第 3 步:固件開發(fā)
在應(yīng)用程序開發(fā)之前,您需要將 MCU SDK 移植到您的項目中。
然后將通用固件和涂鴉的授權(quán)刷入網(wǎng)絡(luò)模塊。這樣,割草機(jī)就可以與云進(jìn)行通信。
演示例程還包括 FreeRTOS,以方便您的開發(fā)。
以上準(zhǔn)備工作完成后,就可以進(jìn)行應(yīng)用開發(fā)了。
下載示例代碼:tuya-iotos-embeded-mcu-demo-wifi-ble-samrt-lawn-mower
電機(jī)、伺服和電調(diào)驅(qū)動器
將四個電機(jī)連接到每個車輪以進(jìn)行運動。兩個舵機(jī)用于控制 ESC 以及連接到 ESC 的刀片的位置。ESC 控制和調(diào)節(jié)刀片旋轉(zhuǎn)的速度。
編寫上述組件的初始化程序,在servo_motor.c
.
- 為輸出 GPIO 定義宏。
#define MOTOR_PORT_1 GPIOA
#define MOTOR_PIN_1 GPIO_PIN_15
#define MOTOR_PORT_1_P GPIOD
#define MOTOR_PIN_1_P GPIO_PIN_0
#define MOTOR_PORT_1_N GPIOD
#define MOTOR_PIN_1_N GPIO_PIN_7
#define MOTOR_PORT_2 GPIOB
#define MOTOR_PIN_2 GPIO_PIN_9
#define MOTOR_PORT_2_P GPIOD
#define MOTOR_PIN_2_P GPIO_PIN_1
#define MOTOR_PORT_2_N GPIOD
#define MOTOR_PIN_2_N GPIO_PIN_2
#define MOTOR_PORT_3 GPIOB
#define MOTOR_PIN_3 GPIO_PIN_10
#define MOTOR_PORT_3_P GPIOD
#define MOTOR_PIN_3_P GPIO_PIN_3
#define MOTOR_PORT_3_N GPIOD
#define MOTOR_PIN_3_N GPIO_PIN_4
#define MOTOR_PORT_4 GPIOB
#define MOTOR_PIN_4 GPIO_PIN_11
#define MOTOR_PORT_4_P GPIOD
#define MOTOR_PIN_4_P GPIO_PIN_8
#define MOTOR_PORT_4_N GPIOD
#define MOTOR_PIN_4_N GPIO_PIN_9
#define MOTOR_CHANNEL_1 TIMER_CH_0
#define MOTOR_CHANNEL_2 TIMER_CH_1
#define MOTOR_CHANNEL_3 TIMER_CH_2
#define MOTOR_CHANNEL_4 TIMER_CH_3
#define SERVO_PORT_1 GPIOC
#define SERVO_PIN_1 GPIO_PIN_6
#define SERVO_PORT_2 GPIOC
#define SERVO_PIN_2 GPIO_PIN_7
#define BLADE_MOTOR_PORT GPIOC
#define BLADE_MOTOR_PIN GPIO_PIN_8
void servo_motor_init(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_GPIOD);
/*Configure PD1~8 Output motor Positive and Negative pin to drive wheels_1~4*/
gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, MOTOR_PIN_1_P | MOTOR_PIN_1_N | MOTOR_PIN_2_P | MOTOR_PIN_2_N | MOTOR_PIN_3_P | MOTOR_PIN_3_N | MOTOR_PIN_4_P | MOTOR_PIN_4_N);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,MOTOR_PIN_1_P | MOTOR_PIN_1_N | MOTOR_PIN_2_P | MOTOR_PIN_2_N | MOTOR_PIN_3_P | MOTOR_PIN_3_N | MOTOR_PIN_4_P | MOTOR_PIN_4_N);
gpio_bit_reset(GPIOD, MOTOR_PIN_1_P | MOTOR_PIN_1_N | MOTOR_PIN_2_P | MOTOR_PIN_2_N | MOTOR_PIN_3_P | MOTOR_PIN_3_N | MOTOR_PIN_4_P | MOTOR_PIN_4_N);
/*Configure PA15(TIMER1_CH0) Output PWM pulse to drive wheels_1*/
gpio_mode_set(MOTOR_PORT_1, GPIO_MODE_AF, GPIO_PUPD_NONE, MOTOR_PIN_1);
gpio_output_options_set(MOTOR_PORT_1, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,MOTOR_PIN_1);
gpio_af_set(MOTOR_PORT_1, GPIO_AF_1, MOTOR_PIN_1);
/*Configure PB9(TIMER1_CH1) Output PWM pulse to drive wheels_2*/
gpio_mode_set(MOTOR_PORT_2, GPIO_MODE_AF, GPIO_PUPD_NONE, MOTOR_PIN_2);
gpio_output_options_set(MOTOR_PORT_2, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,MOTOR_PIN_2);
gpio_af_set(MOTOR_PORT_2, GPIO_AF_1, MOTOR_PIN_2);
/*Configure PB10(TIMER1_CH2) Output PWM pulse to drive wheels_3*/
gpio_mode_set(MOTOR_PORT_3, GPIO_MODE_AF, GPIO_PUPD_NONE, MOTOR_PIN_3);
gpio_output_options_set(MOTOR_PORT_3, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,MOTOR_PIN_3);
gpio_af_set(MOTOR_PORT_3, GPIO_AF_1, MOTOR_PIN_3);
/*Configure PB11(TIMER1_CH3) Output PWM pulse to drive wheels_4*/
gpio_mode_set(MOTOR_PORT_4, GPIO_MODE_AF, GPIO_PUPD_NONE, MOTOR_PIN_4);
gpio_output_options_set(MOTOR_PORT_4, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,MOTOR_PIN_4);
gpio_af_set(MOTOR_PORT_4, GPIO_AF_1, MOTOR_PIN_4);
/*Configure PC6(TIMER2_CH0) Output PWM pulse to drive servo no.1*/
gpio_mode_set(SERVO_PORT_1, GPIO_MODE_AF, GPIO_PUPD_NONE, SERVO_PIN_1);
gpio_output_options_set(SERVO_PORT_1, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,SERVO_PIN_1);
gpio_af_set(SERVO_PORT_1, GPIO_AF_2, SERVO_PIN_1);
/*Configure PC7(TIMER2_CH1) Output PWM pulse to drive servo no.2*/
gpio_mode_set(SERVO_PORT_2, GPIO_MODE_AF, GPIO_PUPD_NONE, SERVO_PIN_2);
gpio_output_options_set(SERVO_PORT_2, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,SERVO_PIN_2);
gpio_af_set(SERVO_PORT_2, GPIO_AF_2, SERVO_PIN_2);
/*Configure PC8(TIMER2_CH2) Output PWM pulse to drive blade motor*/
gpio_mode_set(BLADE_MOTOR_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BLADE_MOTOR_PIN);
gpio_output_options_set(BLADE_MOTOR_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,BLADE_MOTOR_PIN);
gpio_af_set(BLADE_MOTOR_PORT, GPIO_AF_2, BLADE_MOTOR_PIN);
timer_config();
}
void timer_config(void)
{
uint16_t i = 0;
/* TIMER1 configuration: generate PWM signals with different duty cycles:
TIMER1CLK = SystemCoreClock / 120 = 1MHz */
timer_oc_parameter_struct timer_ocintpara;
timer_parameter_struct timer_initpara;
rcu_periph_clock_enable(RCU_TIMER1);
rcu_periph_clock_enable(RCU_TIMER2);
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
timer_struct_para_init(&timer_initpara);
timer_deinit(TIMER1);
timer_deinit(TIMER2);
/* TIMER1 configuration */
timer_initpara.prescaler = 119;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 500; /* 500*(1/1MHZ) = 500us */
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER1,&timer_initpara);
/* TIMER2 configuration */
timer_initpara.prescaler = 119;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 20000; /* 20000*(1/1MHZ) = 20ms */
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER2,&timer_initpara);
timer_channel_output_struct_para_init(&timer_ocintpara);
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
for(i = 0; i < 4; i++) {
timer_channel_output_config(TIMER1,i,&timer_ocintpara);
timer_channel_output_pulse_value_config(TIMER1,i,0);
timer_channel_output_mode_config(TIMER1,i,TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER1,i,TIMER_OC_SHADOW_DISABLE);
}
for(i = 0; i < 3; i++) {
timer_channel_output_config(TIMER2,i,&timer_ocintpara);
timer_channel_output_pulse_value_config(TIMER2,i,0);
timer_channel_output_mode_config(TIMER2,i,TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER2,i,TIMER_OC_SHADOW_DISABLE);
}
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(TIMER1);
timer_auto_reload_shadow_enable(TIMER2);
/* TIMER enable */
timer_enable(TIMER1);
timer_enable(TIMER2);
}
-
調(diào)整電機(jī)和舵機(jī)的PWM占空比,將占空比調(diào)整的操作封裝為通用接口。以連接到車輪的電機(jī)為例。
car_moving
用于根據(jù)輸入方向和速度調(diào)整正負(fù)電平和占空比,從而控制車輪。
void car_moving(MOVING_DIRECTION direction, uint16_t speed_value)
{
uint8_t i;
switch(direction) {
case forward:
gpio_bit_set(GPIOD, MOTOR_PIN_1_P | MOTOR_PIN_2_P | MOTOR_PIN_3_P | MOTOR_PIN_4_P);
gpio_bit_reset(GPIOD, MOTOR_PIN_1_N | MOTOR_PIN_2_N | MOTOR_PIN_3_N | MOTOR_PIN_4_N);
for(i = 0; i < 4; i++) {
timer_channel_output_pulse_value_config(TIMER1,i,speed_value);
}
break;
case right:
gpio_bit_set(GPIOD, MOTOR_PIN_1_P | MOTOR_PIN_2_P | MOTOR_PIN_3_P | MOTOR_PIN_4_P);
gpio_bit_reset(GPIOD, MOTOR_PIN_1_N | MOTOR_PIN_2_N | MOTOR_PIN_3_N | MOTOR_PIN_4_N);
//Since the two sets of wheels on the right are always faster than the left in the actual commissioning process, 60 is added to compensate
timer_channel_output_pulse_value_config(TIMER1,MOTOR_CHANNEL_1,speed_value + 60);
timer_channel_output_pulse_value_config(TIMER1,MOTOR_CHANNEL_3,speed_value + 60);
timer_channel_output_pulse_value_config(TIMER1,MOTOR_CHANNEL_2,speed_value);
timer_channel_output_pulse_value_config(TIMER1,MOTOR_CHANNEL_4,speed_value);
break;
case left:
gpio_bit_set(GPIOD, MOTOR_PIN_1_P | MOTOR_PIN_2_P | MOTOR_PIN_3_P | MOTOR_PIN_4_P);
gpio_bit_reset(GPIOD, MOTOR_PIN_1_N | MOTOR_PIN_2_N | MOTOR_PIN_3_N | MOTOR_PIN_4_N);
timer_channel_output_pulse_value_config(TIMER1,MOTOR_CHANNEL_1,speed_value);
timer_channel_output_pulse_value_config(TIMER1,MOTOR_CHANNEL_3,speed_value);
timer_channel_output_pulse_value_config(TIMER1,MOTOR_CHANNEL_2,speed_value + 50);
timer_channel_output_pulse_value_config(TIMER1,MOTOR_CHANNEL_4,speed_value + 50);
break;
case backward:
gpio_bit_reset(GPIOD, MOTOR_PIN_1_P | MOTOR_PIN_2_P | MOTOR_PIN_3_P | MOTOR_PIN_4_P);
gpio_bit_set(GPIOD, MOTOR_PIN_1_N | MOTOR_PIN_2_N | MOTOR_PIN_3_N | MOTOR_PIN_4_N);
for(i = 0; i < 4; i++) {
timer_channel_output_pulse_value_config(TIMER1,i,speed_value);
}
break;
case stop:
gpio_bit_reset(GPIOD, MOTOR_PIN_1_P | MOTOR_PIN_2_P | MOTOR_PIN_3_P | MOTOR_PIN_4_P);
gpio_bit_reset(GPIOD, MOTOR_PIN_1_N | MOTOR_PIN_2_N | MOTOR_PIN_3_N | MOTOR_PIN_4_N);
for(i = 0; i < 4; i++) {
timer_channel_output_pulse_value_config(TIMER1,i,speed_value);
}
break;
default:
break;
}
}
用于線性運動校正的比例積分微分 (PID) 算法
由于四個輪子由獨立的電機(jī)控制,即使 PWM 輸出設(shè)置為相同的占空比,錯誤和其他因素也會導(dǎo)致割草機(jī)偏離線性運動。因此,我們使用PID算法來動態(tài)調(diào)整每個車輪的實際轉(zhuǎn)速。直線運動表示四個輪子同時移動相同的距離。由于四個輪子的直徑相同,因此每個輪子的轉(zhuǎn)速應(yīng)該相同。因為電機(jī)轉(zhuǎn)速直接決定了電機(jī)編碼器輸出的脈沖數(shù),所以我們以電機(jī)編碼器單位時間內(nèi)實時輸出的脈沖數(shù)作為PID算法的輸入,占空比增量作為控制對象。我們可以不斷微調(diào)脈沖,使四個電機(jī)達(dá)到相同的值。
-
通過外部中斷對脈沖進(jìn)行計數(shù),收集電機(jī)編碼器輸出脈沖的單位時間增量。中的
movement_system_init()
函數(shù)movement.c
包括外部中斷的配置。
void movement_system_init(void)
{
rcu_periph_clock_enable(RCU_SYSCFG);
gpio_mode_set(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_0);
nvic_irq_enable(EXTI0_IRQn, 2U, 0U);
syscfg_exti_line_config(EXTI_SOURCE_GPIOC, EXTI_SOURCE_PIN0);
exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_flag_clear(EXTI_0);
gpio_mode_set(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_1);
nvic_irq_enable(EXTI1_IRQn, 2U, 0U);
syscfg_exti_line_config(EXTI_SOURCE_GPIOC, EXTI_SOURCE_PIN1);
exti_init(EXTI_1, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_flag_clear(EXTI_1);
gpio_mode_set(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_2);
nvic_irq_enable(EXTI2_IRQn, 2U, 0U);
syscfg_exti_line_config(EXTI_SOURCE_GPIOC, EXTI_SOURCE_PIN2);
exti_init(EXTI_2, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_flag_clear(EXTI_2);
gpio_mode_set(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
nvic_irq_enable(EXTI3_IRQn, 2U, 0U);
syscfg_exti_line_config(EXTI_SOURCE_GPIOC, EXTI_SOURCE_PIN3);
exti_init(EXTI_3, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_flag_clear(EXTI_3);
}
void EXTI0_IRQHandler(void)
{
if(RESET != exti_interrupt_flag_get(EXTI_0)){
move_state.encoder_pulse[0]++;
}
exti_interrupt_flag_clear(EXTI_0);
}
void EXTI1_IRQHandler(void)
{
if(RESET != exti_interrupt_flag_get(EXTI_1)){
move_state.encoder_pulse[1]++;
}
exti_interrupt_flag_clear(EXTI_1);
}
void EXTI2_IRQHandler(void)
{
if(RESET != exti_interrupt_flag_get(EXTI_2)){
move_state.encoder_pulse[2]++;
}
exti_interrupt_flag_clear(EXTI_2);
}
void EXTI3_IRQHandler(void)
{
if(RESET != exti_interrupt_flag_get(EXTI_3)){
move_state.encoder_pulse[3]++;
}
exti_interrupt_flag_clear(EXTI_3);
}
-
實現(xiàn)
forward_correction()
接口,將收集到的脈沖pulse_num
、最后一個脈沖pulse_num_old
和所需的脈沖增量standard_increment
傳遞給 PID 控制函數(shù)。調(diào)用single_motor_speed_set()
根據(jù)計算結(jié)果調(diào)整各電機(jī)的PWM占空比。
int e[4]={0},e1[4]={0},e2[4]={0}; // PID offset
float uk[4]={0.0},uk1[4]={0.0},duk[4]={0.0}; // PID output
float Kp=0.8,Ki=0.3,Kd=0.9; // PID control factors.
int out[4] = {0};
static void forward_correction(uint32_t *pulse_num, uint32_t *pulse_num_old, uint32_t standard_increment)
{
uint8_t i = 0;
for(i = 0;i < 4;i++) {
e[i] = standard_increment - (pulse_num[i] - pulse_num_old[i]);
duk[i] = (Kp*(e[i]-e1[i])+Ki*e[i])/100;
uk[i] = uk1[i] + duk[i];
out[i] = (int)uk[i];
uk1[i] = uk[i];
e2[i] = e1[i];
e1[i] = e[i];
single_motor_speed_set(i, (uint16_t)(200+(out[i]*5)));
}
return;
}
-
當(dāng)運動輪詢處理程序進(jìn)入
switch
直線運動的分支時,您可以調(diào)用forward_correction()
來調(diào)整電機(jī)速度,然后將 分配encoder_pulse
給encoder_pulse_old
。
void movement_logic_handle(void)
{
MOVE_STATE_T *p = NULL;
p = &move_state;
uint8_t i = 0;
MOVING_DIRECTION turning_state;
switch(p->todo_type) {
......
case on_the_move:
if(forward_sampling_time_flag == 20) { //20*20ms = 400ms
for(i = 0;i < 4;i++) {
pulse_test[i] = p->encoder_pulse[i]-p->encoder_pulse_old[i];
}
forward_correction(p->encoder_pulse,p->encoder_pulse_old,390);
for(i = 0;i < 4;i++) {
p->encoder_pulse_old[i] = p->encoder_pulse[i];
}
forward_sampling_time_flag = 0;
}
forward_sampling_time_flag++;
todo_judge();
break;
......
default:
break;
}
}
讓割草機(jī)旋轉(zhuǎn) 90 度
以之字形割草模式為例。當(dāng)割草機(jī)到達(dá)直線運動的終點時,它必須轉(zhuǎn)動 90 度。該todo_judge
功能用于確定旋轉(zhuǎn)運動,該運動也基于來自電機(jī)編碼器的脈沖數(shù)。將長度轉(zhuǎn)換為脈沖數(shù)。當(dāng)脈沖達(dá)到規(guī)定值時,割草機(jī)將轉(zhuǎn)動 90 度。割草機(jī)需要確定從長邊或?qū)掃呣D(zhuǎn)向以及向左或向右轉(zhuǎn)向。todo_judge()
函數(shù)有判斷switch
。分支指示割草機(jī)是case
從長邊轉(zhuǎn)向還是從寬邊轉(zhuǎn)向。case
用于判斷直線運動中的割草機(jī)是否應(yīng)轉(zhuǎn)彎。如果是,則轉(zhuǎn)彎狀態(tài)將更改(change_to_do(turning);
),并且案例分支p->run_step_flag = width_right;
將在割草機(jī)在下一個行駛階段進(jìn)入此功能時更改。如果寬度達(dá)到規(guī)定值,則表明曲折割草作業(yè)完成。
static void todo_judge(void)
{
MOVE_STATE_T *p = NULL;
p = &move_state;
switch(p->run_step_flag) {
case length_right:
if(pulse_to_distance(p->encoder_pulse[0]) >= (p->range_length_mm - 10)) {
if((p->current_angle + 900) > 3600) {
p->target_angle = p->current_angle + 900 - 3600;
}else{
p->target_angle = p->current_angle + 900;
}
change_to_do(turning);
p->run_step_flag = width_right;
}
break;
case width_right:
if(pulse_to_distance(p->encoder_pulse[0]) >= 100) {
if((p->current_angle + 900) > 3600) {
p->target_angle = p->current_angle + 900 - 3600;
}else{
p->target_angle = p->current_angle + 900;
}
change_to_do(turning);
p->run_step_flag = length_left;
width_remain_mm -= 100;
}
break;
case length_left:
if(pulse_to_distance(p->encoder_pulse[0]) >= (p->range_length_mm - 10)) {
if(p->current_angle < 900) {
p->target_angle = 3600 - (900 - p->current_angle);
}else{
p->target_angle = p->current_angle - 900;
}
change_to_do(turning);
p->run_step_flag = width_left;
}
break;
case width_left:
if(pulse_to_distance(p->encoder_pulse[0]) >= 100) {
if(p->current_angle < 900) {
p->target_angle = 3600 - (900 - p->current_angle);
}else{
p->target_angle = p->current_angle - 900;
}
change_to_do(turning);
p->run_step_flag = length_right;
width_remain_mm -= 100;
}
break;
default:
break;
}
if(width_remain_mm <= 0) {
change_to_do(to_stop);
move_state.bow_mode_switch = pdFALSE;
}
}
-
上述例程中,
p->target_angle
是目標(biāo)方位角,p->current_angle
是當(dāng)前方位角,用于控制割草機(jī)的轉(zhuǎn)向角。目標(biāo)方位角是割草機(jī)即將轉(zhuǎn)彎時的方位角加減90度得到的。并且當(dāng)前方位角是根據(jù)地磁傳感器的數(shù)據(jù)計算得出的。該QMC5883L.c
文件包含 I2C QMC5883L 的驅(qū)動程序代碼。在這里,我們使用QMC5883L_GetAngle()
來獲取當(dāng)前方位角。
void move_control_task(void *pvParameters)
{
float_xyz Mag_angle;
uint8_t test_flag = 50;
vTaskDelay(200);
QMC_Init();
QMC5883L_GetAngle(&Mag_angle);
move_state.current_angle = (int16_t)Mag_angle.x;
vTaskDelay(500);
while(1) {
if(test_flag){
vTaskDelay(20);
test_flag--;
}else if(test_flag == 0) {
vTaskDelay(20);
movement_logic_handle();
}
QMC5883L_GetAngle(&Mag_angle);
move_state.current_angle = (int16_t)Mag_angle.x;
}
}
-
方位角可用于確定轉(zhuǎn)彎操作。該
angle_correction()
界面可以確定割草機(jī)應(yīng)該左轉(zhuǎn)還是右轉(zhuǎn)或直行。該angle_correction()
接口在移動輪詢處理程序turning
的case
分支中調(diào)用。
static MOVING_DIRECTION angle_correction(void)
{
int16_t target,current = 0;
target = move_state.target_angle;
current = move_state.current_angle;
if(target < current) {
if(current - target <= 20) {
return forward;
}
if(current - target <= 1800) {
return left;
}else{
return right;
}
}else if(target > current) {
if(target - current <= 20) {
return forward;
}
if(target - current <= 1800) {
return right;
}else{
return left;
}
}else if(current == target) {
return forward;
}
}
void movement_logic_handle(void)
{
MOVE_STATE_T *p = NULL;
p = &move_state;
uint8_t i = 0;
MOVING_DIRECTION turning_state;
switch(p->todo_type) {
......
case on_the_move:
if(forward_sampling_time_flag == 20) { //20*20ms = 400ms
for(i = 0;i < 4;i++) {
pulse_test[i] = p->encoder_pulse[i]-p->encoder_pulse_old[i];
}
forward_correction(p->encoder_pulse,p->encoder_pulse_old,390);
for(i = 0;i < 4;i++) {
p->encoder_pulse_old[i] = p->encoder_pulse[i];
}
forward_sampling_time_flag = 0;
}
forward_sampling_time_flag++;
todo_judge();
break;
case turning:
turning_state = angle_correction();
if(turning_state == right) {
car_full_turn(right,150);
turning_sampling_time_flag = 0;
}else if(turning_state == left) {
car_full_turn(left,150);
turning_sampling_time_flag = 0;
}else if(turning_state == forward) {
car_moving(stop,0);
turning_sampling_time_flag++;
}
if(turning_sampling_time_flag >= 25) {
p->todo_type = on_the_move;
car_moving(forward,200);
forward_sampling_time_flag = 0;
turning_sampling_time_flag = 0;
for(i = 0;i < 4;i++) {
p->encoder_pulse[i] = 0;
p->encoder_pulse_old[i] = 0;
}
}
break;
......
default:
break;
}
}
設(shè)置刀片位置和速度
刀片位置由兩個伺服系統(tǒng)控制。如果要在刀片上下移動時保持刀片的水平位置不變,則兩個舵機(jī)必須在相反的方向上改變相同的角度。兩個舵機(jī)的相反方向的角度變化必須相同。封裝一個用于設(shè)置刀片位置的接口,以位置枚舉值作為輸入。
void blade_position_set(BLADE_POSITION value)
{
switch(value) {
case low:
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_0,3100);
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_1,3000);
break;
case medium:
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_0,2800);
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_1,2700);
break;
case high:
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_0,2600);
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_1,2500);
break;
default:
break;
}
}
葉片速度由 ESC 控制并封裝在blade_speed_set();
.
void blade_speed_set(BLADE_SPEED speed)
{
switch(speed) {
case init:
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_2,1500);
break;
case off:
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_2,0);
break;
case low_speed:
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_2,1800);
break;
case medium_speed:
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_2,1900);
break;
case high_speed:
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_2,2000);
break;
default:
break;
}
}
5.接收GNSS數(shù)據(jù)
涂鴉 GNSS 模塊 GUC300 模塊通過串口通信向 MCU 發(fā)送 GNSS 數(shù)據(jù)。我們使用USART1
MCU的來接收數(shù)據(jù),因為USART0
已經(jīng)用于與Wi-Fi模塊的串行通信。
- 初始化串口:
void uart_init(void)
{
/* USART interrupt configuration */
nvic_irq_enable(USART0_IRQn, 0, 0);
nvic_irq_enable(USART1_IRQn, 1, 1);
/* enable USART clock */
rcu_periph_clock_enable(RCU_USART0);
/* connect port to USART0_Tx */
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9);
/* connect port to USART0_Rx */
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);
/* configure USART Tx as alternate function push-pull */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_9);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_9);
/* configure USART Rx as alternate function push-pull */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_10);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_10);
/* USART configure */
usart_deinit(USART0);
usart_baudrate_set(USART0,115200U);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
usart_enable(USART0);
/* enable USART clock */
rcu_periph_clock_enable(RCU_USART1);
/* connect port to USART0_Tx */
gpio_af_set(GPIOD, GPIO_AF_7, GPIO_PIN_5);
/* connect port to USART0_Rx */
gpio_af_set(GPIOD, GPIO_AF_7, GPIO_PIN_6);
/* configure USART Tx as alternate function push-pull */
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_5);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_5);
/* configure USART Rx as alternate function push-pull */
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_6);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_6);
/* USART configure */
usart_deinit(USART1);
usart_baudrate_set(USART1,9600U);
usart_receive_config(USART1, USART_RECEIVE_ENABLE);
usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
usart_enable(USART1);
/* enable USART0 receive interrupt */
usart_interrupt_enable(USART0, USART_INT_RBNE);
/* enable USART1 receive interrupt */
usart_interrupt_enable(USART1, USART_INT_RBNE);
}
-
初始化 USART 中斷處理函數(shù)。GUC300 默認(rèn)每秒輸出
$GNRMC
,$GNGGA
,$GPGSV
, 和$GPGGA
句子。我們可以解析$GPGGA
句子。 -
$GPGGA
句子包含17個字段:標(biāo)題,位置的UTC時間狀態(tài),緯度,緯度方向,經(jīng)度,經(jīng)度方向,定位質(zhì)量,正在使用的衛(wèi)星數(shù)量,精度水平稀釋,天線高度高于/低于平均海平面,天線高度單位、起伏(大地水準(zhǔn)面和WGS84橢球的關(guān)系)、起伏的單位、校正數(shù)據(jù)的年齡、差分基站ID、校驗和、句子終止符。 -
例子:
$GPGGA,014434.70,3817.13334637,N,12139.72994196,E,4,07,1.5,6.571,M,8.942,M,0.7,0016*79
- 按照上述格式處理串行數(shù)據(jù)。
#define USART_FH_len 6 // The length of the header.
char USART_FH[USART_FH_len]={'$','G','N','G','G','A'}; // Header
#define USART_FT_len 2 // The length of the trailer.
uint8_t USART_FT[USART_FT_len]={0X0D,0X0A}; // Frame trailer
uint8_t data_buf[128] = {0};
uint8_t rx_buf[128] = {0};
uint8_t buff_len = 0;
void USART1_IRQHandler(void)
{
if((RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_RBNE)) &&
(RESET != usart_flag_get(USART1, USART_FLAG_RBNE))){
rx_buf[buff_len++] = (uint8_t)usart_data_receive(USART1);
if(rx_buf[0] != USART_FH[0]) {
rx_buf[0] = 0;
buff_len = 0;
}
if(buff_len >= USART_FH_len) {
if(strncmp((char*)rx_buf,USART_FH,USART_FH_len) == 0) {
if(strncmp(&rx_buf[buff_len-2],(char*)USART_FT,USART_FT_len) == 0) {
memcpy(data_buf,rx_buf,buff_len);
memset(rx_buf,0,buff_len);
buff_len = 0;
}
}else {
memset(rx_buf,0,USART_FH_len);
buff_len = 0;
}
}
}
}
void gps_data_task(void *pvParameters)
{
MAP_POINT_t *p;
p = &map_point[point_1];
uint8_t data_len = 0;
while(1) {
vTaskDelay(100);
data_len = strlen((char*)data_buf);
if(data_len != 0){
gps_data_pick(point_1, data_buf, data_len);
memset(data_buf,0,data_len);
}
}
}
概括
恭喜!您已經(jīng)成功地制作了機(jī)器人割草機(jī)的原型。您可以添加更多酷炫和有用的功能來制作功能齊全的割草機(jī)。涂鴉物聯(lián)網(wǎng)平臺提供便捷的物聯(lián)網(wǎng)開發(fā)工具和服務(wù),旨在讓您的物聯(lián)網(wǎng)項目更輕松、更高效。查看并發(fā)現(xiàn)更多很棒的想法
?
- 割草機(jī)器人利用超聲波感應(yīng)自動檢測地形類型和障礙物
- 適用于割草機(jī)器人,商用服務(wù)型機(jī)器人的高精度陀螺儀模組GGPM61
- 檢測機(jī)器人開源分享
- 坦克機(jī)器人開源分享
- 掃地機(jī)器人開源資料 44次下載
- 無刷電機(jī)驅(qū)動器直流無刷綠籬機(jī)園林工具割草機(jī)方案
- 機(jī)器人守衛(wèi)開源分享
- 自動割草機(jī)v1開源項目
- 基于Arduino Mega 2560的自主機(jī)器人割草機(jī) 5次下載
- 英雄機(jī)器人開源
- 機(jī)器人開源案例
- 刷機(jī)機(jī)器人開源
- 基于DSP和PC的農(nóng)業(yè)機(jī)器人控制系統(tǒng) 18次下載
- 基于DSP芯片的足球機(jī)器人實現(xiàn)與設(shè)計 27次下載
- 自動割草機(jī)器人的設(shè)計
- 字節(jié)發(fā)布機(jī)器人領(lǐng)域首個開源視覺-語言操作大模型,激發(fā)開源VLMs更大潛能 562次閱讀
- 機(jī)器人技術(shù)中常用的路徑規(guī)劃算法的開源庫 1188次閱讀
- 用Arduino做一個自動割草機(jī) 2020次閱讀
- GNSS技術(shù)助力自動割草機(jī)轉(zhuǎn)型升級 692次閱讀
- 基于ES32F0101的鋰電割草機(jī)應(yīng)用 1087次閱讀
- 什么是EPSON機(jī)器人與上位機(jī)TCP通信 3436次閱讀
- 采用STC12C5410AD處理器實現(xiàn)自動割草機(jī)器人主控系統(tǒng)的設(shè)計 3007次閱讀
- 面對疫情 醫(yī)療機(jī)器人能幫上什么忙? 2236次閱讀
- dfrobotSparki機(jī)器人套裝簡介 2207次閱讀
- 醫(yī)用機(jī)器人的定義_醫(yī)用機(jī)器人發(fā)展 3257次閱讀
- 協(xié)作機(jī)器人的起源_為什么需要協(xié)作機(jī)器人 8322次閱讀
- 怎樣給割草機(jī)裝上太陽能 4420次閱讀
- 如何區(qū)分機(jī)器人、協(xié)作機(jī)器人和移動機(jī)器人? 7029次閱讀
- 軟體機(jī)器人 前所未見的機(jī)器人 3770次閱讀
- 機(jī)器人的最佳編程語言是什么?機(jī)器人十大流行編程語言匯總 3.5w次閱讀
下載排行
本周
- 1山景DSP芯片AP8248A2數(shù)據(jù)手冊
- 1.06 MB | 532次下載 | 免費
- 2RK3399完整板原理圖(支持平板,盒子VR)
- 3.28 MB | 339次下載 | 免費
- 3TC358743XBG評估板參考手冊
- 1.36 MB | 330次下載 | 免費
- 4DFM軟件使用教程
- 0.84 MB | 295次下載 | 免費
- 5元宇宙深度解析—未來的未來-風(fēng)口還是泡沫
- 6.40 MB | 227次下載 | 免費
- 6迪文DGUS開發(fā)指南
- 31.67 MB | 194次下載 | 免費
- 7元宇宙底層硬件系列報告
- 13.42 MB | 182次下載 | 免費
- 8FP5207XR-G1中文應(yīng)用手冊
- 1.09 MB | 178次下載 | 免費
本月
- 1OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 2555集成電路應(yīng)用800例(新編版)
- 0.00 MB | 33566次下載 | 免費
- 3接口電路圖大全
- 未知 | 30323次下載 | 免費
- 4開關(guān)電源設(shè)計實例指南
- 未知 | 21549次下載 | 免費
- 5電氣工程師手冊免費下載(新編第二版pdf電子書)
- 0.00 MB | 15349次下載 | 免費
- 6數(shù)字電路基礎(chǔ)pdf(下載)
- 未知 | 13750次下載 | 免費
- 7電子制作實例集錦 下載
- 未知 | 8113次下載 | 免費
- 8《LED驅(qū)動電路設(shè)計》 溫德爾著
- 0.00 MB | 6656次下載 | 免費
總榜
- 1matlab軟件下載入口
- 未知 | 935054次下載 | 免費
- 2protel99se軟件下載(可英文版轉(zhuǎn)中文版)
- 78.1 MB | 537798次下載 | 免費
- 3MATLAB 7.1 下載 (含軟件介紹)
- 未知 | 420027次下載 | 免費
- 4OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 5Altium DXP2002下載入口
- 未知 | 233046次下載 | 免費
- 6電路仿真軟件multisim 10.0免費下載
- 340992 | 191187次下載 | 免費
- 7十天學(xué)會AVR單片機(jī)與C語言視頻教程 下載
- 158M | 183279次下載 | 免費
- 8proe5.0野火版下載(中文版免費下載)
- 未知 | 138040次下載 | 免費
評論
查看更多