openMV寻迹与小车控制

1.openMV介绍

官方文档:https://book.openmv.cc/quick-starter.html

下载OpenMV IDE :OpenMV下载 | 星瞳科技 (singtown.com)

openMV内置MicroPython解释器,可以使用python语言进行编写,下面是openMV寻迹的简单示例

# 导入sensor模块,该模块常用于处理摄像头和图像数据  
import sensor  
# 导入image模块,该模块常用于处理图像数据  
import image  
# 导入time模块,该模块常用于处理时间数据  
import time  
# 导入pyb模块,该模块常用于处理Pyboard的硬件接口  
import pyb  
# 从pyb模块导入UART类,该类用于创建串口连接  
from pyb import UART  
# 导入json模块,该模块用于处理JSON数据格式  
import json  
  
# 设置蓝色阈值,这通常用于在图像处理中区分不同的颜色  
blue_threshold   = (10, 50, 32, 87, -48, 57)  
  
# 重置摄像头传感器,初始化摄像头传感器  
sensor.reset() # Initialize the camera sensor.  
# 设置摄像头为水平镜像模式,这会翻转图像的水平方向  
sensor.set_hmirror(True)  
# 设置摄像头为垂直翻转模式,这会翻转图像的垂直方向  
sensor.set_vflip(True)  
# 设置图像数据的格式为RGB565,这是一种常见的颜色编码格式  
sensor.set_pixformat(sensor.RGB565)  
# 设置摄像头捕获的帧大小为QQVGA(320x240像素),这种格式能产生较清晰的图像但计算量较大  
sensor.set_framesize(sensor.QQVGA)  
# 跳过指定数量的帧,通常用于使摄像头传感器稳定下来  
sensor.skip_frames(10)  
# 关闭自动白色平衡,这通常用于手动控制图像的色彩平衡  
sensor.set_auto_whitebal(False)  
# 创建一个计时器对象,用于计算处理图像的时间  
clock = time.clock()  
  
# 创建一个UART对象,指定使用串口3,波特率为9600(串口通信的速率)  
uart = UART(3, 9600)  
  
# 定义一个函数find_max,该函数用于在给定的blob列表中找到最大的blob  
def find_max(blobs):  
    max_size=0   # 初始化最大尺寸为0  
    for blob in blobs:   # 遍历每个blob  
        if blob.pixels() > max_size:   # 如果当前blob的尺寸大于最大尺寸  
            max_blob=blob   # 将当前blob设置为最大blob  
            max_size = blob.pixels()   # 将当前blob的尺寸设置为最大尺寸  
    return max_blob   # 返回最大blob  
  
# 开始一个无限循环,不断捕获和处理图像数据直到强制停止或发生错误等特殊情况  
while(True):  
    img = sensor.snapshot()   # 从摄像头捕获一帧图像并创建一个对应的图像对象  
  
    blobs = img.find_blobs([blue_threshold])   # 在图像中找到所有满足蓝色阈值的blobs并创建一个blob列表  
    if blobs:   # 如果找到至少一个blob  
        max_blob=find_max(blobs)   # 找到最大的blob并创建一个对应的blob对象  
        img.draw_rectangle(max_blob.rect())   # 在图像上绘制最大blob的矩形框以标记它  
        img.draw_cross(max_blob.cx(), max_blob.cy())   # 在图像上绘制一个十字以标记最大blob的中心点位置  
        pcx = max_blob.cx()   # 获取最大blob的中心点x坐标并赋值给变量pcx  
        output_str=json.dumps(max_blob.cx())   # 将最大blob的中心点x坐标转换为JSON字符串并赋值给变量output_str  
        uart.write(output_str + '\r\n')   # 通过串口发送JSON字符串到其他设备并添加CR和LF作为结束标志('\r\n')  
        print(pcx)   # 在控制台打印最大blob的中心点x坐标以供调试和监控使用  
    else:   # 如果没找到任何blobs  
        print('not found!')   # 在控制台打印'not found!'以标识没有找到blobs的情况,这通常用于调试和监控使用  
    # 延时200毫秒(100毫秒的CPU时间),这通常用于控制图像处理的频率和避免过高的CPU使用率,也可以避免过快的串口通信速率导致其他设备无法处理数据的情况发生。这个延时时间可以根据实际需要进行调整。  
    pyb.delay(100)   # 延时200毫秒

2.小车控制

