#例程序使用OpenMV4,OpenMV4Plus均可
import sensor, image, time
from pyb import millis, Pin, Timer, LED
sensor.reset()
sensor.set_hmirror(False)
sensor.set_vflip(False)
sensor.set_transpose(False)
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.VGA)
sensor.set_windowing([200,120,240,240])
sensor.set_vflip(True) #垂直翻转
sensor.set_hmirror(True) #水平翻转
clock = time.clock()
#设置频率,初始化定时器4,将其设置为50HZ,也就是说一个PWM周期为20ms
TIM4 = Timer(4, freq=50)
## 生成50HZ方波,使用TIM4,channels 1,2分别是1.5ms脉宽,对应舵机90度
ch1 = TIM4.channel(1, Timer.PWM, pin=Pin("P7"), pulse_width=0) #旋转舵机
ch2 = TIM4.channel(2, Timer.PWM, pin=Pin("P8"), pulse_width=0) #俯仰舵机
P9_Out = Pin('P9', Pin.OUT_PP)
P9_Out.low() # 设置P9为低电平,关闭激光
red_led = LED(1)
green_led = LED(2)
blue_led = LED(3)
#控制舵机驱动函数,输入舵机角度
def servo_ctrl(angle_x, angle_y):
#1000对应0.5ms,舵机0°
ch1.pulse_width(int(1000+4000*angle_x/180))
ch2.pulse_width(int(1000+4000*angle_y/180))
#根据输入激光点与中心点的x,y距离,计算出云台调节的增量,输出要增加的角度
def trace_add(distance):
#正值
if distance == 1000.0:
return 0.7; #特定的量,云台扫描使用这个角度增量
elif distance > 50.0:
return 0.6;
elif distance > 40.0:
return 0.3;
elif distance > 30.0:
return 0.2;
elif distance > 20.0:
return 0.1;
elif distance > 10.0:
return 0.05;
elif distance > 5.0:
return 0.03;
elif distance > 2.0:
return 0.02;
#负值
elif distance == -1000.0:
return -0.7; #特定的量,云台扫描使用这个角度增量
elif distance < -50.0:
return -0.6;
elif distance < -40.0:
return -0.3;
elif distance < -30.0:
return -0.2;
elif distance < -20.0:
return -0.1;
elif distance < -10.0:
return -0.05;
elif distance < -5.0:
return -0.03;
elif distance < -2.0:
return -0.02;
return 0.0;
#颜色阈值,可以宽泛一些。如果效果不好,则自行调阈值
thr_write = (60, 100, -71, 65, -81, 71)#白色阈值
thr_black = (56, 0, -74, 35, -62, 37)#黑色阈值
thr_purple = (85, 100, -12, 127, -128, 19)#紫色阈值(紫外线激光点)
target = [0,0] #目标坐标,自动计算
purple_point = [0,0] #紫色激光点坐标,自动计算
vision_point = [114,125]#视野中心点,在激光未开启时用于追踪,自行调整
distance = [0,0] #激光点与中心的距离
add_angle = [0,0] #舵机增量角度
now_servo = [90,100] #当前舵机角度
flag = [0,0] #检测成功标志,前者为激光,后者为中心点,检测成功为1,否则为0
count = 0; #计数,无目标时云台要旋转寻找目标
direction = [0,0]; #旋转方向,在寻找目标时来回旋转的方向确定
blue_led.on()
time.sleep_ms(100)
blue_led.off()
while(True):
timer = millis()
clock.tick()
img = sensor.snapshot()
black_blobs = img.find_blobs([thr_black], merge =False) #找黑框
if black_blobs: #如果有目标
#找紫色激光点
purple_blobs = img.find_blobs([thr_purple], merge=True)
if purple_blobs:
for blob in purple_blobs:
purple_point = [blob[5], blob[6]] #激光中心点
flag[0] = 1 #激光点检测成功标志置1
break
else:
flag[0] = 0 #激光点检测成功标志置0
#寻找中心点
for single_black_blob in black_blobs:
#找到的目标中,符合阈值的面积和总的区域之间的比值。因为黑框内部不是黑色,所以这个比值不会很大。
if single_black_blob.pixels() / (single_black_blob.w()*single_black_blob.h()) < 0.3:
#img.draw_rectangle(single_black_blob.rect(),color=(0,255,255))#绘制符合条件的区域
#在区域内找白色
write_blobs = img.find_blobs([thr_write],area_threshold=2,roi =single_black_blob.rect(), merge =False)
if write_blobs:#如果有目标
largest_white = max(write_blobs, key=lambda b: b.area())#找到最大的块
#绘制黑框的中心点
#判断条件1:黑色区域面积和白色区域面积的比例;判断条件2:黑框和白色区域中心坐标的差值
if (2 < largest_white.pixels() / single_black_blob.pixels() < 4) and\
abs( largest_white.cx() - single_black_blob.cx() ) < 10 and \
abs( largest_white.cy() - single_black_blob.cy() ) < 10 :
target = [largest_white.cx(), largest_white.cy()] #白色区域中心坐标
img.draw_cross(target,color=(255,0,0),thickness=3) #绘制在画布上
flag[1] = 1 #中心点检测成功标志置1
green_led.on()
break
else:
green_led.off()
flag[1] = 0 #中心点检测成功标志置0
else:
green_led.off()
flag[1] = 0 #中心点检测成功标志置0
else:
flag[1] = 0 #中心点检测成功标志置0
else:
flag[1] = 0 #中心点检测成功标志置0
flag[0] = 0 #激光点检测成功标志置0
#计算误差距离
if flag[1] == 1:#有中心点,追踪视觉中心,小于一定的值打开激光
count = 0; #把计数清零,避免误识别后进入搜索模式
distance[0] = vision_point[0] - target[0]
distance[1] = vision_point[1] - target[1]
if abs(distance[0]) < 4 and abs(distance[1]) < 4:
P9_Out.high() #设置P9为高电平,打开激光
else:
P9_Out.low() # 设置P9为低电平,关闭激光
elif flag[1] == 0: #无中心点,旋转搜索黑框中心点
if count > 20:
P9_Out.low() # 设置P9为低电平,关闭激光
if direction[0] == 0: #正向自增,增X旋转
distance[0] = 1000
elif direction[0] == 1: #反向自增,增X旋转
distance[0] = -1000
if now_servo[0] >= 120: #到达角度,翻转方向
direction[0] = 1;
elif now_servo[0] <= 60:
direction[0] = 0;
distance[1] = 0 #pitch不自增,直接定角度,距离需要设为0
now_servo[1] = 100
# if direction[1] == 0: #正向自增,增Y俯仰
# distance[1] = 1000
# elif direction[1] == 1: #反向自增,增Y俯仰
# distance[1] = -1000
# if now_servo[1] >= 105: #到达角度,翻转方向
# direction[1] = 1;
# elif now_servo[1] <= 95:
# direction[1] = 0;
elif count < 50:
count = count+1
else:
distance[0] = 0
distance[1] = 0
#根据中心距离计算舵机增量
add_angle[0] = trace_add(distance[0])
add_angle[1] = trace_add(distance[1])
#将舵机角度增量加到当前舵机角度
now_servo[0] = now_servo[0] + add_angle[0]
now_servo[1] = now_servo[1] + add_angle[1]
#角度限幅
if now_servo[0] > 140:
now_servo[0] = 140
elif now_servo[0] < 40:
now_servo[0] = 40
if now_servo[1] > 110:
now_servo[1] = 110
elif now_servo[1] < 90:
now_servo[1] = 90
#舵机执行
servo_ctrl(now_servo[0],now_servo[1])
#servo_ctrl(90,90)
#如需提高帧率,注释掉print
# print('舵机X角度',now_servo[0],'舵机Y角度',now_servo[1],'激光标志',flag[0],'中心点标志',flag[1],'目标',target,'激光点',purple_point)
# timer = millis() - timer
# print('用时',timer,'实时帧速',1000/timer,'平均帧速',clock.fps())
这些都是什么意思
最新发布