• 免费好用的星瞳AI云服务上线!简单标注,云端训练,支持OpenMV H7和OpenMV H7 Plus。可以替代edge impulse。 https://forum.singtown.com/topic/9519
  • 我们只解决官方正版的OpenMV的问题(STM32),其他的分支有很多兼容问题,我们无法解决。
  • 如果有产品硬件故障问题,比如无法开机,论坛很难解决。可以直接找售后维修
  • 发帖子之前,请确认看过所有的视频教程,https://singtown.com/learn/ 和所有的上手教程http://book.openmv.cc/
  • 每一个新的提问,单独发一个新帖子
  • 帖子需要目的,你要做什么?
  • 如果涉及代码,需要报错提示全部代码文本,请注意不要贴代码图片
  • 必看:玩转星瞳论坛了解一下图片上传,代码格式等问题。
  • 大佬,程序卡死,运行不了,急急急,感谢



    • #----------------------------------------------------------------------------

      系统硬件配置初始化

      #----------------------------------------------------------------------------
      import sensor,time,pyb,image
      from pyb import Timer,UART,Pin,LED

      #---摄像头硬件初始化
      #复位
      sensor.reset()

      #设置为灰度图像
      sensor.set_pixformat(sensor.GRAYSCALE)

      #设置彩色
      #sensor.set_pixformat(sensor.RGB565)

      #设置图像大小
      sensor.set_framesize(sensor.QQVGA)

      #相机自检几张图片
      sensor.skip_frames(50)
      #sensor.set_windowing((144, 144)) #取中间的640*80区域

      #关闭白平衡
      sensor.set_auto_whitebal(False)
      red_led = pyb.LED(1)

      #打开时钟,主要负责统计帧率
      clock = time.clock()

      #---发送函数
      def tick(timer):
      uart.write(uart_buf) #发送函数

      #---利用回调函数来进行计时
      def circle_time(timer):
      global run_time
      run_time += 1 #用于计算openmv运算一次所需的时间

      #---定时器2,timer数据发送配置
      senddata = Timer(2, freq = 20) #发送频率是50HZ,20ms跑一次
      senddata.callback(tick) #回调串口发送函数

      #---定时器4计时
      circle_tmp = Timer(4, freq = 100) #定时器4,定时10ms,用于计时
      circle_tmp.callback(circle_time)

      #---串口三配置,负责发送数据
      uart = UART(3, 115200, timeout_char = 1000)
      uart.init(115200, bits=8, parity=None, stop=1)

      #---发送数据协议格式
      uart_buf = bytearray([0xFE,0,0,0,0,0,0,0,0,0,0,0,0])

      #----------------------------------------------------------------------------

      用户自定义值初始化

      #----------------------------------------------------------------------------
      #---阈值初始化
      black_threshold = [(0, 130)] #阈值初始化

      #---循线三个取样区域的权值初始化
      r1 = 0.1
      r2 = 0.2
      r3 = 0.3
      r4 = 0.4

      #---循线三个取样区域的位置、大小初始化
      #roi代表三个取样区域,(x,y,w,h,weight),代表左上顶点(x,y)宽高分别为w和h的矩形,
      #weight为当前矩形的权值。注意本例程采用的QQVGA图像大小为160x120,
      ROIS = [ # [ROI, weight] #摄像头反装(头朝后,芯片朝前),左上角定点(0,0)
      (30, 00, 100, 15,r1), #上方方框
      (30, 35, 100, 15,r2), #中上方框
      (30, 70, 100, 15,r3), #中下方框
      (30, 105,100, 15,r4) #下方方框
      ]

      #三个矩形的阈值要根据实际情况进行调整,离机器人视野最近的矩形权值要最大,
      #如上图的最下方的矩形,即(0, 100, 160, 20, 0.7)
      weight_sum = 0

      #---定时器值初始化
      run_time = 0 #运行时间,统计代码运行一次所需时间

      #---接收发送函数值初始化
      tmp_data = 0 #接收函数中转值
      flag = 0 #巡线标志位
      anla_cricle_sure = 0 #识别到圆标志位(0没有识别 1识别完成)
      threshold_sure = 0 #阈值确认标志位

      #---定义偏移中心点的位置的变量初始化
      err_x = 0 #误差值
      err_y = 0
      prior_x = 0 #前一次误差值
      prior_y = 0
      x_speed = 0 #误差速度
      y_speed = 0
      center_x_sum = 0#循线3区域值和
      center_y_sum = 0
      centroid_sum = 0
      center_x = 0 #权值计算后的最终值
      center_y = 0
      send_err_x = 0 #串口最终发送值,通过分段计算后所得
      send_err_y = 0
      send_x_speed = 0
      send_y_speed = 0
      send_times = 0 #发送次数,通过对20ms处理的算法,用来统计发送次数
      auto_threshold = [0,130]#自动阈值初始化
      times_threshold = 0 #阈值运算次数
      thr = 0 #获取当前阈值
      thr_1 = 0 #平均阈值
      threshold_sum = 0 #阈值累加和

      #----------------------------------------------------------------------------

      扩宽roi,找圆范围

      #----------------------------------------------------------------------------
      def expand_roi(roi):
      extra = 5
      win_size = (160, 120)
      (x, y, width, height) = roi
      new_roi = [x-extra, y-extra, width+2extra, height+2extra]

      if new_roi[0] < 0:
          new_roi[0] = 0
      if new_roi[1] < 0:
          new_roi[1] = 0
      if new_roi[2] > win_size[0]:
          new_roi[2] = win_size[0]
      if new_roi[3] > win_size[1]:
          new_roi[3] = win_size[1]
      
      return tuple(new_roi)
      

      #----------------------------------------------------------------------------

      flag模式选择函数

      接收飞控的指定,相当于switch case语句

      #----------------------------------------------------------------------------
      def fun(temp):
      return{
      '97': 0, #定圆
      '98': 1, #调节阈值
      '99': 2, #循线
      '100': 3, #反向循线
      '101': 4, #循线找圆
      '102': 5, #反向循线找圆
      '103': 6, #单独找圆
      '104': 7, #降落定点
      }.get(temp,0)

      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

      循环代码

      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      while(True):
      #run_time = 0 #将计时清零
      #----------------------------------------------------------------------------
      if uart.any(): #判断飞控有无数据发送
      tmp_data = uart.readchar() #接收数据
      #print("接收数据 %d"%tmp_data)
      num = str(tmp_data)
      flag = fun(num) #调用flag模式函数
      # print(flag)

      #权值赋值
      if flag == 2 or flag == 4:   #正向循线权值
          r1 = 0.1
          r2 = 0.2
          r3 = 0.3
          r4 = 0.4
          
      if flag == 3 or flag == 5:   #反向循线权值
          r1 = 0.4
          r2 = 0.3
          r3 = 0.2
          r4 = 0.1
      

      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

      图像处理

      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      img = sensor.snapshot().lens_corr(1.7) #拍照并返回图像.

      #----------------------------------------------------------------------------

      定点:先找最大的色块,再在色块中找圆,图像中黑色色块越小帧率越高,黑色色块越大速度越慢

      #----------------------------------------------------------------------------
      if flag == 0 or flag == 1:
      blobs = img.find_blobs(black_threshold,area_threshold=150,x_stride=12,y_stride=12)
      anla_cricle_sure = 0 #找圆标志位清零
      threshold_sure = 0 #调制阈值标志位清零
      if blobs:
      #print("定圆")
      #如果找到了目标颜色
      #print(blobs)
      for blob in blobs:
      #迭代找到的目标颜色区域
      is_circle = False
      max_circle = None
      max_radius = -1

                  new_roi = expand_roi(blob.rect())
      
                  for c in img.find_circles(threshold = 3800, x_margin = 25, y_margin = 25, r_margin = 25, roi=new_roi):
                      is_circle = True
                      #img.draw_circle(c.x(), c.y(), c.r(), color = (255, 255, 255))
                      if c.r() > max_radius:
                          max_radius = c.r()
                          max_circle = c
                  if is_circle:
                      #print("定到圆")
                      #如果有对应颜色的圆形,标记外框
                      #img.draw_rectangle(new_roi) #rect
                      #img.draw_rectangle(blob.rect()) #rect
                      err_y = int(60 - max_circle.y())
                      err_x = int(max_circle.x() - 80)
                      #img.draw_circle(max_circle.x(), max_circle.y(), max_circle.r(), color = (255, 255, 255))
                      #err_y = int(60-blob.cy())
                      #err_x = int(blob.cx() - 80)
                      x_speed = err_x - prior_x
                      y_speed = err_y - prior_y
                      prior_x = err_x
                      prior_y = err_y              
                      #用矩形标记出目标颜色区域
                      #img.draw_cross(blob[5], blob[6]) # cx, cy
                      #img.draw_circle(max_circle.x(), max_circle.y(), max_circle.r(), color = (0, 255, 0))
                      #img.draw_circle(max_circle.x(), max_circle.y(), max_circle.r() + 1, color = (0, 255, 0))
          else:
              err_x=0
              err_y=0
              x_speed = 0
              y_speed = 0   
      

      #----------------------------------------------------------------------------

      自动阈值计算

      #----------------------------------------------------------------------------
      if flag == 1 and run_time > 10: #寻线时打开阈值测量
      histogram = img.get_histogram()
      thresholds = histogram.get_threshold()
      thr = thresholds.value() #获取当前阈值
      times_threshold += 1 #计算10次
      threshold_sum += thr #阈值之和
      run_time = 0
      if(times_threshold == 10):
      thr_1 = threshold_sum//10 #求平均
      auto_threshold[1] = thr_1 #得到的阈值写成列表形式
      black_threshold = [tuple(auto_threshold)] #阈值赋值
      times_threshold = 0 #阈值计算次数清零
      threshold_sum = 0 #阈值和清零
      threshold_sure = 1 #告诉飞控,阈值调节完毕
      print("threshold_sure=%d"%threshold_sure)
      print(black_threshold)
      flag = 8
      #----------------------------------------------------------------------------

      双轴正向循线:通过判断三个取样色块权值来计算xy轴偏离的距离,从而实现巡线。

      #----------------------------------------------------------------------------
      if flag == 2 or flag == 4:
      center_x_sum = 0
      center_y_sum = 0
      centroid_sum = 0
      weight_sum = 0
      #print("双轴循线")

          for r in ROIS:
              blobs = img.find_blobs(black_threshold, roi=r[0:4], merge=True,x_stride=10)
              # r[0:4] is roi tuple.
              #找到视野中的线,merge=true,将找到的图像区域合并成一个
              if blobs:
                  most_pixels = 0
                  largest_blob = 0
                  for i in range(len(blobs)):
                  #目标区域找到的颜色块(线段块)可能不止一个,找到最大的一个,作为本区域内的目标直线
                      if blobs[i].pixels() > most_pixels:
                          most_pixels = blobs[i].pixels()
                          #merged_blobs[i][4]是这个颜色块的像素总数,如果此颜色块像素总数大于#most_pixels,则把本区域作为像素总数最大的颜色块。更新most_pixels和largest_blob
                          largest_blob = i                        
                  #将此区域的像素数最大的颜色块画矩形和十字形标记出来       
                  #img.draw_rectangle(blobs[largest_blob].rect())
                  #img.draw_cross(blobs[largest_blob].cx(),blobs[largest_blob].cy())
                  center_x_sum += blobs[largest_blob].cx()*r[4]
                  center_y_sum += blobs[largest_blob].cy()*r[4]    
                  weight_sum += r[4]
                  center_x = int(center_x_sum/weight_sum)
                  center_y = int(center_y_sum/weight_sum) 
                  #img.draw_cross(center_x,center_y)        
                  err_x = center_x - 80
                  err_y = int((60 - center_y)*0.3) #乘0.3,减小往前走的速度
                  x_speed = err_x - prior_x
                  y_speed = err_y - prior_y
                  prior_x = err_x
                  prior_y = err_y
                  #print("循到线")
      

      #----------------------------------------------------------------------------

      双轴反向循线:将y轴的值取反,通过判断三个取样色块权值来计算xy轴偏离

      #----------------------------------------------------------------------------
      if flag == 3 or flag == 5:
      center_x_sum = 0
      center_y_sum = 0
      centroid_sum = 0
      #print("双轴循线")

          for r in ROIS:
              blobs = img.find_blobs(black_threshold, roi=r[0:4], merge=True,x_stride=10)
              # r[0:4] is roi tuple.
              #找到视野中的线,merge=true,将找到的图像区域合并成一个
              if blobs:
                  most_pixels = 0
                  largest_blob = 0
                  for i in range(len(blobs)):
                  #目标区域找到的颜色块(线段块)可能不止一个,找到最大的一个,作为本区域内的目标直线
                      if blobs[i].pixels() > most_pixels:
                          most_pixels = blobs[i].pixels()
                          #merged_blobs[i][4]是这个颜色块的像素总数,如果此颜色块像素总数大于#most_pixels,则把本区域作为像素总数最大的颜色块。更新most_pixels和largest_blob
                          largest_blob = i                        
                  #将此区域的像素数最大的颜色块画矩形和十字形标记出来       
                  #img.draw_rectangle(blobs[largest_blob].rect())
                  #img.draw_cross(blobs[largest_blob].cx(),blobs[largest_blob].cy())
                  center_x_sum += blobs[largest_blob].cx()*r[4]
                  center_y_sum += blobs[largest_blob].cy()*r[4]
                  weight_sum += r[4]
                  center_x = int(center_x_sum/weight_sum)
                  center_y = int(center_y_sum/weight_sum)         
                  #img.draw_cross(center_x,center_y)
                  err_x = center_x - 80
                  err_y = int((center_y - 60)*0.3) #乘0.3,减小往前走的速度
                  x_speed = err_x - prior_x
                  y_speed = err_y - prior_y
                  prior_x = err_x
                  prior_y = err_y
                  #print("循到线")
      

      if flag == 4 or flag == 5 or flag == 6:
          blobs = img.find_blobs(black_threshold,area_threshold=150,x_stride=12,y_stride=12)
          if blobs:
              #如果找到了目标颜色
              #print(blobs)
              #print("找圆")
              for blob in blobs:
              #迭代找到的目标颜色区域
                  is_circle = False
                  max_circle = None
                  max_radius = -1
                  
                  new_roi = expand_roi(blob.rect())
      
                  for c in img.find_circles(threshold = 3800, x_margin = 25, y_margin = 25, r_margin = 25, roi=new_roi):
                      is_circle = True
                      #img.draw_circle(c.x(), c.y(), c.r(), color = (255, 255, 255))
                      if c.r() > max_radius:
                          max_radius = c.r()
                          max_circle = c
                  if is_circle:
                      #如果有对应颜色的圆形,标记外框
                      #img.draw_rectangle(new_roi) #rect
                      #img.draw_rectangle(blob.rect()) #rect
                      #img.draw_circle(max_circle.x(), max_circle.y(), max_circle.r(), color = (255, 255, 255))          
                      #用矩形标记出目标颜色区域
                      #img.draw_cross(blob[5], blob[6]) # cx, cy
                      #img.draw_circle(max_circle.x(), max_circle.y(), max_circle.r(), color = (0, 255, 0))
                      #img.draw_circle(max_circle.x(), max_circle.y(), max_circle.r() + 1, color = (0, 255, 0))
      
                      anla_cricle_sure = 1   #告诉飞控找到圆
                      #print("找到圆")
                      flag = 0    # 开始定圆,关闭巡线
      

      #----------------------------------------------------------------------------

      if flag == 7:
          blobs = img.find_blobs(black_threshold)
          if blobs:
              #print("降落定点")
              #如果找到了目标颜色
              most_pixels = 0
              largest_blob = 0
              for i in range(len(blobs)):
                  red_led.off()
              #目标区域找到的颜色块可能不止一个,找到最大的一个
                  if  blobs[i].pixels() > most_pixels:
                      most_pixels = blobs[i].pixels()
                      largest_blob = i
              err_x = int(blobs[largest_blob].cx() - 80)
              err_y = int(60-blobs[largest_blob].cy())
                            
              #img.draw_cross(blobs[largest_blob].cx(),blobs[largest_blob].cy())#调试使用
              x_speed = err_x - prior_x
              y_speed = err_y - prior_y
              prior_x = err_x
              prior_y = err_y
          else:
              err_x = 0
              err_y = 0
              x_speed = 0
              y_speed = 0
      

      #发送值计算
      #send_times = round(run_time/20,2)   #四舍五入法,保留两位小数
      #send_err_x = int(err_x/send_times)
      #send_err_y = int(err_y/send_times)
      #send_x_speed = int(x_speed/send_times)
      #send_y_speed = int(y_speed/send_times)
      
      send_err_x = err_x
      send_err_y = err_y
      send_x_speed = x_speed
      send_y_speed = y_speed
      print("值为=%d"%threshold_sure)
      uart_buf = bytearray([0xFE,send_err_x>>8,send_err_x,send_err_y>>8,send_err_y,
      send_x_speed>>8,send_x_speed,send_y_speed>>8,send_y_speed,
      (send_err_x+send_err_y+send_x_speed+send_y_speed)>>8,
      (send_err_x+send_err_y+send_x_speed+send_y_speed),anla_cricle_sure,threshold_sure])
      

      #----------------------------------------------------------------------------

      数据测试,打开终端观察数据,便于调试

      #----------------------------------------------------------------------------
      #flag = 1
      #帧率值计算,即1S内代码跑了多少次,实际比仿真快一倍
      #print("FPS %f" %clock.fps()) #打印帧率
      #clock.tick()

      #打印测试值
      #print(black_threshold)
      print("flag %d"%flag)
      #print("threshold_sure=%d"%threshold_sure)
      #print("run_time %d"%run_time)
      #print("send_times %f"%send_times)
      print("err_x %d"%err_x)
      print("err_y %d"%err_y)
      #print("x_speed %d"%x_speed)
      #print("y_speed %d"%y_speed)
      #print("send_err_x %d"%send_err_x)
      #print("send_err_y %d"%send_err_y)
      #print("send_x_speed %d"%send_x_speed)
      #print("send_y_speed %d"%send_y_speed)
      #print("weight_sum %d" %weight_sum)
      print("")
      


    • 你这个程序的目的是什么?
      你遇到了什么问题?



    • 我这个程序时用来寻迹的,摄像头用来巡线。但是巡线的阈值我使用的是自动阈值,就是openmv自动测量出当前环境下的阈值(black_threshold),把测试所得到阈值作为巡线的阈值,但是因为加入了自动阈值的检测后,程序有时跑到中途就卡死了,有时系统会提示是定时器2中断的问题,有时仿真时IDE就直接卡死也不提示到底出现了什么错误。我不明白为什么程序会突然卡死?



    • 我觉得有可能你的代码太长了,建议分多个模块调用。



    • 但是我单独测试了一下定时器程序也会跑死?分模块调用,应该如何弄呢?



    • tick函数里,uart_buf不是global的。

      而且你那个利用回调函数来进行计时,真的很没必要。。。
      https://docs.singtown.com/micropython/zh/latest/openmvcam/openmvcam/quickref.html#id2
      内置了utime.ticks_ms函数。。。



    • 我回调函数主要的作用是用来串口发送数据的,就算我把计时部分去掉也会卡死