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