korone 发表于 2023-4-26 20:51:45

关于用树莓派配合小幻熊视觉模块巡线走路机器人

请问我买了树莓派想要用python搭配小幻熊ai视觉模块进行巡线行走,现在有能识别线条id的程序,怎么让它能在识别到黑线id的时候进行走路import time
import struct
from smbus2 import SMBus, i2c_msg

WONDERCAM_REG_SYS_FIRMWARE_VERSION = (0x0000)
WONDERCAM_REG_SYS_LIGHT_STATE = (0x0030)
WONDERCAM_REG_SYS_CURRENT_FUNC = (0x0035)

WONDERCAM_REG_FACE_DETECT_BASE = (0x0400)
WONDERCAM_REG_OBJ_DETECT_BASE = (0x0800)
WONDERCAM_REG_CLASSIFICATION_BASE = (0x0C00)
WONDERCAM_REG_FEATURE_LEARNING_BASE = (0x0E00)
WONDERCAM_REG_COLOR_DETECT_BASE = (0x1000)
WONDERCAM_REG_LINE_FOLLOWING_BASE = (0x1400)
WONDERCAM_REG_APRILTAG_BASE = (0x1E00)
WONDERCAM_REG_QRCODE_BASE = (0x1800)
WONDERCAM_REG_BARCODE_BASE = (0x1C00)

WONDERCAM_FUNC_NONE = (0x00)
WONDERCAM_FUNC_FACE_DETECT = (0x01)
WONDERCAM_FUNC_OBJ_DETECT = (0x02)
WONDERCAM_FUNC_CLASSIFICATION = (0x03)
WONDERCAM_FUNC_FEATURE_LEARNING = (0x04)
WONDERCAM_FUNC_COLOR_DETECT = (0x05)
WONDERCAM_FUNC_LINE_FOLLOWING = (0x06)
WONDERCAM_FUNC_APRILTAG = (0x07)
WONDERCAM_FUNC_QRCODE = (0x08)
WONDERCAM_FUNC_BARCODE = (0x09)
WONDERCAM_FUNC_NUMBER_REC = (0x0A)
WONDERCAM_FUNC_LANDMARK_REC = (0x0B)

WONDERCAM_OBJ_AIRPLANE = (1)
WONDERCAM_OBJ_BICYCLE = (2)
WONDERCAM_OBJ_BIRD = (3)
WONDERCAM_OBJ_BOAT = (4)
WONDERCAM_OBJ_BOTTLE = (5)
WONDERCAM_OBJ_BUS = (6)
WONDERCAM_OBJ_CAR = (7)
WONDERCAM_OBJ_CAT = (8)
WONDERCAM_OBJ_CHAIR = (9)
WONDERCAM_OBJ_COW = (10)
WONDERCAM_OBJ_DINING_TABLE = (11)
WONDERCAM_OBJ_DOG = (12)
WONDERCAM_OBJ_HORSE = (13)
WONDERCAM_OBJ_MOTORBIKE = (14)
WONDERCAM_OBJ_PERSON = (15)
WONDERCAM_OBJ_POTTED_PLANT = (16)
WONDERCAM_OBJ_SHEEP = (17)
WONDERCAM_OBJ_SOFA = (18)
WONDERCAM_OBJ_TRAIN = (19)
WONDERCAM_OBJ_MONITOR = (20)

