回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

行空板M10扩展板——行空智能跟随垃圾桶 简单

头像 云天 2025.06.29 16 0

【项目背景】

在日常生活中,打扫卫生时常常需要频繁移动垃圾桶,这给使用者带来了诸多不便。为了解决这一问题,我计划设计一个行空智能跟随垃圾桶,它能够在听到我的呼唤后自动跟随我,方便我在打扫过程中随时使用。经过研究和尝试,我选择了在行空板M10上安装Snowboy库进行离线语音唤醒,并使用OpenCV进行人体检测,同时借助硅基流动平台的图像理解大模型进行图像分析,以实现这一功能。

【项目设计】

我将设计一个行空智能跟随垃圾桶,其主要功能如下:

离线语音唤醒:通过安装在行空板M10上的Snowboy库,垃圾桶能够离线识别我的唤醒词,“你好小云”,并迅速做出响应。

人体检测与图像分析:垃圾桶会旋转并使用OpenCV进行人体检测,若未检测到人体,则旋转一定角度(90度)再次检测,直至回到起点。一旦检测到人体,垃圾桶会将照片上传至硅基流动平台进行图像分析,判断是否有人拿着打扫工具。

自动跟随与避障:如果发现有人拿着打扫工具,垃圾桶会驱动电机前进,并通过超声波传感器测量与人的距离,当距离达到30cm时自动停止,确保在打扫室内卫生时能够方便地跟随使用者。

 

 

【制作步骤】

1.安装依赖库

sudo apt-get install python-pyaudio python3-pyaudio swig

2.下载代码

https://github.com/Kitt-AI/snowboy.git

3.安装puaduio库

sudo pip3 install pyaudio

4.生成个人唤醒词模型

网址https://snowboy.hahack.com/,方法:记录3个唤醒词示例,并将其提交以生成.pmdl文件。
(1)启用麦克风(Chrome需要)
(2)单击录制并等待准备就绪
(3)说出你的醒语,等待结束
(4)重复,直到你有3个例子
(5)输入模型名称,提交音频,然后单击“保存模型”按钮

(6)下载模型

image.png

5.将模型上传到行空板

image.png

【代码编写】

1.修改snowboy/examples/demo.py代码,实现直接加载指定唤醒词模型

#if len(sys.argv) == 1:

#    print("Error: need to specify model name")

#    print("Usage: python demo.py your.model")

#    sys.exit(-1)


 

#model = sys.argv[1]

model = "/root/snowboy/resources/models/xiaoxing.pmdl"      

2.修改snowboy/examples/demo.py/snowboydecoder.py文件,实现人体检测、图像分析、电机驱动。

(1)加载语音提醒,“我在呢”,“看到你了,我来了”                               

DETECT_Hello = os.path.join(TOP_DIR, "resources/xiaoxing.wav")

DETECT_COME = os.path.join(TOP_DIR, "resources/come.wav")

(2)使用OpenCV的Haar 检测器,进行人体检测。如检测到人体将此图像进行Base64编码。

import cv2

# 加载 Haar 检测器

face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

def camera():

    global bs,cap

    if bs==0:

        # 打开摄像头

        cap = cv2.VideoCapture(0)  # 参数 0 表示使用默认摄像头

        if not cap.isOpened():

           print("无法打开摄像头")

           return -1

        bs=1

    # 读取一帧

    ret, frame = cap.read()

    if not ret:

        print("无法读取帧")

        return 0

     # 检测行人

    # 转换为灰度图

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 检测人脸

    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))

    # 判断是否有人

    if len(faces) > 0:

        play_audio_file(DETECT_DING)

        print("有人")

        # 将 OpenCV 的 BGR 图像转换为 PIL 的 RGB 图像

        frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        pil_image = Image.fromarray(frame_rgb)

        # 转换为 Base64 编码

        base64_image = convert_image_to_webp_base64(pil_image)

        if base64_image:

            print("Base64 编码成功!")

            # 在这里可以处理 Base64 编码的字符串,例如打印或发送到服务器

            print(base64_image[:20])  # 打印前 100 个字符作为示例

            Vlcontent=QwenVL(base64_image)

            print(Vlcontent)

            if "是" in Vlcontent:

                play_audio_file(DETECT_COME)

                print("yes")

                return 1

            else:

                print("no")

                return 0

        else:

            print("Base64 编码失败!")

            return 0

    else:

        play_audio_file(DETECT_DONG)

        print("无人")

        return 0

