chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

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

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

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

基于STM32的自動(dòng)跟蹤小車

新機(jī)器視覺(jué) ? 來(lái)源:新機(jī)器視覺(jué) ? 作者:新機(jī)器視覺(jué) ? 2021-03-20 09:41 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

概述

小車外形:


功能簡(jiǎn)介

利用攝像頭識(shí)別前車尾部的AprilTag,得到前車位置,傳回stm32主控板處理,使兩車在行駛時(shí)保持恒定距離,實(shí)現(xiàn)自動(dòng)跟車。

openMV4攝像頭

1.1 Apriltag識(shí)別與串口傳輸

AprilTag是一個(gè)視覺(jué)基準(zhǔn)庫(kù),在AR,機(jī)器人,相機(jī)校準(zhǔn)領(lǐng)域廣泛使用。通過(guò)特定的標(biāo)志(與二維碼相似,但是降低了復(fù)雜度以滿足實(shí)時(shí)性要求),可以快速地檢測(cè)標(biāo)志,并計(jì)算相對(duì)位置。


Apriltag示例:

通過(guò)識(shí)別Apriltag,可以得到x,y,z三個(gè)方向的距離以及偏移角度。這里只需要三維的距離即可,通過(guò)串口傳回stm32.

import sensor, image, time, math,pybfrom pyb import UART sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.QQVGA) # we run out of memory if the resolution is much bigger...sensor.skip_frames(time = 2000)sensor.set_auto_gain(False) # must turn this off to prevent image washout...sensor.set_auto_whitebal(False) # must turn this off to prevent image washout...clock = time.clock()uart = UART(3, 115200)#串口波特率 f_x = (2.8 / 3.984) * 160 # find_apriltags defaults to this if not setf_y = (2.8 / 2.952) * 120 # find_apriltags defaults to this if not setc_x = 160 * 0.5 # find_apriltags defaults to this if not set (the image.w * 0.5)c_y = 120 * 0.5 # find_apriltags defaults to this if not set (the image.h * 0.5) def degrees(radians): return (180 * radians) / math.pi while(True): clock.tick() img = sensor.snapshot() for tag in img.find_apriltags(fx=f_x, fy=f_y, cx=c_x, cy=c_y): # defaults to TAG36H11 img.draw_rectangle(tag.rect(), color = (255, 0, 0)) img.draw_cross(tag.cx(), tag.cy(), color = (0, 255, 0)) print_args = (tag.x_translation(), tag.y_translation(), tag.z_translation()) #degrees(tag.x_rotation()), degrees(tag.y_rotation()), degrees(tag.z_rotation())) # Translation units are unknown. Rotation units are in degrees. # print("Tx %f, Ty %f, Tz %f" % print_args) uart.write("A%.2f,B%.2f,C%.2f," % print_args+' ')#設(shè)置特定格式,以便于stm32分割取得數(shù)據(jù) #pyb.delay(500) # print(clock.fps())

STM32主控板(型號(hào)為F407)

2.1 時(shí)鐘與中斷配置

附上stm32時(shí)鐘示意圖:

0b28815e-88ef-11eb-8b86-12bb97331649.png

定時(shí)器示意圖:

0b770856-88ef-11eb-8b86-12bb97331649.png

定時(shí)器分配:

所有時(shí)鐘初始化的函數(shù):(每個(gè)函數(shù)的詳細(xì)內(nèi)容在后面)

TIM8_PWM_Init(400-1,20-1); //用于控制電機(jī),168M/20=8.4Mhz的計(jì)數(shù)頻率,重裝載值400,所以PWM頻率為 8.4M/400=21Khz. TIM3_PWM_Init(200-1,8400-1);//用于控制舵機(jī),50HZ TIM2_Int_Init(400-1,20-1);//定時(shí)中斷,21KHZ TIM7_Int_Init(500-1,8400-1);//用于編碼器計(jì)數(shù),20HZ,50ms中斷一次 uart_init(115200); //初始化串口1波特率為115200 Encoder_Init_TIM4();//編碼器接口初始化

2.2 串口收發(fā)與數(shù)據(jù)處理

串口中斷:USART1,USART2
串口初始化函數(shù)(以USART1為例):

