本項目是博主在本科期間和同學一起制作的一個實訓項目,關鍵代碼以后會放出。
這是我們測試的視頻
項目背景分析
機器人曾經是科幻電影中的形象,可目前已經漸漸走入我們的生活。機器人技術以包含機械、電子、自動控制、計算機、人工智能、傳感器、通訊與網絡等多個學科和領域為代表,是多種高新技術發展成果的綜合集成,因此,它的發展與眾多學科發展密切相關,代表了高科技發展的前沿。
隨著電子技術的不斷發展,人們發明了各式各樣的具有感知,決策,行動和交互能力的機器人,從機器人的構想到今天機器人的相對普及,機器人的應用已經遍及機械、電子、冶金、交通、宇航、國防等多個領域。并且隨著機器人的智能化水平不斷提高,并且迅速的改變著人們的生活方式,隨著它在人類生活領域中的應用不斷擴大,將會給人們的生產生活帶來了巨大的影響。
在國外機器人的發展有如下趨勢。一方面機器人在制造業應用的范圍越來越廣闊,其標準化、模塊化、網絡化和智能化的程度越來越高,功能也越來越強,并向著技術和裝備成套化的方向發展;另一方面,機器人向著非制造業應用以及,微小型方向發展。
智能小車可以理解為機器人的一種特例,它是一種能夠通過編程手段,在智能小車的基礎上,添加上了新的功能。
項目知識背景分析
本次項目我們的SLAM算法的超視距機器人,其基礎機械框架是一個三輪的智能小車,集成使用了樹莓派,STM32等物聯網多種設備。
在物聯網應用中有兩項關鍵技術:
傳感器技術:這也是計算機應用中的關鍵技術。大家都知道,到目前為止絕大部分計算機處理的都是數字信號。自從有計算機以來就需要傳感器把模擬信號轉換成數字信號計算機才能處理。嵌入式系統技術:是綜合了計算機軟硬件、傳感器技術、集成電路技術、電子應用技術為一體的復雜技術。經過幾十年的演變,以嵌入式系統為特征的智能終端產品隨處可見;小到人們身邊的MP3,大到航天航空的衛星系統。嵌入式系統正在改變著人們的生活,推動著工業生產以及國防工業的發展。如果把物聯網用人體做一個簡單比喻,傳感器相當于人的眼睛、鼻子、皮膚等感官,網絡就是神經系統用來傳遞信息,嵌入式系統則是人的大腦,在接收到信息后要進行分類處理。這個例子很形象的描述了傳感器、嵌入式系統在物聯網中的位置與作用。
樹莓派是為學習計算機編程教育而設計,只有信用卡大小的微型電腦,其系統基于Linux。自問世以來,受眾多計算機發燒友和創客的追捧,曾經一“派”難求。別看其外表“嬌小”,內“心”卻很強大,視頻、音頻等功能通通皆有,可謂是“麻雀雖小,五臟俱全”。
STM32系列基于專為要求高性能、低成本、低功耗的嵌入式應用專門設計的ARM Cortex?-M0,M0+,M3, M4和M7內核。Stm32 使用的是Cortex-M4構架, ARMCortex?-M4處理器是由ARM專門開發的最新嵌入式處理器,在M3的基礎上強化了運算能力,新加了浮點、DSP、并行計算等,用以滿足需要有效且易于使用的控制和信號處理功能混合的數字信號控制市場。其高效的信號處理功能與Cortex-M處理器系列的低功耗、低成本和易于使用的優點的組合,旨在滿足專門面向電動機控制、汽車、電源管理、嵌入式音頻和工業自動化市場的新興類別的靈活解決方案。
??關鍵詞:
激光雷達
超視距
SLAM是同步定位與地圖構建(Simultaneous Localization And Mapping)的縮寫,SLAM主要用于解決移動機器人在未知環境中運行時定位導航與地圖構建的問題。
SLAM通常包括如下幾個部分,特征提取,數據關聯,狀態估計,狀態更新以及特征更新等。對于其中每個部分,均存在多種方法。針對每個部分,我們將詳細解釋其中一種方法。在實際使用過程中,讀者可以 使用其他的方法代替本文中說明的方法。這里,我們以室內環境中運行的移動機器人為例進行說明,讀者可以將本文提出的方法應用于其他的環境以及機器人中。
項目過程分析
圖1.2項目基本框架
文中根據設計內容和要求,制定了設計方案,并逐步完成了硬件和軟件部分的設計。 **主控單元方案**:計算機、樹莓派和stm三者的連接與信息互通,實現對電機、雷達等各方面的控制。 **電機驅動方案**:這一部分是解決的是如何帶動電機,stm32輸出給驅動,驅動放大信號給電機。 **通訊方案**:計算機與樹莓派的通信,樹莓派與stm32之間的通信。 **環境感知方案**:用slam算法實現激光雷達的環境感知。 **計算機軟件端方案**:用代碼輸出PWM實現對電機控制、串口通信與無線通信、sdk完成slam算法。 整個系統以STM32F4為主控芯片,實現對小車簡單運動的控制;軟件部分在STM32集成開發環境Keil下編寫各模塊程序,包括PWM波輸出模塊、雷達模塊等等,通過主控制程序將各模塊融合一起。整個設計將硬件與軟件相結合,實現對小車的控制,使小車能夠做出前進、后退、左轉、右轉等動作,并通過計算機段的指令,及對小車速度進行調節,在本次設計中將PWM 波占空比控制在50%以下,使小車不會因速度過高而導致轉彎過程中其方向不易控制。本設計與實際應用相結合,利用高性能的STM32F407芯片,輔以雷達、樹莓派、電機驅動模塊、PWM電機,通過高可靠性的軟件設計,來實現小車的智能控制,具有很強的現實意義。
2.系統整體構架
整個系統以STM32F4為主控芯片,實現對小車簡單運動的控制;軟件部分在STM32集成開發環境Keil下編寫各模塊程序,包括PWM波輸出模塊、雷達模塊等等,通過主控制程序將各模塊融合一起。整個設計將硬件與軟件相結合,實現對小車的控制,使小車能夠做出前進、后退、左轉、右轉等動作,并通過計算機的指令,及對小車速度進行調節,在本次設計中將PWM 波占空比控制在50%以下,使小車不會因速度過高而導致轉彎過程中其方向不易控制。本設計與實際應用相結合,利用高性能的STM32F407芯片,輔以雷達、樹莓派、電機驅動模塊、直流減速電機,通過高可靠性的軟件設計,來實現小車的智能控制,具有很強的現實意義。
系統功能設計:
(1)電機驅動模塊:
使用端口GPIO來連接電機,所以給GPIO編程就可以控制電機。使用系統時鐘SysTick來周期性的給電機發送脈沖。用四個按鈕來控制需要發送脈沖的個數,每個按鈕被按下就設置給電機發送脈沖的個數,如果上一次給電機發送的脈沖沒有發送完成,這次按鈕發送的脈沖將不被響應。
+5V和GND為控制信號電源,如果控制信號為3.3V,那么+5V接3.3V;ENA、ENB分別為電機接口1和電機接口2的使能信號,可以外接PWM;IN1~IN4為兩路電機正反轉、制動(或稱剎車)控制信號。控制邏輯如表 1.2和表 1.3所示。其中0為低電平、1為高平、×為任意電平,懸空時為高電平。
IN1 IN2 ENA OUT1、OUT2輸出
× × 0 無輸出,OUT1、OUT2懸空
0 0 1 剎車,VOUT1 = VOUT2 = VGND
1 0 1 正轉,VOUT1 - VOUT2 = 電源電壓
0 1 1 反轉,VOUT2 - VOUT1 = 電源電壓
1 1 1 剎車,VOUT1 = VOUT2 = 電源電壓(未連接控制信號時的默認狀態)
圖2電機接口1控制信號邏輯
IN3 IN4 ENB OUT3、OUT4輸出
× × 0 無輸出,OUT3、OUT4懸空
0 0 1 剎車,VOUT3 = VOUT4 = VGND
1 0 1 正轉,VOUT3 - VOUT4 = 電源電壓
0 1 1 反轉,VOUT4 - VOUT3 = 電源電壓
1 1 1 剎車,VOUT3 = VOUT4 = 電源電壓
(未連接控制信號時的默認狀態)
使用STM32控制電機轉動的時候,STM32的電源與驅動板控制信號電源應共地,但不要與電機電源PGND共地。當使用5V單片機時,驅動板+5V接電源+5V;當使用3.3V單片機時,驅動板+5V接電源+3.3V。單片機和驅動板控制信號可共用一電源或各自獨立供電(但一定要共地)。ENA為與STM32的一個GPIO或PWM輸出端口相連,當ENA為高電平時,驅動板使能,正反轉或剎車有效,如果是PWM信號,那么可對電機進行調速;低電平時,驅動板禁能,電機接口無輸出。IN1和IN2與單片機的兩個GPIO相連(可支持STM32任意IO端口,無需上拉電阻),控制電機正反轉及剎車。
(2)激光雷達模塊
RPLIDAR A1 360 度激光掃描測距雷達是由SLAMTEC 公司開發的低成本二維激光雷達(LIDAR)解決方案。它可以實現在二維平面的6 米半徑范圍內進行360 度全方位的激光測距掃描,并產生所在空間的平面點云地圖信息。這些云地圖信息可用于地圖測繪、機器人定位導航、物體/環境建模等實際應用中。
在將采樣周期設為360 點采樣/周的條件下,RPLIDAR 掃描頻率達5.5hz,并且最高可達10hz 的掃描頻率。
RPLIDAR 采用由SLAMTEC 研發的低成本的激光三角測距系統,在各種室內環境以及無日光直接照射的室外環境下均表現出色。
RPLIDAR A1 主要分為激光測距核心以及使得激光測距核心高速旋轉的機械部分。在分別給各子系統供電后,測距核心將開始順時針旋轉掃描。用戶可以通過RPLIDAR A1 的通訊接口(串口/USB 等)獲取RPLIDAR 的掃描測距數據。
RPLIDAR A1 采用了激光三角測距技術,配合SLAMTEC 研發的高速的視覺采集處理機構,可進行每秒高達2000 次以上的測距動作。每次測距過程中, RPLIDAR A1 將發射經過調制的紅外激光信號,該激光信號在照射到目標物體后產生的反光將被RPLIDAR A1 的視覺采集系統接受。經過嵌入在RPLIDAR A1 內部的DSP 處理器實時解算,被照射到的目標物體與RPLIDAR A1 的距離值以及當前的夾角信息將從通訊接口中輸出。
Framegrabber的圖形化調試界面如圖6所示,這里,將雷達連接到智能機器人上,為了達成超視距的效果,我們需要通過無線網絡將計算機與樹莓派之間實現通信,然后樹莓派通過串口與STM32接通,這樣我們就能實現在計算機端對機器人的超視距控制了。
(3)SLAM算法模塊
SLAM算法首先要考慮四個方面地圖表示,信息感知問題, 數據關聯問題,定位與構圖問題。機器人在未知環境中從一個未知位置開始移動,在移動過程中根據位置估計和地圖進行自身定位,同時在自身定位的基礎上建造增量式地圖,實現機器人的自主定位和導航。
(4)通訊模塊
樹莓派和電腦連接的是同一個wifi,在wpa_supplicant.conf里配置好網絡名和密碼,實現計算機與樹莓派的通信,然后我們定好TCP協議,STM32寫好寫串口驅動,在樹莓派上打開串口,按照TCP的協議通信就完成了樹莓派與STM32之間的通信。
當然,我們也嘗試著外網通訊,現在虛擬機里將網絡連接設置成橋接模式,然后配置有線網絡的IPV4的地址、子網掩碼和網關,如圖所示。
圖7有線連接的配置
配置好以后,分別在阿里云和虛擬機下運行客戶端和服務器程序,如圖所示,最終實現信息互傳,圖8。但是最后的控制命令由外網實現還需要進一步的學習和探討。
圖8虛擬機與外網信息互傳
最終結果
我們的最終結果如圖9所示,附上幾組圖片。
Main.C程序如下,頭文件已經省略
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置系統中斷優先級分組2uart3_init(9600); //串口初始化波特率為9600BEEP_Init(); //蜂鳴器初始化delay_init(); //初始化延時函數LED_Init(); //初始化LED KEY_Init();LCD_Init();BRUSH_COLOR=RED; //設置畫筆顏色為紅色TIM3_PWM_Init(4200,1); //84M/42=2Mhz的計數頻率,重裝載值40000,所以PWM頻率為 2M/40000=50hz. //go(3000,1,4200,3000,4200,4,0,1,1);//delay_ms(1000);
/* go(3000,4200,1,3000,1,4200,0,1,1);delay_ms(1000);go(3000,1,4200,0,1,1,3000,4200,1);delay_ms(1000);go(3000,4200,1,0,1,1,3000,1,4200);delay_ms(1000);go(0,1,1,3000,1,4200,3000,4200,1);delay_ms(1000);go(0,1,1,3000,4200,1,3000,1,4200);delay_ms(1000);
*///go(0,1,1,0,1,1,0,1,1);while(1){key_scan(0);if(keyup_data==KEY0_DATA){uart3SendChars("UART3 TEST",11);}}
pwm.c里的關鍵代碼如下
void TIM3_PWM_Init(u32 auto_data,u32 fractional)
{ GPIO_InitTypeDef GPIO_InitStructureB4,GPIO_InitStructureB5,GPIO_InitStructureB0,GPIO_InitStructureB1;GPIO_InitTypeDef GPIO_InitStructureD12,GPIO_InitStructureD13;GPIO_InitTypeDef GPIO_InitStructureA0,GPIO_InitStructureA7,GPIO_InitStructureE6;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //TIM3時鐘使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //使能PORTB時鐘 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); //TIM4時鐘使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); //使能PORTD時鐘 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //TIM5時鐘使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE); //TIM5時鐘使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9,ENABLE); //TIM5時鐘使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); //使能PORTA時鐘GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_TIM3); //GPIOB4復用為定時器3GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_TIM3); //GPIOB5復用為定時器3GPIO_PinAFConfig(GPIOB,GPIO_PinSource0,GPIO_AF_TIM3); //GPIOB0復用為定時器3GPIO_PinAFConfig(GPIOB,GPIO_PinSource1,GPIO_AF_TIM3); //GPIOB1復用為定時器3GPIO_PinAFConfig(GPIOD,GPIO_PinSource12,GPIO_AF_TIM4); //GPIOD12復用為定時器4GPIO_PinAFConfig(GPIOD,GPIO_PinSource13,GPIO_AF_TIM4); //GPIOD13復用為定時器4GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5); //GPIOA0復用為定時器5 GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM14); //GPIOA0復用為定時器5GPIO_PinAFConfig(GPIOE,GPIO_PinSource6,GPIO_AF_TIM9); //GPIOA0復用為定時器5GPIO_InitStructureB4.GPIO_Pin = GPIO_Pin_4; //GPIOBGPIO_InitStructureB4.GPIO_Mode = GPIO_Mode_AF; //復用功能GPIO_InitStructureB4.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHzGPIO_InitStructureB4.GPIO_OType = GPIO_OType_PP; //推挽復用輸出GPIO_InitStructureB4.GPIO_PuPd = GPIO_PuPd_UP; //上拉GPIO_Init(GPIOB,&GPIO_InitStructureB4); //初始化PB4GPIO_InitStructureB5.GPIO_Pin = GPIO_Pin_5; //GPIOB5GPIO_InitStructureB5.GPIO_Mode = GPIO_Mode_AF; //復用功能GPIO_InitStructureB5.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHzGPIO_InitStructureB5.GPIO_OType = GPIO_OType_PP; //推挽復用輸出GPIO_InitStructureB5.GPIO_PuPd = GPIO_PuPd_UP; //上拉GPIO_Init(GPIOB,&GPIO_InitStructureB5); //初始化PB5TIM_TimeBaseStructure.TIM_Prescaler=fractional; //定時器分頻TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上計數模式TIM_TimeBaseStructure.TIM_Period=auto_data; //自動重裝載值TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);//初始化定時器3TIM_TimeBaseStructure.TIM_Prescaler=fractional; //定時器分頻TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上計數模式TIM_TimeBaseStructure.TIM_Period=auto_data; //自動重裝載值TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);//初始化定時器3TIM_TimeBaseStructure.TIM_Prescaler=fractional; //定時器分頻TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上計數模式TIM_TimeBaseStructure.TIM_Period=auto_data; //自動重裝載值TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);//初始化定時器3TIM_TimeBaseStructure.TIM_Prescaler=fractional; //定時器分頻TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上計數模式TIM_TimeBaseStructure.TIM_Period=auto_data; //自動重裝載值TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM14,&TIM_TimeBaseStructure);//初始化定時器3TIM_TimeBaseStructure.TIM_Prescaler=83; //定時器分頻TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上計數模式TIM_TimeBaseStructure.TIM_Period=auto_data; //自動重裝載值TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM9,&TIM_TimeBaseStructure);//初始化定時器3//初始化TIM3 Channel 1.2.3.4 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //選擇定時器模式:TIM脈沖寬度調制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //輸出極性:TIM輸出比較極性低
TIM_OC1Init(TIM3, &TIM_OCInitStructure); //根據T指定的參數初始化外設TIM3 4OC1
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR3上的預裝載寄存器
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //輸出極性:TIM輸出比較極性低
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根據T指定的參數初始化外設TIM3 4OC2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR3上的預裝載寄存器TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //輸出極性:TIM輸出比較極性低
TIM_OC3Init(TIM3, &TIM_OCInitStructure); //根據T指定的參數初始化外設TIM3 4OC3
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR3上的預裝載寄存器
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //輸出極性:TIM輸出比較極性低
TIM_OC4Init(TIM3, &TIM_OCInitStructure); //根據T指定的參數初始化外設TIM3 4OC4
TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR4上的預裝載寄存器
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //輸出極性:TIM輸出比較極性低
TIM_OC1Init(TIM4, &TIM_OCInitStructure); //根據T指定的參數初始化外設TIM3 4OC4
TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable); //使能TIM3在CCR4上的預裝載寄存器
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //輸出極性:TIM輸出比較極性低
TIM_OC2Init(TIM4, &TIM_OCInitStructure); //根據T指定的參數初始化外設TIM3 4OC4
TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable); //使能TIM3在CCR4上的預裝載寄存器
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //輸出極性:TIM輸出比較極性低
TIM_OC1Init(TIM5, &TIM_OCInitStructure); //根據T指定的參數初始化外設TIM3 4OC4
TIM_OC1PreloadConfig(TIM5, TIM_OCPreload_Enable); //使能TIM3在CCR4上的預裝載寄存器
TIM_ARRPreloadConfig(TIM3,ENABLE);//ARPE使能
TIM_ARRPreloadConfig(TIM4,ENABLE);//ARPE使能
TIM_ARRPreloadConfig(TIM5,ENABLE);//ARPE使能
TIM_ARRPreloadConfig(TIM14,ENABLE);//ARPE使能
TIM_ARRPreloadConfig(TIM9,ENABLE);//ARPE使能 TIM_Cmd(TIM3, ENABLE); //使能TIM3
TIM_Cmd(TIM4, ENABLE); //使能TIM3
TIM_Cmd(TIM5, ENABLE); //使能TIM3
TIM_Cmd(TIM14, ENABLE); //使能TIM3
TIM_Cmd(TIM9, ENABLE); //使能TIM3
} void duoji(int a,int b,int c, int d,int e){a=a*34+34200;b=b*24+36000;c=39200-c*20;d=d*17+36000;e=36800-e*11;}
void forward(int a,int b,int c,int d){a=a*400;b=b*400;c=c*400;d=d*400;}
void go(int D13,int D12,int B1,int B0,int A7,int E6,int A0,int B4,int B5)
{TIM_SetCompare2(TIM4,D13); //PD13 ENA數值減小,轉速增大TIM_SetCompare1(TIM4,D12); //PD12 IN1TIM_SetCompare4(TIM3,B1); //PB1 IN2TIM_SetCompare3(TIM3,B0); //PB0 ENBTIM_SetCompare1(TIM14,A7); //PA7 IN1 TIM_SetCompare2(TIM9,E6); //PE6 IN2TIM_SetCompare1(TIM5,A0); //PA0 ENA 2TIM_SetCompare1(TIM3,B4); //PB4 IN1 2
TIM_SetCompare2(TIM3,B5); //PB5 IN2 2
總結
以上是生活随笔為你收集整理的《基于slam算法的超视距小车》调研分析报告的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。