def convert_image_to_webp_base64(image):

    """

    将图像对象转换为 WebP 格式的 Base64 编码字符串。

    :param image: PIL.Image 对象

    :return: Base64 编码字符串

    """

    try:

        byte_arr = io.BytesIO()

        image.save(byte_arr, format='webp')

        byte_arr = byte_arr.getvalue()

        base64_str = base64.b64encode(byte_arr).decode('utf-8')

        return base64_str

    except IOError:

        print("Error: Unable to convert the image to WebP Base64")

        return None

(3)使用硅基流动的图像理解大模型,进行图像分析,检测是否有人拿着打扫工具。                                    

def QwenVL(base64_url):

    response = client.chat.completions.create(

        model="Qwen/Qwen2-VL-72B-Instruct",

        messages=[

        {

            "role": "user",

            "content": [

                {

                    "type": "image_url",

                    "image_url": {

                        "url": "data:image/jpg;base64,"+base64_url

                    }

                },

                {

                    "type": "text",

                    "text": "请看一下这张图像中,如果有一个人手中拿着打扫工具,请回复是,否则回复否。"

                }

            ]

        }],

        stream=False

)

    return response.choices[0].message.content

(4)唤醒后,控制电机转向并检测,识别到目标,驱动电机前进,并利用超声传感器测距。                 

def play_audio_file(fname=DETECT_Hello):

    """Simple callback function to play a wave file. By default it plays

    a Ding sound.


 

    :param str fname: wave file name

    :return: None

    """


 

    ding_wav = wave.open(fname, 'rb')

    ding_data = ding_wav.readframes(ding_wav.getnframes())

    with no_alsa_error():

        audio = pyaudio.PyAudio()

    stream_out = audio.open(

        format=audio.get_format_from_width(ding_wav.getsampwidth()),

        channels=ding_wav.getnchannels(),

        rate=ding_wav.getframerate(), input=False, output=True)

    stream_out.start_stream()

    stream_out.write(ding_data)

    time.sleep(0.2)

    stream_out.stop_stream()

    stream_out.close()

    audio.terminate()

    if fname==DETECT_Hello:

        print("已唤醒")

        for i in range(4):

            j=camera()

            if j==0:

                #转向

                turn(1,800)

                time.sleep(0.3)

                stop()

                time.sleep(4)

                continue

            else:

                break

        if j==1:

           print("前进")

           #前进

           while True:

             print(urm091.distance_cm())

             if urm091.distance_cm()>30:

               goahead(1,800)

             else:

               stop()

               break

 

(5)电机驱动

def goahead(direction,PWM):

    p_p23_pwm.write_analog(PWM)

    p_p24_out.write_digital(direction)

    p_p9_out.write_digital(direction)

    p_p21_pwm.write_analog(PWM)

    p_p1_out.write_digital(1-direction)

    p_p4_out.write_digital(1-direction)

def turn(direction,PWM):

    p_p23_pwm.write_analog(PWM)

    p_p24_out.write_digital(direction)

    p_p9_out.write_digital(direction)

    p_p21_pwm.write_analog(PWM)

    p_p1_out.write_digital(direction)

    p_p4_out.write_digital(direction)

def stop():

    p_p23_pwm.write_analog(0)

    p_p21_pwm.write_analog(0)

 

【硬件组装】

1.底盘使用麦克纳姆轮,两个两路电机驱动,两节锂电池供电。                  

d3612e98b701051d3794c3f8aa87858.jpg

2.使用行空板M10及扩展上的相应引脚(代码中有设置),连接电机驱动、超声波传感器。因使用了独立的电机驱动,扩展板上的电机驱动引脚未使用。                               

dbd0b757a41935ea9d27827ff1f37b0.jpg

3.固定垃圾桶

46d5d4aba28d1cfbf9b376d75a40991.jpg

4.固定摄像头

 da31add5b4436925ef0fb717aa4f852.jpg

 

036b574afe59a55c0732a345dfd7e77.jpg

【演示视频】

【代码附件】

因附件大小限制为10M,删除了一部分无关本项目的文件。       

评论

user-avatar