赞
踩
功能实现:利用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 © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。