小车由电机驱动模块控制电机,电机控制车轮转动,一般商家会给驱动模块的使用手册,按单片机类型可分51 stm32 ardunio等,控制小车就使用开发板连接驱动模块,向驱动模块发送控制信号,由驱动模块控制小车。

以TB6612电机驱动和ardunio为例,详见代码:


///TB6612引脚接线///
//直流电机----------TB6612丝印标识----------ArduinoUNO主板引脚
//                     PWMA-----------------3
//                     AIN2-----------------4
//                     AIN1-----------------5
//                     STBY-----------------7
//                     BIN1-----------------8
//                     BIN2-----------------9
//                     PWMB-----------------10
//                     GND------------------GND
//                     ADC------------------A0 (只有带TB6612带稳压模块版才有ADC测量电池电压功能)
//                     VM-------------------12V电池
//                     VCC------------------5V  (使用带有稳压模块版时,接线变动如下:  5V---------5V  板子可向arduino供电)
//                     GND------------------GND
//电机A正极-------------AO1
//电机A负极-------------A02
//电机B负极-------------BO2
//电机B正极-------------BO1
//                     GND-----------------GND
//直流电机----------TB6612丝印标识----------ArduinoUNO主板引脚

#include <Servo.h>
#include <SoftwareSerial.h>

//定义引脚名称
#define PWMA 3  //3为模拟引脚,用于PWM控制
#define AIN1 5
#define AIN2 4
#define PWMB 10  //10为模拟引脚,用于PWM控制
#define BIN1 8
#define BIN2 9
#define STBY 7  //2、4、8、12、7为数字引脚,用于开关量控制
#define Voltage A0 //使用模拟引脚
#define ServoPin A1

int PwmA, PwmB;
double V;

SoftwareSerial mySerial(13, 12); // RX, TX  通过软串口连接esp8266,
Servo myservo;                          // 创建Servo对象控制伺服电机

void setup() {
  //TB6612电机驱动模块控制信号初始化
  pinMode(AIN1, OUTPUT);//控制电机A的方向,(AIN1, AIN2)=(1, 0)为正转,(AIN1, AIN2)=(0, 1)为反转
  pinMode(AIN2, OUTPUT);
  pinMode(BIN1, OUTPUT);//控制电机B的方向,(BIN1, BIN2)=(0, 1)为正转,(BIN1, BIN2)=(1, 0)为反转(不准)
  pinMode(BIN2, OUTPUT);
  pinMode(PWMA, OUTPUT);//A电机PWM
  pinMode(PWMB, OUTPUT);//B电机PWM
  pinMode(STBY, OUTPUT);//TB6612FNG使能, 置0则所有电机停止, 置1才允许控制电机
  myservo.attach(ServoPin);        //舵机绑定引脚
  myservo.write(90);             //初始化成正向
  // 使用自定义的舵机控制
  pinMode(ServoPin, OUTPUT);
  digitalWrite(ServoPin, LOW);//先保证拉低

  //初始化TB6612电机驱动模块
  digitalWrite(AIN1, 1);
  digitalWrite(AIN2, 0);
  digitalWrite(BIN1, 1);
  digitalWrite(BIN2, 0);
  digitalWrite(STBY, 1);
  analogWrite(PWMA, 0);
  analogWrite(PWMB, 0);

  //初始化串口,用于输出电池电压
  Serial.begin(9600);
  mySerial.begin(9600);
  pinMode(Voltage, INPUT); //初始化作为输入端


  // 随机数种子初始化
  //  randomSeed(analogRead(0));
}

int x = 0;
int z = 0;
int n = 0;
int last = 0;
void loop()
{

  SetPWM(1, 150);//电机AB同时满速正转
  SetPWM(2, 150);

  String rxdata = "";
  while (mySerial.available() > 0)
  {
    char inchar = mySerial.read();
    rxdata += inchar;        //逐个字符接收串口缓冲区内的数据
    //    Serial.println(rxdata);
    delay(10);                     //等待数据完全进入串口缓冲区

    if (rxdata.indexOf("\r\n") >= 0 && rxdata.length() < 6)
    {
      x = rxdata.toInt();
      Serial.println(x);
      if (x >= 0 && x <= 180) {
        x =  map(x, 0, 160, 0, 180);
        n++;
        z += x;
        
        int angle = (180 - x);
        if (angle > 180) {
          angle = 180;
        }
        if (angle < 0) {
          angle = 0;
        }
        myservo.write(angle);

      }

      rxdata = ""; // 清空数据缓冲区,准备接收下一个指令
    }
  }


  //  Serial.println(x);

}

void stop1() {
  SetPWM(1, 0);
  SetPWM(2, 0);
}


//自定义的舵机控制,需要传入一个角度值
void ServoControl(int servoAngle)
{
  double thisAngle = map(servoAngle, 0, 180, 500, 2500);//等比例角度值范围转换高电平持续时间范围
  unsigned char i = 50;//50Hz 每秒的周期次数(周期/秒) 即1S 50 个周期 每个周期20ms
  while (i--)
  {
    digitalWrite(ServoPin, HIGH);
    delayMicroseconds(thisAngle); //高电平时间
    digitalWrite(ServoPin, LOW);
    delayMicroseconds(20000 - thisAngle);//每个周期20ms减去高电平持续时间
  }
}

/**************************************************************************
  函数功能:设置指定电机转速
  入口参数:指定电机motor,motor=1(2)代表电机A(B); 指定转速pwm,大小范围为0~255,代表停转和满速
  返回  值:无
**************************************************************************/
void SetPWM(int motor, int pwm)
{
  if (motor == 1 && pwm >= 0) //motor=1代表控制电机A,pwm>=0则(AIN1, AIN2)=(1, 0)为正转
  {
    digitalWrite(AIN1, 1);
    digitalWrite(AIN2, 0);
    analogWrite(PWMA, pwm);
  }
  else if (motor == 1 && pwm < 0) //motor=1代表控制电机A,pwm<0则(AIN1, AIN2)=(0, 1)为反转
  {
    digitalWrite(AIN1, 0);
    digitalWrite(AIN2, 1);
    analogWrite(PWMA, -pwm);
  }
  else if (motor == 2 && pwm >= 0) //motor=2代表控制电机B,pwm>=0则(BIN1, BIN2)=(0, 1)为正转
  {
    digitalWrite(BIN1, 1);
    digitalWrite(BIN2, 0);
    analogWrite(PWMB, pwm);
  }
  else if (motor == 2 && pwm < 0) //motor=2代表控制电机B,pwm<0则(BIN1, BIN2)=(1, 0)为反转
  {
    digitalWrite(BIN1, 0);
    digitalWrite(BIN2, 1);
    analogWrite(PWMB, -pwm);
  }
}

3.资料下载链接

百度网盘:

链接:https://pan.baidu.com/s/1I8auha0w7b98FEY0c74j1A?pwd=data 
提取码:data

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
引用\[1\]:循迹小车由三轮或四轮小车和摄像头两大部分组成,通过镜头识别路径,将其得到的图像做处理并发送给小车小车对应做出动作。\[1\]在制作openmv寻迹小车时,需要掌握一些相关知识,包括STM32相关知识、openMV相关知识、USART通信、SPI通信、直流电机驱动等等。\[1\]你可以通过学习相关的视频和网站来获取这些知识。引用\[2\]:在制作寻迹小车时,你可以参考一些教程,比如《STM32各类小车工作原理及学习》。\[2\]在制作过程中可能会遇到一些问题,下面是一些常见问题及解决方法:引用\[3\]:1、如果小车只能简单寻迹,但不能完全寻迹,你可以将摄像头从小车上拿下来,固定在一个摄像头倾斜角和高度相同的简易支架上,连接到电脑上观看小车视野,检查是否在过弯到一半时找不到视野。根据需要调整程序。2、如果小车向左转很顺利,但向右转会出轨,或者左转到一半会乱跑,首先要确保摄像头的位置正确,接线是否松动影响数据传输,然后检查偏移量的数据。通过查看openMV处理出来的偏移量数据,发现右转偏移量不足,导致过弯一半出轨。适当增加右转偏移量即可解决。3、如果数据传输出现错乱,但硬件没有问题,可以尝试将数据传输相关的模块单独接电源或与其他线路隔离,以减少可能的干扰。4、在测试时务必在光线好的地方进行,因为光线弱会影响路径识别,导致乱跑或跑到旁边的路径上。确保光线充足可以避免误以为是程序问题而进行不必要的调试。 #### 引用[.reference_title] - *1* *2* *3* [openMV镜头下的STM32小车寻迹原理及其调试注意事项(附openMV代码)](https://blog.csdn.net/weixin_43679759/article/details/88205708)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值