#__________________________________________________________________
# 导入模块
import sensor, time, image # 导入感光元件模块 sensor 跟踪运行时间模块 time 机器视觉模块 image
import utime # 导入延时模块 utime
from fpioa_manager import fm # 从 fpioa_manager 模块中导入 引脚注册模块 fm
from Maix import GPIO # 从 Maix 模块中导入 模块 GPIO
import lcd # 导入 LCD 模块
from machine import Timer, PWM, UART # 从 machine 模块中导入 定时器模块 Timer 脉宽调制模块 PWM 双向串行通信模块 UART
import math # 导入数学函数模块 math
#__________________________________________________________________
# 感光元件设置
sensor.reset() # 重置并初始化感光元件 默认设置为 摄像头频率 24M 不开启双缓冲模式
#sensor.reset(freq=24000000, dual_buff=True) # 设置摄像头频率 24M 开启双缓冲模式 会提高帧率 但内存占用增加
sensor.set_pixformat(sensor.RGB565) # 设置图像格式为 RGB565 (彩色) 除此之外 还可设置格式为 GRAYSCALE 或者 YUV422
sensor.set_framesize(sensor.QVGA) # 设置图像大小为 QVGA (320 x 240) 像素个数 76800 K210最大支持格式为 VGA
sensor.set_auto_exposure(0) # 关闭自动曝光
#sensor.set_auto_exposure(0, exposure=120000) # 设置手动曝光 曝光时间 120000 us
sensor.set_auto_gain(0) # 关闭画面增益
sensor.set_auto_whitebal(0) # 关闭RGB自动增益(白平衡)
#sensor.set_auto_gain(0, gain_db = 12) # 设置画面增益 17 dB 影响实时画面亮度
#sensor.set_auto_whitebal(0, rgb_gain_db = (0,0,0)) # 设置RGB增益 0 0 0 dB 影响画面色彩呈现效果 在 K210 上无法调节增益 初步判定是感光元件 ov2640 无法支持
#sensor.set_contrast(0) # 设置对比度 0 这个参数无法读取 且调这个参数对画面似乎不会产生影响 暂时注释
#sensor.set_brightness(0) # 设置亮度 0 这个参数无法读取 且调这个参数对画面似乎不会产生影响 暂时注释
#sensor.set_saturation(0) # 设置饱和度 0 这个参数无法读取 且调这个参数对画面似乎不会产生影响 暂时注释
#sensor.set_vflip(1) # 打开垂直翻转 如果是 01Studio 的 K210 不开启会导致画面方向与运动方向相反
sensor.set_hmirror(1) # 打开水平镜像 如果是 01Studio 的 K210 不开启会导致画面方向与运动方向相反
sensor.skip_frames(time = 8000) # 延时跳过8s 等待感光元件稳定
#__________________________________________________________________
# 创建时钟对象
clock = time.clock() # 创建时钟对象 clock
#__________________________________________________________________
# 定时器的使用
# 定义定时器属性类
class Timer_Property():
cnt = 0 # 定时器计数值
cnt_max = 0 # 定时器计数值上限
period = 0 # 定时器周期
freq = 0 # 定时器频率
# 定时器0 配置_______________________________________________________
# 定时器0 实例化类
timer0 = Timer_Property() # 实例化定时器属性类 Timer_Property() 为 timer0
timer0.cnt_max = 9 # 设定 定时器0 的计数值上限为 9
timer0.period = 100 # 设定 定时器0 的周期为 100
# 定时器0 定义回调函数
def Timer0_Back(tim0):
if timer0.cnt < timer0.cnt_max: # 若 定时器0 的计数值小于 定时器0 的计数值上限
timer0.cnt = timer0.cnt + 1 # 计数值自增
else:
timer0.cnt = 0 # 超出计数值上限 则计数值重置为0
# 定时器0 初始化
tim0 = Timer(Timer.TIMER0, # 定时器编号 定时器0
Timer.CHANNEL0, # 定时器通道 通道0
mode = Timer.MODE_PERIODIC, # 定时器模式 周期性
unit = Timer.UNIT_MS, # 定时器周期单位 ms
period = timer0.period, # 定时器周期 timer0.period 若 unit 为 Timer.UNIT_MS 则周期为 timer0.period ms
callback = Timer0_Back) # 定时器触发中断后执行的回调函数 Timer0_Back
#__________________________________________________________________
# 串口的使用
# 串口1 设置 P9 RX P6 TX
#fm.register(9, fm.fpioa.UART1_RX, force = True) # 配置 9 脚为 UART1_RX 强制注册
#fm.register(6, fm.fpioa.UART1_TX, force = True) # 配置 6 脚为 UART1_TX 强制注册
uart1 = UART(UART.UART1, 115200, 8, 0, 1) # 设置 uart1 为 串口1 波特率 921600 数据位 8位 校验位 0位 停止位 1位
# 串口2 设置 P7 RX P8 TX
fm.register(9, fm.fpioa.UART2_RX, force = True) # 配置 7 脚为 UART2_RX 强制注册
fm.register(6, fm.fpioa.UART2_TX, force = True) # 配置 8 脚为 UART2_TX 强制注册
uart2 = UART(UART.UART2, 921600, 8, 0, 1) # 设置 uart2 为 串口2 波特率 921600 数据位 8位 校验位 0位 停止位 1位
#__________________________________________________________________
# 串口发送
# 定义 UART 发送类
class UART_Transmit(): # 定义 UART 发送类
pack_flag = 0 # 打包方法标志位
head1 = 0x00 # uint8_t 帧头1
head2 = 0x00 # uint8_t 帧头2
x = 0 # uint16_t 目标x轴坐标
y = 0 # uint16_t 目标y轴坐标
color = 0 # uint8_t 目标颜色标志位
shape = 0 # uint8_t 目标形状标志位
flag = 0 # uint8_t 目标标志位
mode = 0 # uint8_t 模式标志位
# 实例化类
fasong = UART_Transmit() # 实例化 UART_Transmit() 为 fasong
fasong.pack_flag = 1 # 打包方法为 方法1
fasong.head1 = 0xAA # fasong 的帧头1为 0xAA
fasong.head2 = 0xAA # fasong 的帧头2为 0xAA
jieshou = UART_Transmit() # 实例化 UART_Transmit() 为 jieshou
jieshou.pack_flag = 2 # 打包方法为 方法2
jieshou.head1 = 0xAA # jieshou 的帧头1为 0xAA
jieshou.head2 = 0xAA # jieshou 的帧头2为 0xAA
# 定义打包函数
def Pack_Data(TData):
data = UART_Pack_Method(TData) # 根据不同的方法打包发送数据
# 数据包的长度
data_len = len(data) # 获得数据包总长度
data[2] = data_len - 4 # 有效数据的长度 扣去 帧头1 帧头2 有效数据长度位 校验位
# 校验和
sum = 0 # 和置零
for i in range(0,data_len-1):
sum = sum + data[i] # 和累加
data[data_len-1] = sum # 和赋值 给数组最后一位发送 只保存低8位 溢出部分无效
# 返回打包好的数据
return data
#__________________________________________________________________
# 串口接收
# 定义 UART 接收类
class UART_Receive(object): # 定义 UART 接收类
uart_buf = [] # 串口缓冲区数组
data_len = 0 # 有效数据长度
data_cnt = 0 # 总数据长度
state = 0 # 接收状态
buf_len = 0 # 保存串口等待字节的数量
head1 = 0x00 # 接收帧头1
head2 = 0x00 # 接收帧头2
lenmax = 0 # 有效数据最大长度
save_flag = 0 # 保存方法标志位
# 实例化类
rfasong = UART_Receive() # 实例化 UART_Receive() 为 rfasong
rfasong.head1 = 0xAA # rfasong 的帧头1为 0xAA
rfasong.head2 = 0xAA # rfasong 的帧头2为 0xAA
rfasong.lenmax = 40 # rfasong 的有效数据最大长度为 40
rfasong.save_flag = 1 # rfasong 的保存方法标志位为 1
rjieshou = UART_Receive() # 实例化 UART_Receive() 为 rjieshou
rjieshou.head1 = 0xAA # rjieshou 的帧头1为 0xAA
rjieshou.head2 = 0xAA # rjieshou 的帧头2为 0xAA
rjieshou.lenmax = 40 # rjieshou 的有效数据最大长度为 40
rjieshou.save_flag = 2 # rjieshou 的保存方法标志位为 2
# 定义串口数据读取函数
def UART_Read(RData, uart):
RData.buf_len = uart.any() # 检查 串口 是否有内容需要读取 返回等待的字节数量(可能为0)
for i in range(0, RData.buf_len): # 读取 RData.buf_len 个数据
Receive_Data(RData, uart.readchar()) # 接收单个数据 uart.readchar() 然后将这个数据传递到函数 Receive_Data() 进行 数据接收
# 定义串口数据接收函数
def Receive_Data(RData, buf):
if RData.state == 0 and buf == RData.head1: # 判断帧头1是否符合要求 符合则进入下一个状态
RData.state = 1 # 更改状态为 1
RData.uart_buf.append(buf) # 将这个数据添加到数组末尾
elif RData.state == 1 and buf == RData.head2: # 判断帧头2是否符合要求 符合则进入下一个状态
RData.state = 2 # 更改状态为 2
RData.uart_buf.append(buf) # 将这个数据添加到数组末尾
elif RData.state == 2 and buf < RData.lenmax: # 有效数据长度位 规定有效数据长度小于40 符合则进入下一个状态
RData.state = 3 # 更改状态为 3
RData.data_len = buf # 获得有效数据长度
RData.data_cnt = buf + 4 # 获得总数据长度 总数据长度 = 帧头1 + 帧头2 + 有效数据长度位 + 有效数据 + 校验位
RData.uart_buf.append(buf) # 将这个数据添加到数组末尾
elif RData.state == 3 and RData.data_len > 0: # 存储有效数据长度个数据
RData.data_len = RData.data_len - 1 # 每存储一次 还需要存储的数据个数减1
RData.uart_buf.append(buf) # 将这个数据添加到数组末尾
if RData.data_len == 0: # 直到存储完毕
RData.state = 4 # 进入下一个状态
elif RData.state == 4: # 当接收到存储完毕的信息
RData.uart_buf.append(buf) # 保存最后一位校验位 将这个数据添加到数组末尾
RData.state = 0 # 状态重置为0 调用串口数据解析函数进行数据解析
Parse_Data(RData) # 解析数据
#print(RData.uart_buf) # 打印接收数组 若接收结果不对 可取消注释查看数组
RData.uart_buf = [] # 清空缓冲区 准备下次接收数据
else: # 不满足以上条件 视为接收出错 重置状态为0 丢弃所有数据 准备下一次接收数据
RData.state = 0 # 重置状态为0
RData.uart_buf = [] # 清空缓冲区 准备下一次接收数据
# 定义串口数据解析函数
def Parse_Data(PData):
# 和累加
sum = 0 # 和置0
i = 0 # 已循环次数置0
while i < (PData.data_cnt - 1): # 循环累加
sum = sum + PData.uart_buf[i] # 累加求数组和
i = i + 1 # 已循环次数自增
# 求余 因为 校验和 为 8 位 超出部分无效 因此只校验 低8位 即可
sum = sum % 256 # 和对256取余 得低八位
# 和校验失败则退出
if sum != PData.uart_buf[PData.data_cnt - 1]: # 和取余结果若不等于校验位的值
return # 退出
# 和校验成功则根据保存方法的不同 接收数据
UART_Save_Method(PData)
#__________________________________________________________________
# 调试区
# 定义 K210 属性类
class K210_Property(object): # 定义 K210 接收类
x = 0 # uint16_t 目标x轴坐标
y = 0 # uint16_t 目标y轴坐标
color = 0 # uint8_t 目标颜色标志位
shape = 0 # uint8_t 目标形状标志位
flag = 0 # uint8_t 目标标志位
mode = 0 # uint8_t 工作模式位
# 实例化类
K210 = K210_Property() # 实例化 K210_Property() 为 K210
# 串口发送测试信息赋值
#测试用信息
#fasong.mode = 1
#jieshou.mode = 1
#jieshou.x = 36
#jieshou.y = 26
#jieshou.color = 24
#jieshou.shape = 24
#jieshou.flag = 2
# 打印信息函数
# 打印 sensor 各参数
def Print_sensor():
print("Exposure :", sensor.get_exposure_us(), "Gain:", sensor.get_gain_db(), "RGB:", sensor.get_rgb_gain_db())
# 打印 K210 各参数
def Print_K210():
print("Mode:", K210.mode, "x:", K210.x, "y:", K210.y, "color:", K210.color, "shape:", K210.shape, "flag:", K210.flag)
# 打印 色块 各参数
def Print_Blobs_Property(color,name):
print(name,"cx:",color.cx,"cy:",color.cy,"flag:",color.flag,"color:",color.color,"density:",color.density,"led_flag:",color.led_flag)
# 打印总函数
def Print_All():
print("______________________________________________________________________")
Print_sensor() # 打印 sensor 参数
#Print_Blobs_Property(black,"Black ") # 打印 黑色色块 参数
#Print_Blobs_Property(red, "Red ") # 打印 红色色块 参数
Print_K210() # 打印 K210 参数
# LCD
# LCD 初始化
lcd.init() # lcd初始化
# 串口数据打包方法函数
def UART_Pack_Method(TData):
if TData.pack_flag == 1:
data = bytearray([TData.head1, # 帧头1
TData.head2, # 帧头2
0x00, # 有效数据长度 0x00 + data_len - 4
TData.mode, # 保存目标x轴坐标 高八位
0x00]) # 数据和校验位
elif TData.pack_flag == 2:
data = bytearray([TData.head1, # 帧头1
TData.head2, # 帧头2
0x00, # 有效数据长度 0x00 + data_len - 4
TData.x>>8, # 保存目标x轴坐标 高八位
TData.x, # 保存目标x轴坐标 低八位
TData.y>>8, # 保存目标y轴坐标 高八位
TData.y, # 保存目标y轴坐标 低八位
TData.color, # 保存目标颜色标志位
TData.shape, # 保存目标形状标志位
TData.flag, # 保存目标标志位
0x00]) # 数据和校验位
return data
# 串口数据保存方法函数
def UART_Save_Method(PData):
if PData.save_flag == 1 and PData.uart_buf[2] > 0:
K210.mode = PData.uart_buf[3]
elif PData.save_flag == 2 and PData.uart_buf[2] > 6:
K210.x = PData.uart_buf[3]*256 + PData.uart_buf[4]
K210.y = PData.uart_buf[5]*256 + PData.uart_buf[6]
K210.color = PData.uart_buf[7]
K210.shape = PData.uart_buf[8]
K210.flag = PData.uart_buf[9]
#颜色识别
#__________________________________________________________________
color_thresholds = [
(45, 57, -10, -3, 10, 19),#安全区
(24, 31, 29, 36, 17, 29),# red
(28, 57, -21, -5, 19, 48), # yellow
(24, 35, -11, 4, -28, -14),# Blue
]
color_strings = ['1', '2', '3'] #1:red 2:yellow 3:bule
color_zhongxin = dict.fromkeys(color_strings)
color_anquanqu = []
#测距模块
#______________________________________________________________
____# 摄像头参数(根据实际安装调整)
CAMERA_HEIGHT = 110 # 摄像头离地高度(mm)
CAMERA_ANGLE = 30 # 摄像头倾角(度)
FOCAL_LENGTH = 540 # 重新标定的焦距(像素)
# 图像中心点
CENTER_X = 160
CENTER_Y = 120
COLOR_THRESHOLDS= color_thresholds
def calculate_distance(y_pos):
"""
根据物体在图像中的y位置计算距离(考虑摄像头倾角)
:param y_pos: 物体底部在图像中的y坐标
:return: 距离(毫米)
"""
# 计算垂直偏移(像素)
offset_y = CENTER_Y - y_pos # 注意符号反转
# 计算角度偏移(弧度)
angle_offset = math.atan(offset_y / FOCAL_LENGTH)
# 计算总俯角(弧度)
total_angle = math.radians(CAMERA_ANGLE) + angle_offset
# 计算实际距离
distance = CAMERA_HEIGHT / math.sin(total_angle)
horizontal_distance = distance * math.cos(total_angle)
return horizontal_distance
def find_target(blob):
max_size = 0
target = None
for b in blob:
if b.pixels() > max_size:
max_size = b.pixels()
target = b
return target
def draw_info(img, target, distance):
img.draw_rectangle(target.rect(), color=(255, 0, 0))
img.draw_cross(target.cx(), target.cy(), color=(0, 255, 0))
dist_text = "Dist: {:.0f}mm".format(distance)
img.draw_string(10, 10, dist_text, color=(255, 0, 0), scale=1.5)
img.draw_line(0, CENTER_Y, 320, CENTER_Y, color=(0, 0, 255))
img.draw_string(10, CENTER_Y - 20, "Horizon", color=(0, 0, 255))
img.draw_line(0, target.y() + target.h(), 320, target.y() + target.h(), color=(255, 0, 0))
# 主函数
#______________________________________________________________
while(True):
clock.tick()
img = sensor.snapshot()
color_anquanqu = [] # 每次循环都清空安全区列表
color_zhongxin = {'1': None, '2': None, '3': None} # 初始化字典
for color_idx, threshold in enumerate(color_thresholds):
blobs = img.find_blobs([threshold], pixels_threshold=100, area_threshold=100, merge=True, margin=10)
if blobs:
for blob in blobs:
color_new = (255, 255, 255)
if color_idx == 0:
color_new = (120, 120, 120)
color_anquanqu.append(blob.x())
color_anquanqu.append(blob.y())
color_anquanqu.append(blob.x() + blob.w())
color_anquanqu.append(blob.y() + blob.h())
# 安全区检查
in_safe_zone = False
if len(color_anquanqu) >= 4 and :
x_in_range = color_anquanqu[0] < blob.cx() < color_anquanqu[2]
y_in_range = color_anquanqu[1] < blob.cy() < color_anquanqu[3]
in_safe_zone = x_in_range and y_in_range
if color_idx == 1 and not in_safe_zone:
target = find_target(blob)
color_new = (255, 0, 0)
bottom_y = target.y() + target.h()
distance = calculate_distance(bottom_y)
color_zhongxin['1'] = [blob.cx(), blob.cy(), distance]
elif color_idx == 2 and not in_safe_zone:
target = find_target(blob)
color_new = (0, 255, 0)
bottom_y = target.y() + target.h()
distance = calculate_distance(bottom_y)
color_zhongxin['2'] = [blob.cx(), blob.cy(), distance]
elif color_idx == 3 and not in_safe_zone:
target = find_target(blob)
color_new = (0, 0, 255)
bottom_y = target.y() + target.h()
distance = calculate_distance(bottom_y)
color_zhongxin['3'] = [blob.cx(), blob.cy(),distance]
img.draw_rectangle(blob.rect(), color=color_new, thickness=3)
img.draw_cross(blob.cx(), blob.cy(), color=color_new)
img.draw_string(blob.cx() + 10, blob.cy() - 10, color_strings[color_idx], color=color_new)
lcd.display(img)
# 发送检测到的色块数据
for s in range(1, 4):
key = str(s)
if color_zhongxin[key] is not None:
jieshou.x = color_zhongxin[key][0]
jieshou.y = color_zhongxin[key][1]
jieshou.color = s
jieshou.shape = 1
jieshou.flag = color_zhongxin[key][2]
print(color_zhongxin[key])
#uart2.write(Pack_Data(jieshou))
color_zhongxin[key] = None
time.sleep(1)
Traceback (most recent call last):
File "<stdin>", line 390
SyntaxError: invalid syntax
MicroPython v0.6.2-89-gd8901fd22 on 2024-06-17; Sipeed_M1 with kendryte-k210
Type "help()" for more information.以上程序程序发生了如上报错,请分析原因,给出解决方案,并以提高识别精度为目的生成一份优化后的新python程序
最新发布