class WonderCam:

    def __init__(self, i2c_addr=0x32, i2c_adapter=1):
      self.i2c_adapter = i2c_adapter
      self.i2c_addr = i2c_addr
      self.summary = b''# 结果概述缓存
      self.result = b''# 结果内容缓存
      self.curFunc = 0# 当前缓存结果对应功能

    @staticmethod
    def __get_addr_bytes(addr):
      lb = addr & 0xFF
      hb = (addr >> 8) & 0xFF
      return

    def read_from_mem(self, addr, length):
      write = i2c_msg.write(self.i2c_addr, self.__get_addr_bytes(addr))
      read = i2c_msg.read(self.i2c_addr, length)
      with SMBus(self.i2c_adapter) as bus:
            bus.i2c_rdwr(write, read)
      return bytes(list(read))

    def write_to_mem(self, addr, dat):
      buf = self.__get_addr_bytes(addr)
      buf.extend(dat)
      write = i2c_msg.write(self.i2c_addr, buf)
      with SMBus(self.i2c_adapter) as bus:
            bus.i2c_rdwr(write)
            
    def firmware_version(self):
      """
            功能:获取固件版本号
            参数:无
            返回:版本号字符串, 如: "v0.6.5"
      """
      return self.read_from_mem(WONDERCAM_REG_SYS_FIRMWARE_VERSION, 16).decode('utf-8').replace('\x00', '')

    def set_led(self, new_st):
      """
            功能:设置LED开关状态
            参数:new_st 新的LED状态, False为关, True为开
            返回: None
      """
      self.write_to_mem(WONDERCAM_REG_SYS_LIGHT_STATE,)

    def cur_func(self):
      """
            功能:获取当前运行中的功能
            参数: fun 要运行的新功能
            返回: None
      """
      return int(self.read_from_mem(WONDERCAM_REG_SYS_CURRENT_FUNC, 1))

    def set_func(self, func, timeout=3):
      """
            功能: 设置要运行的功能, 此方法会阻塞等待切换成功直至成功或超时
            参数: fun 要运行的新功能,timeout超时时间单位秒
            返回: 成功返回True, 超时返回False
      """
      self.write_to_mem(WONDERCAM_REG_SYS_CURRENT_FUNC, )
      timeout += time.time()
      while True:
            time.sleep(0.05)
            if self.cur_func() == func:
                return True
            if time.time() > timeout:
                return False

    def update_result(self):
      """
            功能: 更新并获取结果到缓存
            参数: 无
            返回: None
      """
      cur_func = self.cur_func()
      self.curFunc = cur_func
      tmp = (None, 0x0400, 0x0800, 0x0C00, 0x0E00, 0x1000, 0x1400, 0x1E00, 0x1800, 0x1C00, 0x0D00, 0x0D80)
      addr = tmp
      if addr is None:
            return
      self.summary = self.read_from_mem(addr, 48)# 获取结果概述,描述了本次结果的长度等情况
      if self.summary > 0:# 根据结果个数读取对应长度字节
            if 0 < cur_func < 3 or 5 <= cur_func < 7 or cur_func == 10 or cur_func == 11:
                self.result = self.read_from_mem(addr + 0x30, 16 * self.summary)
            elif cur_func == 7:
                self.result = self.read_from_mem(addr + 0x30, 32 * self.summary)
            else:# 二维码等不直接读取,因为可能比较长, 再需要用时再读取
                self.result = b''
      else:
            self.result = b''

    def is_face_detected(self, id_want=None):# 检查在画面中是否存在人脸
      """
            功能: 检查是否在画面中识别到指定ID的人脸
            参数: id_want在1~5间时代表要检查的人脸id, 为None就是为任意人脸, 若为0只指未学习的人脸
            返回: 若识别到则返回 True
                  若未识别到返回 False
      """
      if self.curFunc == WONDERCAM_FUNC_FACE_DETECT and self.summary > 0:# 当前结果的功能不是人脸识别
            if id_want is None:# 任意人脸,已学习或未学习的
                return True
            if id_want == 0:
                id_want = 0xFF
            for i in range(4, 4 + self.summary):# 未学习or已学习人脸
                if self.summary == id_want:
                  return True
      return False

    def get_face(self, id_want, face_type=1):# 获取人脸, type = 1 为已学习人脸, type = 2 为未学习人脸
      """
          功能: 获取识别到的指定的人脸
          参数: id_want 要获取的人脸ID, 若face_type=2则为要获取的人脸的序号
                face_type 要获取的人脸的类型, face_type = 1为已学习人脸, face_type = 2 为未学习人脸
          返回: 若识别到则返回一个元组人脸的(中心X 中心Y, 宽, 高)
                若未识别到返回 None
      """
      if self.is_face_detected():
            if face_type == 1:# 获取指定id人脸
                for i in range(4, 4 + self.summary):# 逐个检查识别到的人脸是否是想要的人脸
                  if self.summary == id_want:
                        index = 16 * (i - 4)
                        return struct.unpack("<hhHH", self.result)
            elif face_type == 2:# 获取未学习人脸
                for i in range(4, 4 + self.summary):
                  if self.summary == 0xFF:
                        id_want -= 1# 要第id_want 个未学习的人脸
                        if id_want == 0:
                            index = 16 * (i - 4)
                            return struct.unpack("<hhHH", self.result)
            else:
                pass
      return None

    def is_detected_common(self, func, id_want):
      if self.curFunc == func and self.summary > 0:
            if id_want is None:
                return True
            else:
                for i in range(2, 2 + self.summary):
                  if self.summary == id_want:
                        return True
      return False

    def is_object_detected(self, id_want=None):   # 人脸识别
      """
            功能: 检查是否在画面中识别到指定ID的人脸
            参数: id_want为None时检查是否识别到任何可以识别的物品, id_want为ID时检查是否识别到特定物品
            返回: 若识别到则返回 True
               若未识别到返回 False
      """
      return self.is_detected_common(WONDERCAM_FUNC_OBJ_DETECT, id_want)

    def get_object(self, id_want, index):      # 图像分类
      """
            功能: 获取在画面中识别到的物品的数据
            参数: id_want为要获取的物品ID, index为要获取的物品序号(因可能在画面中同时识别到多个同样的物品)
            返回: (X坐标, Y坐标, 宽度, 高度)
      """
      if self.is_object_detected():
            for i in range(2, 2 + self.summary):
                if self.summary == id_want:
                  index -= 1
                  if index == 0:
                        index = 16 * (i - 2)
                        return struct.unpack("<hhHH", self.result)
      return None

    def most_likely_id(self):            # 图像分类
      """
          功能: 图像分类或特征学习中获取可能性最大的ID
          参数: 无
          返回: 一个整数, 可能性最大的ID
      """
      if self.curFunc == WONDERCAM_FUNC_CLASSIFICATION or self.curFunc == WONDERCAM_FUNC_FEATURE_LEARNING:
            return self.summary
      return 0

    def max_conf(self):
      """
          功能: 图像分类或特征学习中获取可能性最大的ID对应的概率
          参数: 无
          返回: 一个小数, 对应的概率
      """
      if self.curFunc == WONDERCAM_FUNC_CLASSIFICATION or self.curFunc == WONDERCAM_FUNC_FEATURE_LEARNING:
            conf = int.from_bytes(self.summary, byteorder="little", signed=False)
            conf = conf / 10000.0
            return conf
      return 0

    def conf_of_id(self, id_want):      
      """
          功能: 图像分类或特征学习中获取图像是指定id_want的概率
          参数: 无
          返回: 一个小数, 对应的概率
      """
      if self.curFunc == WONDERCAM_FUNC_CLASSIFICATION or self.curFunc == WONDERCAM_FUNC_FEATURE_LEARNING:
            addr = 0x10 + ((id_want - 1) * 4)
            conf = int.from_bytes(self.summary, byteorder="little", signed=False)
            conf = conf / 10000.0
            return conf
      return 0

    def is_color_blob_detected(self, id_want=None):    # 颜色识别
      """
          功能: 检查是否在画面中识别到指定的颜色ID
          参数: id_want=要获取的颜色ID, id_want为None时检查任意一个ID的颜色, id_want为1~7间时检测指定ID颜色
          返回: 若识别到则返回 True
                若未识别到返回 False
      """
      return self.is_detected_common(WONDERCAM_FUNC_COLOR_DETECT, id_want)

    def get_color_blob(self, id_want):
      """
          功能: 获取识别到的指定ID的颜色色块位置数据
          参数: id_want=要获取的颜色ID
          返回: 若识别到则返回一个元组色块的(中心X 中心Y, 宽, 高)
                若未识别到返回 None
      """
      if self.is_color_blob_detected(id_want):
            for i in range(2, 2 + self.summary):
                if self.summary == id_want:
                  index = 16 * (i - 2)
                  return struct.unpack("<hhHH", self.result)# 反序列化
      return None

    def is_line_detected(self, id_want=None):      # 视觉巡线
      """
          功能: 检查是否在画面中识别到指定ID的线条
          参数: id_want=要获取的线条ID, id_want为None时检查任意一个ID的线条, id_want为1~3间时检测指定ID的线条
          返回: 若识别到则返回 True
                若未识别到返回 False
      """
      return self.is_detected_common(WONDERCAM_FUNC_LINE_FOLLOWING, id_want)

    def get_line(self, id_want):
      """
          功能: 获取识别到的指定ID的线条数据
          参数: id_want=要获取的线条ID
          返回: 若识别到则返回一个元组色块的(箭头尖端X, 简短Y, 尾部X, 尾部Y, 偏移, 角度)
                若未识别到返回 None
          关于apriltag标签识别, WonderCam Standard v1设计只识别TAG36H11族标签,其他族的apriltag会被忽略不识别      
      """
      if self.is_line_detected(id_want):
            for i in range(2, 2 + self.summary):
                if self.summary == id_want:
                  index = 16 * (i - 2)
                  x, y, w, h, angle, offset = struct.unpack("<hhHHhh", self.result)
                  angle = angle - 180 if angle > 90 else angle
                  offset = abs(offset) - 160
                  return x, y, w, h, angle, offset
      return None

    def is_tag_detected(self, id_want=None):      # 标签识别
      """
          功能: 检查是否在画面中识别到了标签, 或者指定ID的标签
          参数: id_want 若为None则识别任意ID的标签, 若为指定的ID数值则识别指定ID
          返回:若识别到则返回 True
                若未识别到返回 False
      """
      return self.is_detected_common(WONDERCAM_FUNC_APRILTAG, id_want)

    def num_of_tag_detected(self, id_want=None):
      """
          功能: 获取在画面中识别到的标签的个数
          参数: id_want 若为None则获取画面中识别到的全部标签的个数, 若为指定ID则获取画面中识别到的指定ID的标签个数
          返回:若识别到则返回识别到的个数
                若未识别到返回0
      """
      ret = 0
      if self.curFunc == WONDERCAM_FUNC_APRILTAG:
            if id_want is None:
                return int(self.summary)
            else:
                if id_want >= 0:
                  for i in range(2, 2 + self.summary):
                        if self.summary == id_want:
                            ret += 1
      return ret

    def get_tag(self, id_want, index):
      """
          功能: 获取在画面中识别到的第index个id为id_want的标签的位置姿态数据
          参数: id_want为要获取的标签的id, index为画面中识别到的第index个id_want的标签 (一个画面中可以识别到多个同id的标签, 所以要做选择)
          返回: 若获取成功返回标签数据 (中心X, 中心Y, 宽, 高, X轴变换, X轴旋转, Y轴变换, Y轴旋转, Z轴变换, Z轴旋转)
      """
      if self.is_tag_detected():
            for i in range(2, 2 + self.summary):
                if self.summary == id_want:
                  index -= 1
                  if index == 0:
                        index = 32 * (i - 2)
                        return struct.unpack("<hhHHffffff", self.result)
      return None

    def landmark_most_likely(self):         # 路标识别
      """
          功能: 获取路标识别中最可能的路标
          参数: 无
          返回: 一个整数, 可能性最大的路标的ID
      """
      if self.curFunc == WONDERCAM_FUNC_LANDMARK_REC:
            return self.summary
      return 0

    def landmark_max_conf(self):
      """
          功能: 路标识别中最大的概率
          参数: 无
          返回: 一个小数, 对应的概率
      """
      if self.curFunc == WONDERCAM_FUNC_LANDMARK_REC:
            conf = int.from_bytes(self.summary, byteorder="little", signed=False)
            conf = conf / 10000.0
            return conf
      return 0

    def landmark_conf_of_id(self, id_want):
      """
          功能: 路标识别中是某个指定的路标的概率
          参数: 无
          返回: 一个小数, 对应的概率
      """
      if self.curFunc == WONDERCAM_FUNC_LANDMARK_REC:
            addr = 0x10 + ((id_want - 1) * 4)
            conf = int.from_bytes(self.summary, byteorder="little", signed=False)
            conf = conf / 10000.0
            return conf
      return 0

    def number_most_likely(self):          # 数字识别
      """
          功能: 获取数字识别中最可能的路标
          参数: 无
          返回: 一个整数, 可能性最大的数字的ID
      """
      if self.curFunc == WONDERCAM_FUNC_NUMBER_REC:
            return self.summary
      return 0

    def number_max_conf(self):
      """
          功能: 数字识别中最大的概率
          参数: 无
          返回: 一个小数, 对应的概率
      """
      if self.curFunc == WONDERCAM_FUNC_NUMBER_REC:
            conf = int.from_bytes(self.summary, byteorder="little", signed=False)
            conf = conf / 10000.0
            return conf
      return 3

