1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
| ''' 功能描述 完整功能包括: * 直线巡线 * 直角转弯判定 (左转or右转) * T字形路口判定 * 十字形路口判定 其中T字形跟十字形可以用作四轴悬停的参考点。 原理介绍 算法的主要核心在于,讲整个画面分割出来5个ROI区域 * 上方横向采样 * 中间横向采样 * 下方横向采样 * 左侧垂直采样 * 右侧垂直采样 通过判断5个图片的组合关系给出路口类型的判断 ''' import sensor import image import time import math import pyb from pyb import Pin, Timer, UART,LED from GeometryFeature import GeometryFeature
LED(4).on() is_debug = True
DISTORTION_FACTOR = 1.5 IMG_WIDTH = 64 IMG_HEIGHT = 64 def init_sensor(): ''' 初始化感光芯片 ''' sensor.reset() sensor.set_pixformat(sensor.GRAYSCALE) sensor.set_framesize(sensor.B64X64) sensor.skip_frames(time=2000) sensor.set_auto_gain(False) sensor.set_auto_whitebal(False)
init_sensor()
def ternleft(): uart.write('G') time.sleep_ms(650) uart.write('L') time.sleep_ms(600)
def ternright(): uart.write('G') time.sleep_ms(650) uart.write('R') time.sleep_ms(590)
uart = pyb.UART(3,115200,timeout_char = 1000)
def get_symbol(num): ''' 根据数值正负,返回数值对应的符号 正数:‘+’, 负数‘-’ 主要为了方便C语言解析待符号的数值。 ''' if num >=0: return '+' else: return '-'
def data_format_wrapper(yaw_angle, sum_x, sum_y, cx_mean, cx, cy, is_left_angle, is_t, last_y): ''' 根据通信协议封装数据 TODO 重新编写通信协议 与配套C解析代码
yaw_angle,sum_x, sum_y 没有用到 cx_mean: roi 1 2 3 对应的bolb中心的x坐标加权平均, 如果没有就补32 都没有就赋值为原来的值 cx : roi 1 3 blob 中心坐标的加权平均, 如果一方丢失, 就赋值为另外一个 都没有就赋值为原来的值 cy : roi 4 5 blob 中心坐标的加权平均,如果一方丢失, 就赋值为另外一个, 都没有就赋值为原来的值 is_left_angle :代表是否有直角,!!!信息丢失 其实,可以用一个字符来表示,是左转还是右转 T(T字形) L(Left) R(Right) last_x, last_y 是两个直线的交叉点的坐标 改写为 intersect_x,intersect_y
args = [ get_symbol(yaw_angle), # 偏航角符号 abs(int(yaw_angle)), # 偏航角 get_symbol(sum_x), # 光流数据sux_x的符号 abs(int(sum_x)), # 光流数据sum_x get_symbol(sum_y), # 光流数据sum_y的符号 abs(int(sum_y)), # 光流数据 sum_y int(cx_mean), # x的中心,三个取样区域色块中心x坐标的平均值 int(cx), int(cy), int(is_left_angle), int(last_x), int(last_y) ] # 将数值列表按照通信协议,转换为待发送的字符 info = 's%c%.2d%c%.2d%c%.2d%.2d%.2d%.2d%.2d%.2d%.2d#'%tuple(args) global is_debug if is_debug: print('s%c%.2d%c%.2d%c%.2d | cx_mean=%.2d cx=%.2d cy=%.2d Turn Left: %.2d | %.2d%.2d#'%tuple(args)) '''
if cx_mean >= 22 and cx_mean <=40 : info='G' if cx_mean<22 : info='L' if cx_mean>40 : info='R' if is_t : info='S' ternleft()
return info
is_need_send_data = False def uart_time_trigger(timer): ''' 串口发送数据的定时器,定时器的回调函数 ''' global is_need_send_data is_need_send_data = True
tim = Timer(4, freq=20)
tim.callback(uart_time_trigger)
INTERSERCT_ANGLE_THRESHOLD = (45,90)
LINE_COLOR_THRESHOLD = [(20, 80)]
ROIS = { 'down': (0, 55, 64, 8), 'middle': (0, 28, 64, 8), 'up': (0, 0, 64, 8), 'left': (0, 0, 8, 64), 'right': (56, 0, 8, 64) }
def find_blobs_in_rois(img): ''' 在ROIS中寻找色块,获取ROI中色块的中心区域与是否有色块的信息 ''' global ROIS global is_debug
roi_blobs_result = {} for roi_direct in ROIS.keys(): roi_blobs_result[roi_direct] = { 'cx': -1, 'cy': -1, 'blob_flag': False } for roi_direct, roi in ROIS.items(): blobs=img.find_blobs(LINE_COLOR_THRESHOLD, roi=roi, merge=True, pixels_area=10) if len(blobs) == 0: continue
largest_blob = max(blobs, key=lambda b: b.pixels()) x,y,width,height = largest_blob[:4]
if not(width >=5 and width <= 15 and height >= 5 and height <= 15): continue
roi_blobs_result[roi_direct]['cx'] = largest_blob.cx() roi_blobs_result[roi_direct]['cy'] = largest_blob.cy() roi_blobs_result[roi_direct]['blob_flag'] = True
if is_debug: img.draw_rectangle((x,y,width, height), color=(255))
return roi_blobs_result
def visualize_result(canvas, cx_mean, cx, cy, is_turn_left, is_turn_right, is_t, is_cross): ''' 可视化结果 ''' if not(is_turn_left or is_turn_right or is_t or is_cross): mid_x = int(canvas.width()/2) mid_y = int(canvas.height()/2) canvas.draw_circle(int(cx_mean), mid_y, 5, color=(255)) canvas.draw_circle(mid_x, mid_y, 8, color=(0)) canvas.draw_line((mid_x, mid_y, int(cx_mean), mid_y), color=(255))
turn_type = 'N'
if is_t or is_cross: canvas.draw_cross(int(cx), int(cy), size=10, color=(255)) canvas.draw_circle(int(cx), int(cy), 5, color=(255))
if is_t: turn_type = 'T' elif is_cross: turn_type = 'C' elif is_turn_left: turn_type = 'L' elif is_turn_right: turn_type = 'R'
canvas.draw_string(0, 0, turn_type, color=(0))
last_cx = 0 last_cy = 0
while True: if not is_need_send_data: continue is_need_send_data = False
img = sensor.snapshot() img.lens_corr(DISTORTION_FACTOR)
lines = img.find_lines(threshold=1000, theta_margin = 50, rho_margin = 50) intersect_pt = GeometryFeature.find_interserct_lines(lines, angle_threshold=(45,90), window_size=(IMG_WIDTH, IMG_HEIGHT)) if intersect_pt is None: intersect_x = 0 intersect_y = 0 else: intersect_x, intersect_y = intersect_pt
reslut = find_blobs_in_rois(img)
is_turn_left = False is_turn_right = False
if (not reslut['up']['blob_flag'] ) and reslut['down']['blob_flag']: if reslut['left']['blob_flag']: is_turn_left = True if reslut['right']['blob_flag']: is_turn_right = True
is_t = False is_cross = False
cnt = 0 for roi_direct in ['up', 'down', 'left', 'right']: if reslut[roi_direct]['blob_flag']: cnt += 1 is_t = cnt == 3 is_cross = cnt == 4
cx_mean = 0 for roi_direct in ['up', 'down', 'middle']: if reslut[roi_direct]['blob_flag']: cx_mean += reslut[roi_direct]['cx'] else: cx_mean += IMG_WIDTH / 2 cx_mean /= 3
cx = 0 cy = 0
if is_cross or is_t: cnt = 0 for roi_direct in ['up', 'down']: if reslut[roi_direct]['blob_flag']: cnt += 1 cx += reslut[roi_direct]['cx'] if cnt == 0: cx = last_cx else: cx /= cnt
cnt = 0 for roi_direct in ['left', 'right']: if reslut[roi_direct]['blob_flag']: cnt += 1 cy += reslut[roi_direct]['cy'] if cnt == 0: cy = last_cy else: cy /= cnt
info = data_format_wrapper(0, 0, 0, cx_mean, cx, cy, is_turn_left, is_t, 0) uart.write(info) print(info)
last_cx = cx last_cy = cy
if is_debug: visualize_result(img, cx_mean, cx, cy, is_turn_left, is_turn_right, is_t, is_cross)
|