国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基于STM32的自動跟蹤小車

新機器視覺 ? 來源:新機器視覺 ? 作者:新機器視覺 ? 2021-03-20 09:41 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

概述

小車外形:


功能簡介

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

openMV4攝像頭

1.1 Apriltag識別與串口傳輸

AprilTag是一個視覺基準庫,在AR,機器人,相機校準領域廣泛使用。通過特定的標志(與二維碼相似,但是降低了復雜度以滿足實時性要求),可以快速地檢測標志,并計算相對位置。


Apriltag示例:

通過識別Apriltag,可以得到x,y,z三個方向的距離以及偏移角度。這里只需要三維的距離即可,通過串口傳回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+' ')#設置特定格式,以便于stm32分割取得數據 #pyb.delay(500) # print(clock.fps())

STM32主控板(型號為F407)

2.1 時鐘與中斷配置

附上stm32時鐘示意圖:

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

定時器示意圖:

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

定時器分配:

所有時鐘初始化的函數:(每個函數的詳細內容在后面)

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

2.2 串口收發與數據處理

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

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

串口中斷處理函數:

void USART1_IRQHandler(void) //串口1中斷服務程序{ u8 Res;#ifdef OS_TICKS_PER_SEC //如果時鐘節拍數定義了,說明要使用ucosII了. OSIntEnter(); #endif if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷(接收到的數據必須是0x0d 0x0a結尾) { Res =USART_ReceiveData(USART1);//(USART1->DR); //讀取接收到的數據 if((USART_RX_STA&0x8000)==0)//接收未完成 { if(USART_RX_STA&0x4000)//接收到了0x0d { if(Res!=0x0a)USART_RX_STA=0;//接收錯誤,重新開始 else USART_RX_STA|=0x8000; //接收完成了 } else //還沒收到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;//接收數據錯誤,重新開始接收 } } } } #ifdef OS_TICKS_PER_SEC //如果時鐘節拍數定義了,說明要使用ucosII了. OSIntExit(); #endif} #endif

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

/*涉及到的全局變量float data[3];//x,y,z方向的距離,浮點數形式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;//得到此次接收到的數據長度 for(t=0,j=0;t

字符串轉化為兩位小數浮點數(用于后續PID控制):

int myatof(const char *str)//此函數僅適用于兩位小數的浮點數,返回的是乘100后的int值,因float返回有錯誤{ int flag = 1;//表示正數 int res =0; u8 i=1; //小數點后兩位 while(*str != '') { if( !(*str >= '0' && *str <= '9'))//找到字符串中的第一個數字 { str++; continue; } if(*(str-1) == '-') { flag=-1;//表示是一個負數 } 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模塊用于調試時觀察數據,調試完成可以刪去,因為顯示屏很耗時,使處理速度變慢
驅動函數總覽:

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:");}

字符串顯示函數;

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 電機、舵機與編碼器

定時中斷:TIM2,用于修改電機和舵機的PWM占空比
初始化函數:

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

TIM2中斷處理函數:

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

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

void TIM8_PWM_Init(u32 arr,u32 psc){ //此部分需手動修改IO口設置 GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE); //TIM8時鐘使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC, ENABLE); //使能PORTA時鐘 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //GPIOFA GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //復用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽復用輸出 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復用為定時器1 GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_TIM8); //GPIOA9復用為定時器1 GPIO_PinAFConfig(GPIOC,GPIO_PinSource8,GPIO_AF_TIM8); //GPIOA10復用為定時器1 GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM8); //GPIOB13復用為定時器1 GPIO_PinAFConfig(GPIOB,GPIO_PinSource0,GPIO_AF_TIM8); //GPIOB14復用為定時器1 GPIO_PinAFConfig(GPIOB,GPIO_PinSource1,GPIO_AF_TIM8); //GPIOB15復用為定時器1 TIM_TimeBaseStructure.TIM_Prescaler=psc; //定時器分頻 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上計數模式 TIM_TimeBaseStructure.TIM_Period=arr; //自動重裝載值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM8,&TIM_TimeBaseStructure);//初始化定時器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); }

編碼器初始化函數:

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);//開啟TIM4時鐘 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);//開啟GPIOB時鐘 GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_TIM4);//PB6引腳復用 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; /*它的搶占優先級可以盡量設置低點*/ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;//禁用中斷,防止計數溢出而沒有相應函數,造成卡死 NVIC_Init(&NVIC_InitStructure); TIM_TimeBaseStructure.TIM_Period = 4095; //設置下一個更新事件裝入活動的自動重裝載寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler = 0; //設置用來作為TIMx時鐘頻率除數的預分頻值 不分頻 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設置時鐘分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式 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); //清除所有標志位 TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE); //允許中斷更新 TIM4->CNT = 0; TIM_Cmd(TIM4, ENABLE); //使能TIM4}