void uart_init(u32 bound){ //GPIO端口設(shè)置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA時(shí)鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1時(shí)鐘 //串口1對(duì)應(yīng)引腳復(fù)用映射 GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9復(fù)用為USART1 GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10復(fù)用為USART1 //USART1端口配置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9與GPIOA10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//復(fù)用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽復(fù)用輸出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10 //USART1 初始化設(shè)置 USART_InitStructure.USART_BaudRate = bound;//波特率設(shè)置 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長(zhǎng)為8位數(shù)據(jù)格式 USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個(gè)停止位 USART_InitStructure.USART_Parity = USART_Parity_No;//無(wú)奇偶校驗(yàn)位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無(wú)硬件數(shù)據(jù)流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發(fā)模式 USART_Init(USART1, &USART_InitStructure); //初始化串口1 USART_Cmd(USART1, ENABLE); //使能串口1 USART_ClearFlag(USART1, USART_FLAG_TC); #if EN_USART1_RX USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開(kāi)啟相關(guān)中斷 //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中斷通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//搶占優(yōu)先級(jí)3 NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子優(yōu)先級(jí)3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根據(jù)指定的參數(shù)初始化VIC寄存器、 #endif }

串口中斷處理函數(shù):

void USART1_IRQHandler(void) //串口1中斷服務(wù)程序{ u8 Res;#ifdef OS_TICKS_PER_SEC //如果時(shí)鐘節(jié)拍數(shù)定義了,說(shuō)明要使用ucosII了. OSIntEnter(); #endif if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷(接收到的數(shù)據(jù)必須是0x0d 0x0a結(jié)尾) { Res =USART_ReceiveData(USART1);//(USART1->DR); //讀取接收到的數(shù)據(jù) if((USART_RX_STA&0x8000)==0)//接收未完成 { if(USART_RX_STA&0x4000)//接收到了0x0d { if(Res!=0x0a)USART_RX_STA=0;//接收錯(cuò)誤,重新開(kāi)始 else USART_RX_STA|=0x8000; //接收完成了 } else //還沒(méi)收到0X0D { if(Res==0x0d)USART_RX_STA|=0x4000; else { USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收數(shù)據(jù)錯(cuò)誤,重新開(kāi)始接收 } } } } #ifdef OS_TICKS_PER_SEC //如果時(shí)鐘節(jié)拍數(shù)定義了,說(shuō)明要使用ucosII了. OSIntExit(); #endif} #endif

字符串接收與處理(從openMV接收到的數(shù)據(jù)):

/*涉及到的全局變量float data[3];//x,y,z方向的距離,浮點(diǎn)數(shù)形式unsigned char data_string[3][7];//x,y,z方向的距離,字符串形式*/if(USART_RX_STA&0x8000) { //清空字符串 for(i=0;i<2;i++) { for(j=0;j<6;j++) { data_string[i][j]=' '; } } len=USART_RX_STA&0x3fff;//得到此次接收到的數(shù)據(jù)長(zhǎng)度 for(t=0,j=0;t

字符串轉(zhuǎn)化為兩位小數(shù)浮點(diǎn)數(shù)(用于后續(xù)PID控制):

int myatof(const char *str)//此函數(shù)僅適用于兩位小數(shù)的浮點(diǎn)數(shù),返回的是乘100后的int值,因float返回有錯(cuò)誤{ int flag = 1;//表示正數(shù) int res =0; u8 i=1; //小數(shù)點(diǎn)后兩位 while(*str != '') { if( !(*str >= '0' && *str <= '9'))//找到字符串中的第一個(gè)數(shù)字 { str++; continue; } if(*(str-1) == '-') { flag=-1;//表示是一個(gè)負(fù)數(shù) } while(*str >= '0' && *str <= '9') { res = res *10 + (*str - '0'); str++; } if(*str == '.') { str++; res = res *10 + (*str - '0'); str++; res = res *10 + (*str - '0');//保留兩位,故加兩次 return res*flag; } }}

2.3 LCD顯示模塊

LCD模塊用于調(diào)試時(shí)觀察數(shù)據(jù),調(diào)試完成可以刪去,因?yàn)轱@示屏很耗時(shí),使處理速度變慢
驅(qū)動(dòng)函數(shù)總覽:

void LCD_GPIO_Init(void);void Lcd_WriteIndex(u8 Index);void Lcd_WriteData(u8 Data);void Lcd_WriteReg(u8 Index,u8 Data);u16 Lcd_ReadReg(u8 LCD_Reg);void Lcd_Reset(void);void Lcd_Init(void);void Lcd_Clear(u16 Color);void Lcd_SetXY(u16 x,u16 y);void Gui_DrawPoint(u16 x,u16 y,u16 Data);unsigned int Lcd_ReadPoint(u16 x,u16 y);void Lcd_SetRegion(u16 x_start,u16 y_start,u16 x_end,u16 y_end);void LCD_WriteData_16Bit(u16 Data);

TFT屏幕初始化:

void TFT_Init_Show(void){ Lcd_Clear(WHITE); Gui_DrawFont_GBK16(16,70,BLACK,WHITE,"by WILL CHAN"); delay_ms(1000); Lcd_Clear(WHITE); Gui_DrawFont_GBK16(3,0,RED,WHITE,"X:"); Gui_DrawFont_GBK16(3,20,RED,WHITE,"Y:"); Gui_DrawFont_GBK16(3,40,RED,WHITE,"Z:"); Gui_DrawFont_GBK16(3,60,RED,WHITE,"speed:");}

字符串顯示函數(shù);

void Gui_DrawFont_GBK16(u16 x, u16 y, u16 fc, u16 bc, u8 *s){ unsigned char i,j; unsigned short k,x0; x0=x; while(*s) { if((*s) < 128) { k=*s; if (k==13) { x=x0; y+=16; } else { if (k>32) k-=32; else k=0; for(i=0;i<16;i++) for(j=0;j<8;j++) { if(asc16[k*16+i]&(0x80>>j)) Gui_DrawPoint(x+j,y+i,fc); else { if (fc!=bc) Gui_DrawPoint(x+j,y+i,bc); } } x+=8; } s++; } else { for (k=0;k>j)) Gui_DrawPoint(x+j,y+i,fc); else { if (fc!=bc) Gui_DrawPoint(x+j,y+i,bc); } } for(j=0;j<8;j++) { if(hz16[k].Msk[i*2+1]&(0x80>>j)) Gui_DrawPoint(x+j+8,y+i,fc); else { if (fc!=bc) Gui_DrawPoint(x+j+8,y+i,bc); } } } } } s+=2;x+=16; } }}

