17| 2
|
[M10项目] 行空板M10扩展板——行空智能跟随垃圾桶 |
本帖最后由 云天 于 2025-6-30 10:54 编辑 【项目背景】 在日常生活中,打扫卫生时常常需要频繁移动垃圾桶,这给使用者带来了诸多不便。为了解决这一问题,我计划设计一个行空智能跟随垃圾桶,它能够在听到我的呼唤后自动跟随我,方便我在打扫过程中随时使用。经过研究和尝试,我选择了在行空板M10上安装Snowboy库进行离线语音唤醒,并使用OpenCV进行人体检测,同时借助硅基流动平台的图像理解大模型进行图像分析,以实现这一功能。 【项目设计】 我将设计一个行空智能跟随垃圾桶,其主要功能如下: 离线语音唤醒:通过安装在行空板M10上的Snowboy库,垃圾桶能够离线识别我的唤醒词,“你好小云”,并迅速做出响应。 人体检测与图像分析:垃圾桶会旋转并使用OpenCV进行人体检测,若未检测到人体,则旋转一定角度(90度)再次检测,直至回到起点。一旦检测到人体,垃圾桶会将照片上传至硅基流动平台进行图像分析,判断是否有人拿着打扫工具。 自动跟随与避障:如果发现有人拿着打扫工具,垃圾桶会驱动电机前进,并通过超声波传感器测量与人的距离,当距离达到30cm时自动停止,确保在打扫室内卫生时能够方便地跟随使用者。 【制作步骤】 1.安装依赖库 sudo apt-get install python-pyaudio python3-pyaudio swig 2.下载代码 3.安装puaduio库 sudo pip3 install pyaudio 4.生成个人唤醒词模型 网址https://snowboy.hahack.com/,方法:记录3个唤醒词示例,并将其提交以生成.pmdl文件。 (1)启用麦克风(Chrome需要) (2)单击录制并等待准备就绪 (3)说出你的醒语,等待结束 (4)重复,直到你有3个例子 (5)输入模型名称,提交音频,然后单击“保存模型”按钮 (6)下载模型 ![]() 5.将模型上传到行空板 ![]() 【代码编写】 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.底盘使用麦克纳姆轮,两个两路电机驱动,两节锂电池供电。 ![]() 2.使用行空板M10及扩展上的相应引脚(代码中有设置),连接电机驱动、超声波传感器。因使用了独立的电机驱动,扩展板上的电机驱动引脚未使用。 ![]() 3.固定垃圾桶 ![]() 4.固定摄像头 ![]() ![]() 【演示视频】 |
© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed