当前位置:   article > 正文

stm32零基础从知识总结到实践:基于openmv的32循迹小车_agv智能小车设计与控制 openmv

agv智能小车设计与控制 openmv

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

技术模块概述:

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

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

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

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

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

一,openmv模块

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

代码及注释如下:

  1. THRESHOLD = (0, 32, -128, 127, -128, 127) # 颜色阈值
  2. import sensor, image, time,lcd
  3. from pyb import UART
  4. import ustruct
  5. # 本处为初始化操作,各类运用此处操作大同小异
  6. uart = UART(3,115200,bits=8, parity=None, stop=1, timeout_char = 1000)
  7. sensor.reset()
  8. sensor.set_pixformat(sensor.RGB565)
  9. sensor.set_framesize(sensor.QQQVGA)
  10. sensor.set_vflip(True)
  11. sensor.set_hmirror(True)
  12. sensor.skip_frames(time = 2000) # If you use QQVGA it may take seconds
  13. clock = time.clock()
  14. # 传输函数
  15. def sending_data(data1):
  16. global uart;
  17. data=bytearray([0xA5,data1,0XA6])
  18. uart.write(data); # !!!必须要传入一个字节数组
  19. while(True):
  20. clock.tick()
  21. img = sensor.snapshot().binary([THRESHOLD])
  22. line = img.get_regression([(100,100)], robust = True) # 线性回归函数
  23. if (line):
  24. if line.theta()>90:
  25. theta_err = line.theta()-90
  26. else:
  27. theta_err = 90 - line.theta()
  28. #处理后:绝对值为直线同Y+轴的夹角,右正左负
  29. img.draw_line(line.line(), color = 127)
  30. err = 90
  31. if line.magnitude()>10:
  32. sending_data((int)(theta_err))
  33. time.sleep_ms(50)
  34. else:
  35. sending_data((int)('0xE5')) #错误标志位
  36. 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灯亮灭

  1. void LED_Init(void) //PB8
  2. {
  3. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  4. GPIO_InitTypeDef GPIO_InitStructure;
  5. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  6. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  7. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  8. GPIO_Init(GPIOB, &GPIO_InitStructure);
  9. GPIO_SetBits(GPIOA, GPIO_Pin_2);
  10. }
  11. void LED_ON(void)
  12. {
  13. GPIO_ResetBits(GPIOA, GPIO_Pin_2);
  14. }
  15. void LED_OFF(void)
  16. {
  17. GPIO_SetBits(GPIOA, GPIO_Pin_2);
  18. }

2,PWM输出控制

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

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

  1. void TIM3_PWM_Init(u16 arr,u16 psc)
  2. {
  3. //make structure
  4. GPIO_InitTypeDef GPIO_InitStructure;
  5. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  6. TIM_OCInitTypeDef TIM_OCInitStructure;
  7. // open RCC
  8. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
  9. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE);
  10. // GPIO_Init
  11. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //
  12. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  13. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  14. GPIO_Init(GPIOA, &GPIO_InitStructure);//TIM3通道2
  15. // TIM_TimeBaseStructure_Init
  16. TIM_TimeBaseStructure.TIM_Period = arr;
  17. TIM_TimeBaseStructure.TIM_Prescaler =psc;
  18. TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  19. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  20. TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
  21. // TIM_OC_Init
  22. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
  23. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  24. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  25. TIM_OC2Init(TIM3, &TIM_OCInitStructure);
  26. TIM_Cmd(TIM3, ENABLE);
  27. }

3.编码器使用

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

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

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


4.pid控制

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


5.usart串口通信 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/913643
推荐阅读
相关标签
  

闽ICP备14008679号