stm32零基础从知识总结到实践:基于openmv的32循迹小车

您所在的位置:网站首页 小车循迹算法 stm32零基础从知识总结到实践:基于openmv的32循迹小车

stm32零基础从知识总结到实践:基于openmv的32循迹小车

2023-08-24 09:32| 来源: 网络整理| 查看: 265

功能实现:利用openmv模块识别轨迹,基于各模块和软件控制实现pid循迹功能

技术模块概述:

        1.openmv模块(与stm32的uart通信,识别轨迹&线性回归返回直线数据)

        2.STM32各软件功能:GPIO输入输出操作 / USART串口通信 / 

                                             PWM控制 / 中断操作 / 编码器使用

        3.pid算法:速度环 / 位置环 & pid调试

/*大家也可以在此基础上添加 避障/蓝牙遥控 等功能*/

一,openmv模块

想要把openmv玩明白,建议去详细学习opencv库的各种函数。本文我们只是简单应用。

代码及注释如下:

THRESHOLD = (0, 32, -128, 127, -128, 127) # 颜色阈值 import sensor, image, time,lcd from pyb import UART import ustruct # 本处为初始化操作,各类运用此处操作大同小异 uart = UART(3,115200,bits=8, parity=None, stop=1, timeout_char = 1000) sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QQQVGA) sensor.set_vflip(True) sensor.set_hmirror(True) sensor.skip_frames(time = 2000) # If you use QQVGA it may take seconds clock = time.clock() # 传输函数 def sending_data(data1): global uart; data=bytearray([0xA5,data1,0XA6]) uart.write(data); # !!!必须要传入一个字节数组 while(True): clock.tick() img = sensor.snapshot().binary([THRESHOLD]) line = img.get_regression([(100,100)], robust = True) # 线性回归函数 if (line): if line.theta()>90: theta_err = line.theta()-90 else: theta_err = 90 - line.theta() #处理后:绝对值为直线同Y+轴的夹角,右正左负 img.draw_line(line.line(), color = 127) err = 90 if line.magnitude()>10: sending_data((int)(theta_err)) time.sleep_ms(50) else: sending_data((int)('0xE5')) #错误标志位 print(line.magnitude(),theta_err)

二,STM32 ***

1.GPIO口输入输出模式

GPIO_Mode_AIN    模拟输入    //电压信号直接输入到片上外设,如ADC等 GPIO_Mode_IN_FLOATING    浮空输入   // 使用较多,电平高低由外部输入决定 GPIO_Mode_IPD    下拉输入  //默认输出低电平 GPIO_Mode_IPU    上拉输入  //默认输出高电平

GPIO_Mode_Out_OD    开漏输出   //  使用较少,自行搜寻

GPIO_Mode_AF_OD    复用开漏输出  // 用于特定场景,如iic GPIO_Mode_Out_PP    推挽输出  //  使用较多,可以输出高低电平,如led GPIO_Mode_AF_PP    复用推挽输出   // 主要用在具有复用功能的情况下,比如USART的TX引脚

例:控制led灯亮灭

void LED_Init(void) //PB8 { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOA, GPIO_Pin_2); } void LED_ON(void) { GPIO_ResetBits(GPIOA, GPIO_Pin_2); } void LED_OFF(void) { GPIO_SetBits(GPIOA, GPIO_Pin_2); }

2,PWM输出控制

定时器有输入捕获和输出比较两种模式(前者只读,后者只写)

下为PWM控制电机转速示例,为定时器输出比较功能,用setcompare函数设置速度

void TIM3_PWM_Init(u16 arr,u16 psc) { //make structure GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // open RCC RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE); // GPIO_Init GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);//TIM3通道2 // TIM_TimeBaseStructure_Init TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_Prescaler =psc; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // TIM_OC_Init TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM3, &TIM_OCInitStructure); TIM_Cmd(TIM3, ENABLE); }

3.编码器使用

PWM可以通过占空比设置速度值,但是由于外界干扰存在,error不可避免。此时我们就引入了pid闭环控制,而编码器负责的是测量小车的速度值,用于后续的pid计算。

void Encoder_Init_TIM2(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器2的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PB端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; //端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始GPIOB TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器 TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3 TIM_ICStructInit(&TIM_ICInitStructure); TIM_ICInitStructure.TIM_ICFilter = 10; TIM_ICInit(TIM2, &TIM_ICInitStructure); TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //Reset counter TIM_SetCounter(TIM2,0); TIM_Cmd(TIM2, ENABLE); }

之后通过中断函数调取编码器的值,从而计算速度

4.pid控制

原理简单,实操要求较高,可以去搜索专业教程

5.usart串口通信 

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3