編碼器返回速度值:

/**************************************************************************函數功能:單位時間讀取編碼器計數入口參數:定時器返回 值:速度值**************************************************************************/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;}

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

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

2.5 PID控制

PID庫函數:

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

主函數中的PID調節:

z_get=data[2]; x_get=data[0]; if(z_get-z_set>0.5||z_get-z_set<-0.5)//電機PID { LED1=0; //調節時燈亮 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控制電機正反轉,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;//標志太遠,讓車停止 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)//舵機PID { LED1=0; PID_val_servo=PID_realize(x_set,x_get,1); servo_angle=((140-35)/6)*PID_val_servo+35;//線性映射,把PID的值轉化為角度35~140的舵機轉角 if(servo_angle<35)servo_angle=35; if(servo_angle>140)servo_angle=140; } LED1=1;

定時器TIM2中斷里改變占空比:

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

電源與電機驅動

3.1 L298N電機驅動板

因為后面兩路電機要求同速,故把AB兩通道用線短接,用一路PWM控制兩路電機。


下面是使用說明:

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

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

3.2 LM2596降壓模塊

手冊中的典型連接:

原理圖如下:

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

3.3 電源部分注意事項

1.電池用的是12v航模鋰電池,為了防止過放導致電池損壞,必須要在電池輸入端加一個電壓表模塊,如下圖:

2.控制部分電源和電機舵機電源分開,因為電機舵機啟動時會過大電流,導致電壓不穩定,影響芯片供電。這里LM2596給電機供電,一個LM2596給舵機供電,另一個LM2596給單片機和openMV供電。

3.控制電源和電機舵機電源分別加開關,下程序的時候先關閉電機和舵機的電源。因為此時控制器沒有給信號,電機和舵機可能會不受控制的運動。

責任編輯:lq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • STM32
    +關注

    關注

    2309

    文章

    11162

    瀏覽量

    373464
  • 攝像頭
    +關注

    關注

    61

    文章

    5091

    瀏覽量

    103124
  • 串口傳輸
    +關注

    關注

    0

    文章

    33

    瀏覽量

    2115

原文標題:基于STM32的自動跟蹤小車