2.4 電機(jī)、舵機(jī)與編碼器

定時(shí)中斷:TIM2,用于修改電機(jī)和舵機(jī)的PWM占空比
初始化函數(shù):

//通用定時(shí)器2中斷初始化//arr:自動(dòng)重裝值。//psc:時(shí)鐘預(yù)分頻數(shù)//定時(shí)器溢出時(shí)間計(jì)算方法:Tout=((arr+1)*(psc+1))/Ft us.//Ft=定時(shí)器工作頻率,單位:Mhz//這里使用的是定時(shí)器2!void TIM2_Int_Init(u16 arr,u16 psc){ TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); ///使能TIM2時(shí)鐘 TIM_TimeBaseInitStructure.TIM_Period = arr; //自動(dòng)重裝載值 TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //定時(shí)器分頻 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上計(jì)數(shù)模式 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//初始化TIM3 TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //允許定時(shí)器2更新中斷 TIM_Cmd(TIM2,ENABLE); //使能定時(shí)器2 NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn; //定時(shí)器2中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; //搶占優(yōu)先級(jí)1 NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; //子優(yōu)先級(jí)3 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); }

TIM2中斷處理函數(shù):

void TIM2_IRQHandler(void){ if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)//溢出中斷 { if(motor_flag==1)//反轉(zhuǎn) { TIM_SetCompare1(TIM8,motor_duty*PID_val_motor*400.0);//和定時(shí)器的自動(dòng)重裝載值進(jìn)行比較,來(lái)設(shè)置占空比,引腳:PC6 TIM_SetCompare2(TIM8,0); } if(motor_flag==0)//正轉(zhuǎn) { TIM_SetCompare1(TIM8,0); TIM_SetCompare2(TIM8,motor_duty*PID_val_motor*400.0);//和定時(shí)器的自動(dòng)重裝載值進(jìn)行比較,來(lái)設(shè)置占空比,引腳:PC7 } TIM_SetCompare1(TIM3,200-(servo_angle/45.0+1)*5);//設(shè)置舵機(jī)角度,引腳:PA6 } TIM_ClearITPendingBit(TIM2,TIM_IT_Update); //清除中斷標(biāo)志位}