if __name__ == "__main__":
    cam = WonderCam()
    # """识别指定线条"""
    cam.set_func(WONDERCAM_FUNC_LINE_FOLLOWING)
    while True:
      try:
            cam.update_result()
            cam.set_led(True)
            if cam.is_line_detected():
                for i in range(1,4):
                  if cam.get_line(i):
                        print("识别到线条ID: %d" %i)   
                        print(cam.get_line(i))
            else:
                print("未识别到线条")
            time.sleep(0.5)
      except KeyboardInterrupt:
            break
      except Exception as e:
            print(e)
            continue
这是识别线条id的代码

歌者文明清理员 发表于 2023-4-26 20:55:58

你没有闭合

korone 发表于 2023-4-26 21:05:31

不是很懂,就是想要识别到那个id的时候执行由多个舵机配合的行走,然后达到个自主巡线的功能

歌者文明清理员 发表于 2023-4-26 21:29:30

korone 发表于 2023-4-26 21:05
不是很懂,就是想要识别到那个id的时候执行由多个舵机配合的行走,然后达到个自主巡线的功能

看不懂你的代码{:10_257:}

陶远航 发表于 2023-4-29 12:22:14

要让树莓派通过小幻熊AI视觉模块识别黑线并进行巡线,你需要编写一个Python程序来控制机器人的移动。你需要将视觉模块与树莓派连接,并使用Python代码来读取它的输出。