文章出處:【微信號:vision263com,微信公眾號:新機器視覺】歡迎添加關注!文章轉載請注明出處。

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

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    【CW32L012小車測評】到手小車測評其中基本功能

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

    【項目實戰】基于STM32F103的智能小車(遠程控制、超聲波避障、循跡、紅外遙控)有教程代碼

    在嵌入式開發學習中,實戰項目是將理論轉化為能力的最佳載體——本次【項目實戰】聚焦基于STM32的智能小車,不僅整合了紅外遙控、微信小程序遠程物聯控制、自適應巡線、動態避障系統、交互式顯示屏五大
    的頭像 發表于 09-08 16:06 ?1508次閱讀
    【項目實戰】基于<b class='flag-5'>STM32</b>F103的智能<b class='flag-5'>小車</b>(遠程控制、超聲波避障、循跡、紅外遙控)有教程代碼

    智能小車設計源碼和圖紙資料

    智能小車設計源碼和圖紙
    發表于 08-25 15:38 ?1次下載

    低速自動駕駛與乘用車自動駕駛在技術要求上有何不同?

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

    倍加福PGV導航定位系統在自動輸送小車中的應用

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

    基于STM32藍牙控制小車系統設計(硬件+源代碼+論文)下載

    基于STM32藍牙控制小車系統設計(硬件+源代碼+論文)推薦下載!
    發表于 05-29 21:45

    【每周推薦】基于STM32開發項目實例下載(含PCB、原理圖、源碼等)

    1、手機APP遠程控制,智能家居監測、智能控制系統(含源碼)手機APP遠程控制,智能家居監測、智能控制系統(STM32L4、服務器、安卓源碼)項目實例下載!2、基于STM32藍牙控制小車系統
    的頭像 發表于 05-27 08:05 ?1244次閱讀
    【每周推薦】基于<b class='flag-5'>STM32</b>開發項目實例下載(含PCB、原理圖、源碼等)

    基于STM32藍牙控制小車系統設計(硬件+源代碼+論文) 項目實例下載

    基于STM32藍牙控制小車系統設計(硬件+源代碼+論文) 項目實例下載! 純分享帖,需要者可點擊附件免費獲取完整資料~~~【免責聲明】本文系網絡轉載,版權歸原作者所有。本文所用視頻、圖片、文字如涉及作品版權問題,請第一時間告知,刪除內容!
    發表于 05-23 20:55

    【硬核項目】STM32F103 智能小車全棧開發:紅外循跡 / 避障算法 + WiFi 遠程控制,附原理圖與代碼

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

    【零基礎逆襲軟硬件工程師】華清遠見STM32F103智能小車開發實戰,手把手帶你從硬件組裝到WiFi遠程控制,解鎖

    STM32F103智能云控小車是由華清遠見傾力打造的一款多功能智能小車,專為高校教學、學生畢業設計、創新競賽、單片機入門學習及項目實踐量身定制。這款小車集紅外遙控、遠程物聯網控制、智能
    的頭像 發表于 04-17 14:49 ?1747次閱讀
    【零基礎逆襲軟硬件工程師】華清遠見<b class='flag-5'>STM32</b>F103智能<b class='flag-5'>小車</b>開發實戰,手把手帶你從硬件組裝到WiFi遠程控制,解鎖

    水文監測中的雙軌纜道小車和鉛魚纜道小車

    ? ? ? ? ?在水文監測領域,每一次技術的革新都意味著防汛能力的躍升與生態保護水平的突破,雙軌纜道小車與鉛魚纜道小車,作為現代水文監測的“智慧雙翼”,正以高效、精準、智能的特點,為江河安瀾筑起
    的頭像 發表于 04-11 15:15 ?986次閱讀
    水文監測中的雙軌纜道<b class='flag-5'>小車</b>和鉛魚纜道<b class='flag-5'>小車</b>

    EMS小車技術特點與優勢:高效靈活的自動化輸送解決方案

    EMS小車是一種基于單軌運行的電動輸送系統,通過電力驅動實現物料的高效搬運和輸送,具有高效靈活、節能環保、多功能集成、行業適配性強等特性,廣泛應用于汽車制造、工程機械、家電生產、倉儲物流等行業自動化輸送生產線,幫助企業優化生產流程,提升
    的頭像 發表于 03-24 09:42 ?1061次閱讀
    EMS<b class='flag-5'>小車</b>技術特點與優勢:高效靈活的<b class='flag-5'>自動</b>化輸送解決方案

    汽車制造領域激光焊縫跟蹤系統的應用案例

    現在汽車制造慢慢轉向了自動化和智能化,焊接是汽車車身、零部件、車橋等部件的重要工藝,焊接的精度和效率直接影響生產成本和產品的質量。傳統焊接主要靠人工完成,受到工件裝配誤差、焊縫復雜等難題的限制。通過
    的頭像 發表于 03-17 14:58 ?851次閱讀
    汽車制造領域激光焊縫<b class='flag-5'>跟蹤</b>系統的應用案例

    使用STM32F407ZGT6芯片做小車主控時,總是在運行時芯片突然被鎖,無法下載程序怎么解決?

    在使用STM32F407ZGT6芯片做小車主控時,總是在運行時芯片突然被鎖,無法下載程序。 使用STM32 ST-LINK Utility也無法解除保護
    發表于 03-11 06:20

    船舶焊接自動化升級:激光焊縫跟蹤傳感器解決方案

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