PWM輸出:TIM3(舵機(jī)),TIM8(電機(jī))
初始化函數(shù)(以TIM8為例):

void TIM8_PWM_Init(u32 arr,u32 psc){ //此部分需手動(dòng)修改IO口設(shè)置 GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE); //TIM8時(shí)鐘使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC, ENABLE); //使能PORTA時(shí)鐘 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //GPIOFA GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //復(fù)用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽復(fù)用輸出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA7 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; GPIO_Init(GPIOB,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8; GPIO_Init(GPIOC,&GPIO_InitStructure); GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM8); //GPIOA8復(fù)用為定時(shí)器1 GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_TIM8); //GPIOA9復(fù)用為定時(shí)器1 GPIO_PinAFConfig(GPIOC,GPIO_PinSource8,GPIO_AF_TIM8); //GPIOA10復(fù)用為定時(shí)器1 GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM8); //GPIOB13復(fù)用為定時(shí)器1 GPIO_PinAFConfig(GPIOB,GPIO_PinSource0,GPIO_AF_TIM8); //GPIOB14復(fù)用為定時(shí)器1 GPIO_PinAFConfig(GPIOB,GPIO_PinSource1,GPIO_AF_TIM8); //GPIOB15復(fù)用為定時(shí)器1 TIM_TimeBaseStructure.TIM_Prescaler=psc; //定時(shí)器分頻 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上計(jì)數(shù)模式 TIM_TimeBaseStructure.TIM_Period=arr; //自動(dòng)重裝載值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM8,&TIM_TimeBaseStructure);//初始化定時(shí)器1 //初始化PWM模式 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; TIM_OC1Init(TIM8, &TIM_OCInitStructure); TIM_OC2Init(TIM8, &TIM_OCInitStructure); TIM_OC3Init(TIM8, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM8,TIM_OCPreload_Enable); TIM_OC2PreloadConfig(TIM8,TIM_OCPreload_Enable); TIM_OC3PreloadConfig(TIM8,TIM_OCPreload_Enable); TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; TIM_BDTRInitStructure.TIM_DeadTime = 0; TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable; TIM_BDTRConfig(TIM8,&TIM_BDTRInitStructure); TIM_Cmd(TIM8,ENABLE); TIM_CCPreloadControl(TIM8,ENABLE); TIM_CtrlPWMOutputs(TIM8,ENABLE); }

編碼器初始化函數(shù):

void Encoder_Init_TIM4(void){ GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//開(kāi)啟TIM4時(shí)鐘 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);//開(kāi)啟GPIOB時(shí)鐘 GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_TIM4);//PB6引腳復(fù)用 GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_TIM4);//PB7引腳服用 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //GPIOB6,GPIOB7 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; //GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB,&GPIO_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; /*它的搶占優(yōu)先級(jí)可以盡量設(shè)置低點(diǎn)*/ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;//禁用中斷,防止計(jì)數(shù)溢出而沒(méi)有相應(yīng)函數(shù),造成卡死 NVIC_Init(&NVIC_InitStructure); TIM_TimeBaseStructure.TIM_Period = 4095; //設(shè)置下一個(gè)更新事件裝入活動(dòng)的自動(dòng)重裝載寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler = 0; //設(shè)置用來(lái)作為TIMx時(shí)鐘頻率除數(shù)的預(yù)分頻值 不分頻 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置時(shí)鐘分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計(jì)數(shù)模式 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Falling); TIM_ICStructInit(&TIM_ICInitStructure); TIM_ICInitStructure.TIM_ICFilter = 10; //輸入濾波器 TIM_ICInit(TIM4, &TIM_ICInitStructure); TIM_ClearFlag(TIM4, TIM_FLAG_Update); //清除所有標(biāo)志位 TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE); //允許中斷更新 TIM4->CNT = 0; TIM_Cmd(TIM4, ENABLE); //使能TIM4}

編碼器返回速度值:

/**************************************************************************函數(shù)功能:?jiǎn)挝粫r(shí)間讀取編碼器計(jì)數(shù)入口參數(shù):定時(shí)器返回 值:速度值**************************************************************************/float Read_Encoder_Speed(uint8_t TIMX){ int32_t Encoder_TIM; float res = 0; switch (TIMX) { case 5: Encoder_TIM = TIM_GetCounter(TIM5); TIM5->CNT = ENCODER_BASE_COUNT; res = (int32_t)Encoder_TIM - ENCODER_BASE_COUNT; break; case 4: Encoder_TIM = TIM_GetCounter(TIM4); TIM4->CNT = ENCODER_BASE_COUNT; res = (int32_t)Encoder_TIM - ENCODER_BASE_COUNT; break; default: Encoder_TIM = 0; res = 0; } if(res>2048.0f) res-=4096.0f; return res*360.0f/4096.0f;}

定時(shí)從編碼器取數(shù),注意,時(shí)間不一樣,取回的數(shù)值也不一樣,取決于實(shí)際速度以及編碼器線數(shù)。這里50ms取一次:

void TIM7_IRQHandler(void)//頻率20HZ,用于編碼器計(jì)數(shù){ if(TIM_GetITStatus(TIM7,TIM_IT_Update)==SET)//溢出中斷 { speed=Read_Encoder_Speed(4); } TIM_ClearITPendingBit(TIM7,TIM_IT_Update); //清除中斷標(biāo)志位}

2.5 PID控制

PID庫(kù)函數(shù):

#define N 2 //需要對(duì)多少變量進(jìn)行pid調(diào)節(jié) const float KP[N]={1.3,1.0};//這里只用了比例調(diào)節(jié)const float KI[N]={0,0};const float KD[N]={0,0}; struct _pid{ float SetVol; //定義設(shè)定值 float ActVol; //定義實(shí)際值 float Err; //定義誤差 float Err_Next; //定義上一個(gè)誤差 float Err_Last; //定義上上一個(gè)誤差 float Kp,Ki,Kd; //定義比例、積分、微分系數(shù) float integral; //定義積分值 float actuator; //定義控制器執(zhí)行變量}pid[N]; void PID_Init(void){ for(int i=0;i

主函數(shù)中的PID調(diào)節(jié):

z_get=data[2]; x_get=data[0]; if(z_get-z_set>0.5||z_get-z_set<-0.5)//電機(jī)PID { LED1=0; //調(diào)節(jié)時(shí)燈亮 PID_val_motor=PID_realize(z_set,z_get,0); PID_val_motor=PID_val_motor/10.0; if(PID_val_motor<=0) motor_flag=0;//motor_flag控制電機(jī)正反轉(zhuǎn),PID_val_motor用于改變占空比,范圍0~1 if(PID_val_motor>0) motor_flag=1; PID_val_motor=abs_float(PID_val_motor); if(PID_val_motor>2)PID_val_motor=0;//標(biāo)志太遠(yuǎn),讓車停止 if(PID_val_motor>1&&PID_val_motor<=2)PID_val_motor=1; if(PID_val_motor<0.2)PID_val_motor=0; } if(x_get-x_set>0.1||x_get-x_set<-0.1)//舵機(jī)PID { LED1=0; PID_val_servo=PID_realize(x_set,x_get,1); servo_angle=((140-35)/6)*PID_val_servo+35;//線性映射,把PID的值轉(zhuǎn)化為角度35~140的舵機(jī)轉(zhuǎn)角 if(servo_angle<35)servo_angle=35; if(servo_angle>140)servo_angle=140; } LED1=1;

定時(shí)器TIM2中斷里改變占空比:

void TIM2_IRQHandler(void){ if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)//溢出中斷 { if(motor_flag==1)//反轉(zhuǎn) { TIM_SetCompare1(TIM8,motor_duty*PID_val_motor*400.0);//和定時(shí)器的自動(dòng)重裝載值進(jìn)行比較,來(lái)設(shè)置占空比,引腳:PC6 TIM_SetCompare2(TIM8,0); } if(motor_flag==0)//正轉(zhuǎn) { TIM_SetCompare1(TIM8,0); TIM_SetCompare2(TIM8,motor_duty*PID_val_motor*400.0);//和定時(shí)器的自動(dòng)重裝載值進(jìn)行比較,來(lái)設(shè)置占空比,引腳:PC7 } TIM_SetCompare1(TIM3,200-(servo_angle/45.0+1)*5);//設(shè)置舵機(jī)角度,根據(jù)舵機(jī)手冊(cè)得到占空比與轉(zhuǎn)角的關(guān)系,引腳:PA6 } TIM_ClearITPendingBit(TIM2,TIM_IT_Update); //清除中斷標(biāo)志位}

電源與電機(jī)驅(qū)動(dòng)

3.1 L298N電機(jī)驅(qū)動(dòng)板

因?yàn)楹竺鎯陕冯姍C(jī)要求同速,故把AB兩通道用線短接,用一路PWM控制兩路電機(jī)。


下面是使用說(shuō)明:

0eaa7382-88ef-11eb-8b86-12bb97331649.png

具體控制代碼見(jiàn)上面TIM2中斷處理函數(shù)中,利用兩路定時(shí)器輪流輸出PWM(另一路為零),即可控制電機(jī)正反轉(zhuǎn)。

3.2 LM2596降壓模塊

手冊(cè)中的典型連接:

原理圖如下:

10938170-88ef-11eb-8b86-12bb97331649.png

3.3 電源部分注意事項(xiàng)

1.電池用的是12v航模鋰電池,為了防止過(guò)放導(dǎo)致電池?fù)p壞,必須要在電池輸入端加一個(gè)電壓表模塊,如下圖:

2.控制部分電源和電機(jī)舵機(jī)電源分開(kāi),因?yàn)殡姍C(jī)舵機(jī)啟動(dòng)時(shí)會(huì)過(guò)大電流,導(dǎo)致電壓不穩(wěn)定,影響芯片供電。這里L(fēng)M2596給電機(jī)供電,一個(gè)LM2596給舵機(jī)供電,另一個(gè)LM2596給單片機(jī)和openMV供電。

3.控制電源和電機(jī)舵機(jī)電源分別加開(kāi)關(guān),下程序的時(shí)候先關(guān)閉電機(jī)和舵機(jī)的電源。因?yàn)榇藭r(shí)控制器沒(méi)有給信號(hào),電機(jī)和舵機(jī)可能會(huì)不受控制的運(yùn)動(dòng)。

責(zé)任編輯:lq

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

    關(guān)注

    2305

    文章

    11118

    瀏覽量

    370965
  • 攝像頭
    +關(guān)注

    關(guān)注

    61

    文章

    5055

    瀏覽量

    102381
  • 串口傳輸
    +關(guān)注

    關(guān)注

    0

    文章

    33

    瀏覽量

    2087

原文標(biāo)題:基于STM32的自動(dòng)跟蹤小車

文章出處:【微信號(hào):vision263com,微信公眾號(hào):新機(jī)器視覺(jué)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    【CW32L012小車測(cè)評(píng)】到手小車測(cè)評(píng)其中基本功能

    開(kāi)箱介紹 在CW小程序中購(gòu)買了小車,其中的包裝特別好,外面有個(gè)箱子來(lái)裝著,其中我們將外包裝拆開(kāi),可以看見(jiàn)我們本次購(gòu)買的小車的本體,我購(gòu)買的是焊接完成的,所以我可以開(kāi)箱直接試用,方便很多,如果大家追求
    的頭像 發(fā)表于 11-24 22:59 ?49次閱讀
    【CW32L012<b class='flag-5'>小車</b>測(cè)評(píng)】到手<b class='flag-5'>小車</b>測(cè)評(píng)其中基本功能

    智能小車設(shè)計(jì)源碼和圖紙資料

    智能小車設(shè)計(jì)源碼和圖紙
    發(fā)表于 08-25 15:38 ?1次下載

    低速自動(dòng)駕駛與乘用車自動(dòng)駕駛在技術(shù)要求上有何不同?

    [首發(fā)于智駕最前沿微信公眾號(hào)]自動(dòng)駕駛技術(shù)的發(fā)展正朝著多元化方向邁進(jìn),其中低速自動(dòng)駕駛小車(以下簡(jiǎn)稱“低速小車”)因其在物流配送、園區(qū)運(yùn)維、社區(qū)服務(wù)等場(chǎng)景中的獨(dú)特價(jià)值而受到廣泛關(guān)注,且
    的頭像 發(fā)表于 07-14 09:10 ?651次閱讀
    低速<b class='flag-5'>自動(dòng)</b>駕駛與乘用車<b class='flag-5'>自動(dòng)</b>駕駛在技術(shù)要求上有何不同?

    倍加福PGV導(dǎo)航定位系統(tǒng)在自動(dòng)輸送小車中的應(yīng)用

    為何德國(guó)Imetron公司的自動(dòng)輸送小車總能準(zhǔn)確導(dǎo)航,行走自如?奧秘在于其內(nèi)置的倍加福PGV導(dǎo)航定位系統(tǒng),配合Mecanum車輪設(shè)計(jì),讓小車仿佛氣墊船一般,能夠輕松向任意方向移動(dòng),提升了用戶內(nèi)部物流的靈活性和空間利用率。
    的頭像 發(fā)表于 06-10 14:13 ?879次閱讀

    基于STM32藍(lán)牙控制小車系統(tǒng)設(shè)計(jì)(硬件+源代碼+論文)下載

    基于STM32藍(lán)牙控制小車系統(tǒng)設(shè)計(jì)(硬件+源代碼+論文)推薦下載!
    發(fā)表于 05-29 21:45

    【每周推薦】基于STM32開(kāi)發(fā)項(xiàng)目實(shí)例下載(含PCB、原理圖、源碼等)

    1、手機(jī)APP遠(yuǎn)程控制,智能家居監(jiān)測(cè)、智能控制系統(tǒng)(含源碼)手機(jī)APP遠(yuǎn)程控制,智能家居監(jiān)測(cè)、智能控制系統(tǒng)(STM32L4、服務(wù)器、安卓源碼)項(xiàng)目實(shí)例下載!2、基于STM32藍(lán)牙控制小車系統(tǒng)
    的頭像 發(fā)表于 05-27 08:05 ?960次閱讀
    【每周推薦】基于<b class='flag-5'>STM32</b>開(kāi)發(fā)項(xiàng)目實(shí)例下載(含PCB、原理圖、源碼等)

    基于STM32藍(lán)牙控制小車系統(tǒng)設(shè)計(jì)(硬件+源代碼+論文) 項(xiàng)目實(shí)例下載

    基于STM32藍(lán)牙控制小車系統(tǒng)設(shè)計(jì)(硬件+源代碼+論文) 項(xiàng)目實(shí)例下載! 純分享帖,需要者可點(diǎn)擊附件免費(fèi)獲取完整資料~~~【免責(zé)聲明】本文系網(wǎng)絡(luò)轉(zhuǎn)載,版權(quán)歸原作者所有。本文所用視頻、圖片、文字如涉及作品版權(quán)問(wèn)題,請(qǐng)第一時(shí)間告知,刪除內(nèi)容!
    發(fā)表于 05-23 20:55

    【硬核項(xiàng)目】STM32F103 智能小車全棧開(kāi)發(fā):紅外循跡 / 避障算法 + WiFi 遠(yuǎn)程控制,附原理圖與代碼

    今天為大家推薦一款功能強(qiáng)大的STM32多功能智能小車——華清遠(yuǎn)見(jiàn)STM32F103智能云控小車。這款小車集紅外遙控、遠(yuǎn)程物聯(lián)控制、智能循跡、
    的頭像 發(fā)表于 05-16 17:11 ?1763次閱讀
    【硬核項(xiàng)目】<b class='flag-5'>STM32</b>F103 智能<b class='flag-5'>小車</b>全棧開(kāi)發(fā):紅外循跡 / 避障算法 + WiFi 遠(yuǎn)程控制,附原理圖與代碼

    水文監(jiān)測(cè)中的雙軌纜道小車和鉛魚纜道小車

    ? ? ? ? ?在水文監(jiān)測(cè)領(lǐng)域,每一次技術(shù)的革新都意味著防汛能力的躍升與生態(tài)保護(hù)水平的突破,雙軌纜道小車與鉛魚纜道小車,作為現(xiàn)代水文監(jiān)測(cè)的“智慧雙翼”,正以高效、精準(zhǔn)、智能的特點(diǎn),為江河安瀾筑起
    的頭像 發(fā)表于 04-11 15:15 ?751次閱讀
    水文監(jiān)測(cè)中的雙軌纜道<b class='flag-5'>小車</b>和鉛魚纜道<b class='flag-5'>小車</b>

    EMS小車技術(shù)特點(diǎn)與優(yōu)勢(shì):高效靈活的自動(dòng)化輸送解決方案

    EMS小車是一種基于單軌運(yùn)行的電動(dòng)輸送系統(tǒng),通過(guò)電力驅(qū)動(dòng)實(shí)現(xiàn)物料的高效搬運(yùn)和輸送,具有高效靈活、節(jié)能環(huán)保、多功能集成、行業(yè)適配性強(qiáng)等特性,廣泛應(yīng)用于汽車制造、工程機(jī)械、家電生產(chǎn)、倉(cāng)儲(chǔ)物流等行業(yè)自動(dòng)化輸送生產(chǎn)線,幫助企業(yè)優(yōu)化生產(chǎn)流程,提升
    的頭像 發(fā)表于 03-24 09:42 ?800次閱讀
    EMS<b class='flag-5'>小車</b>技術(shù)特點(diǎn)與優(yōu)勢(shì):高效靈活的<b class='flag-5'>自動(dòng)</b>化輸送解決方案

    船舶焊接自動(dòng)化升級(jí):激光焊縫跟蹤傳感器解決方案

    提供了更加智能穩(wěn)定的解決方案,今天一起了解激光焊縫跟蹤傳感器在船舶焊接自動(dòng)化解決方案。 激光焊縫跟蹤傳感器原理 激光焊縫跟蹤傳感器基于激光視覺(jué)傳感技術(shù),通過(guò)高精度激光束掃描焊縫表面,實(shí)
    的頭像 發(fā)表于 03-10 15:05 ?585次閱讀
    船舶焊接<b class='flag-5'>自動(dòng)</b>化升級(jí):激光焊縫<b class='flag-5'>跟蹤</b>傳感器解決方案

    工業(yè)智能網(wǎng)關(guān)助力AGV小車數(shù)據(jù)采集

    在工業(yè)自動(dòng)化程度日益提升的當(dāng)下,AGV 小車已成為物流運(yùn)輸和生產(chǎn)制造的關(guān)鍵設(shè)備。要實(shí)現(xiàn)其智能化管理與高效運(yùn)行,精準(zhǔn)全面的數(shù)據(jù)采集必不可少。工業(yè)智能網(wǎng)關(guān)作為連接設(shè)備與上層系統(tǒng)的橋梁,在 AGV 小車數(shù)據(jù)采集中至關(guān)重要。
    的頭像 發(fā)表于 02-17 15:56 ?577次閱讀

    松下MPS媒體制作平臺(tái)之自動(dòng)跟蹤插件(第一部分)

    ? 歡迎大家觀看松下操作教程 MPS媒體制作平臺(tái) 第十篇:Auto Tracking(自動(dòng)跟蹤)插件 Auto Tracking(自動(dòng)跟蹤)插件是一款基于人體檢測(cè)和面部識(shí)別的高精度
    的頭像 發(fā)表于 02-08 11:15 ?1054次閱讀
    松下MPS媒體制作平臺(tái)之<b class='flag-5'>自動(dòng)</b><b class='flag-5'>跟蹤</b>插件(第一部分)

    自動(dòng)往返小車電氣原理及接線圖

    電子發(fā)燒友網(wǎng)站提供《自動(dòng)往返小車電氣原理及接線圖.docx》資料免費(fèi)下載
    發(fā)表于 01-07 14:40 ?1次下載

    AGV自動(dòng)搬運(yùn)小車基于物聯(lián)網(wǎng)的數(shù)據(jù)采集解決方案

    AGV自動(dòng)搬運(yùn)小車能夠在沒(méi)有人類直接干預(yù)的情況下,沿預(yù)定路徑或隨機(jī)路徑自主移動(dòng),以完成物料搬運(yùn)任務(wù)的自動(dòng)化設(shè)備。它主要由驅(qū)動(dòng)系統(tǒng)、導(dǎo)航系統(tǒng)、控制系統(tǒng)、安全系統(tǒng)和通信系統(tǒng)組成。AGV能夠根據(jù)預(yù)設(shè)的指令
    的頭像 發(fā)表于 12-30 14:42 ?865次閱讀
    AGV<b class='flag-5'>自動(dòng)</b>搬運(yùn)<b class='flag-5'>小車</b>基于物聯(lián)網(wǎng)的數(shù)據(jù)采集解決方案