下面是一个简单的代码示例,用于识别黑线并控制机器人向前移动:
import time
import RPi.GPIO as GPIO
from hx711 import HX711
from pixy import *

# 初始化Pixy摄像头
pixy = Pixy()

# 初始化HX711模块
hx711 = HX711(dout_pin=5, pd_sck_pin=6)
hx711.set_scale_ratio(scale_ratio=2272.0)
hx711.reset()
hx711.tare()

# 初始化GPIO引脚
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(17, GPIO.OUT)
GPIO.setup(18, GPIO.OUT)

# 设置机器人移动的速度
speed = 40

# 循环执行
while True:
    # 读取Pixy摄像头的输出
    black_line_id = pixy.get_black_line_id()

    # 如果检测到黑线
    if black_line_id != 0:
      # 读取HX711模块的输出,计算重量
      weight = hx711.get_weight_mean()
      
      # 根据重量控制机器人的移动方向
      if weight < -10:
            GPIO.output(17, True)
            GPIO.output(18, False)
      elif weight > 10:
            GPIO.output(17, False)
            GPIO.output(18, True)
      else:
            GPIO.output(17, True)
            GPIO.output(18, True)
    # 如果未检测到黑线
    else:
      GPIO.output(17, False)
      GPIO.output(18, False)
   
    # 等待一段时间后继续执行
    time.sleep(0.01)

这个代码示例假设你已经安装了相关的Python模块,例如RPi.GPIO用于控制GPIO引脚,hx711用于读取重量传感器的数据,以及pixy用于读取Pixy摄像头的输出。

代码首先初始化了Pixy摄像头和HX711模块,并设置了GPIO引脚用于控制机器人的移动。然后进入一个循环,在循环中不断读取Pixy摄像头的输出,并根据输出来控制机器人的移动方向。

如果检测到黑线,则读取重量传感器的数据,并根据重量来控制机器人向左或向右移动。如果未检测到黑线,则停止机器人的移动。

请注意,这只是一个简单的示例程序,你需要根据你的具体硬件和代码实现进行适当的修改。同时,要确保在执行该程序之前正确连接所有的硬件设备,并安装必要的Python模块。

korone 发表于 2023-5-3 18:34:37

陶远航 发表于 2023-4-29 12:22
要让树莓派通过小幻熊AI视觉模块识别黑线并进行巡线,你需要编写一个Python程序来控制机器人的移动。你需要 ...

我是用的幻尔科技的LX-824的舵机摄像头好像不是pixy的是那个小幻熊ai视觉模块
页: [1]
查看完整版本: 关于用树莓派配合小幻熊视觉模块巡线走路机器人