【项目背景】
在当今的创客文化和教育环境中,培养学生的创新思维和实践能力成为了教育的重要目标。创客社团作为学校或社区中推广创客文化和项目的重要平台,一直在寻找能够激发学生兴趣、增强实践技能并促进团队合作的教学案例。物联网(IoT)作为一个充满创新潜力的领域,为创客社团提供了丰富的学习资源和项目实施机会。
本项目旨在为创客社团提供一个基于物联网技术的对-讲-机功能的实践案例。通过这个项目,学生将有机会了解和掌握物联网的基本概念、音频处理技术和无线通信原理,同时提高他们的编程能力和问题解决能力。
项目的核心是使用两个行空板,通过物联网技术实现对-讲-机功能。行空板作为一种多功能的开源硬件平台,非常适合用于教育和创新项目。它集成了麦克风和扬声器,可以通过编程实现音频的录制和播放,非常适合用来构建语音通信设备。
【项目目标】
物联网技术理解:学生将学习物联网的基础知识,包括传感器、通信协议和云平台。
编程实践:通过使用Mind+编程软件和Python语言,学生将练习编程技巧,实现音频数据的采集、处理和传输。
音频处理技术:学生将了解音频信号的数字化过程,包括录音、文件格式转换和音频播放。
无线通信原理:学生将探索蓝牙和物联网通信技术,了解它们在无线通信中的应用。
团队合作与交流:项目需要学生分组合作,共同设计、编程和测试对-讲-机系统,培养团队协作和沟通能力。
创新思维:鼓励学生在项目实施过程中发挥创意,探索物联网技术在其他领域的潜在应用。
【知识学习】
成员们分组进行物联网和音频处理技术的基础知识学习,包括了解行空板的功能、Mind+编程软件的使用、Python语言基础、物联网通信协议以及音频信号的数字化处理。
【硬件准备】
社团准备所需的硬件设备,包括两个行空板、两个蓝牙音箱、两个充电宝、必要的连接线和电脑设备。
【编程实践】
1.在老师的指导下,成员们开始编写代码。他们使用Mind+编程软件中的Python编程环境,利用unihiker库的Audio模块来控制行空板上的麦克风进行声音采集,并通过wave库将声音文件转换为十六进制格式。成员们注册并配置物联网平台Easy IOT,创建设备ID和相应的话题,用于音频数据的传输。
import wave,os
import json
import time
from unihiker import GUI
from unihiker import Audio
import siot
bs=1
def send_wave(FILE_PATH):
with wave.open(FILE_PATH, 'rb') as wav_file:
# 获取文件大小
file_size = os.path.getsize(FILE_PATH)
# 读取数据并发送
frame_count = 0
siot.publish(topic="z4ksqL6Ig", data="start")
while True:
frame = wav_file.readframes(1024) # 读取1024字节
if not frame:
break
siot.publish(topic="z4ksqL6Ig", data=frame.hex())
frame_count += 1
显示.config(text="发送:"+str(frame_count)+"frame")
siot.publish(topic="z4ksqL6Ig", data="stop")
# 事件回调函数
def on_buttona_click_callback():
global bs
wave_path="record.wav"
if bs==1:
bs=0
显示.config(text="开始讲话")
u_audio.play("ding.wav")
u_audio.start_record("record.wav")
else:
bs=1
显示.config(text="讲话结束")
u_audio.stop_record()
send_wave(wave_path)
u_audio.play("ding.wav")
u_gui=GUI()
u_audio = Audio()
u_gui.on_a_click(on_buttona_click_callback)
显示=u_gui.draw_text(text="行空板",x=0,y=0,font_size=20, color="#0000FF")
siot.init(client_id="14603802900222362",server="iot.dfrobot.com.cn",port=1883,user="AVNLqL6SR",password="04HYqY6IRz")
siot.connect()
siot.loop()
siot.getsubscribe(topic="z4ksqL6Ig")
while True:
pass
复制代码
2.编写代码,实现音频数据的接收。成员们测试音频数据是否能够成功通过物联网平台接收。
import wave
from unihiker import GUI
import siot
from unihiker import Audio
# 接收到的消息存储在这里
received_frames = []
frame_count=0
# 事件回调函数
def on_message_callback(client, userdata, msg):
global bs2,received_frames,frame_count
re_msg=msg.payload.decode()
if re_msg=="stop":
bs2=2
if bs2==1:
frame_data = bytes.fromhex(re_msg)
received_frames.append(frame_data)
frame_count+=1
显示.config(text="接收到:"+str(frame_count)+"frame")
if re_msg=="start":
bs2=1
received_frames = [] # 重置接收缓冲区
frame_count=0
u_audio.play("ding.wav")
u_gui=GUI()
显示=u_gui.draw_text(text="行空板",x=0,y=0,font_size=20, color="#0000FF")
siot.init(client_id="506958351015395",server="iot.dfrobot.com.cn",port=1883,user="AVNLqL6SR",password="04HYqY6IRz")
u_audio = Audio()
siot.connect()
siot.loop()
siot.set_callback(on_message_callback)
siot.getsubscribe(topic="z4ksqL6Ig")
bs2=0
while True:
if bs2==2:
js=0
bs2=0
# 重新组装WAV文件
FILE_NAME = "received.wav"
with wave.open(FILE_NAME, 'wb') as out_file:
out_file.setnchannels(1) # 单声道
out_file.setsampwidth(2) # 采样宽度2字节
out_file.setframerate(16000) # 采样率44100Hz
for frame in received_frames:
out_file.writeframes(frame)
js+=1
print(js)
u_audio.play(FILE_NAME)
print(f"Reassembly complete, saved to {FILE_NAME}")
复制代码
【蓝牙音箱连接】
成员们学习如何通过蓝牙将行空板与音箱连接,并将接收到的音频数据播放出来。
import subprocess
import sys
sys.path.append("/root/mindplus/.lib/thirdExtension/nick-pyttsx3-thirdex")
import pyttsx3
engine = pyttsx3.init()
# 搜索附近的蓝牙设备
def connect_bluetooth(address):
result = subprocess.run(['bluetoothctl', 'default-agent'], stdout=subprocess.PIPE)
result = subprocess.run(['bluetoothctl', 'power', 'on'], stdout=subprocess.PIPE)
result = subprocess.run(['bluetoothctl', 'pair', address], stdout=subprocess.PIPE)
result=subprocess.run(['bluetoothctl', 'connect', address], stdout=subprocess.PIPE)
print(result)
engine.say("蓝牙连接已完成")
engine.runAndWait()
def is_connected(device_mac):
# 获取已配对的设备列表
result = subprocess.run(['bluetoothctl', 'paired-devices'], stdout=subprocess.PIPE)
paired_devices = result.stdout.decode().strip().split('\n')[1:] # 跳过标题行
# 遍历已配对的设备,检查MAC地址
for device in paired_devices:
if device_mac in device:
# 如果设备已配对,检查是否已连接
result = subprocess.run(['bluetoothctl', 'info', device_mac], stdout=subprocess.PIPE)
info = result.stdout.decode().strip().split('\n')
for line in info:
if "Connected: yes" in line:
return True
return False
# 你的蓝牙音箱的MAC地址
#speaker_mac = "08:D0:03:96:70:8D"#收音机音箱
#speaker_mac ="41:42:BE:4A:B6:C1"#海螺音箱
speaker_mac ="5A:5A:5A:A7:01:CA"#话筒音箱
if not(is_connected(speaker_mac)):
connect_bluetooth(speaker_mac)
else:
engine.say("蓝牙已连接")
engine.runAndWait()
while True:
pass
#先用手机搜索蓝牙音箱,查看蓝牙音箱名称。如X8
#使用 PowerShell:
#打开 PowerShell。可以在开始菜单中搜索 “PowerShell”,然后右键选择 “以管理员身份运行”。
#输入以下命令:Get-PnpDevice -Class Bluetooth | Select-Object FriendlyName,InstanceId,Status,DeviceID。这个命令会列出系统中检测到的蓝牙设备的相关信息,包括设备名称、实例 ID、状态和设备 ID 等,你可以根据设备名称等信息来确定你想要获取 MAC 地址的蓝牙设备。
#X8 Avrcp 传输 BTHENUM\{0000110C-0000-1000-8000-00805F9B34FB}_LOCALMFG&0002\7&4000742&0&4142BE4AB6C1_C00000000
#X8 BTHENUM\DEV_4142BE4AB6C1\7&4000742&0&BLUETOOTHDEVICE_4142BE4AB6C1
#4142BE4AB6C1,这个就是蓝牙音箱的MAC地址。
复制代码
【系统集成】
所有功能模块的代码集成到一个系统中,进行系统的全面测试,确保音频从采集到播放的整个流程顺畅无误。提示:两个行空板程序,物联网发送和接收主题要互相交换。
import wave,os
import json
import time
from unihiker import GUI
from unihiker import Audio
import siot
import subprocess
import sys
sys.path.append("/root/mindplus/.lib/thirdExtension/nick-pyttsx3-thirdex")
import pyttsx3
engine = pyttsx3.init()
# 搜索附近的蓝牙设备
def connect_bluetooth(address):
result = subprocess.run(['bluetoothctl', 'default-agent'], stdout=subprocess.PIPE)
result = subprocess.run(['bluetoothctl', 'power', 'on'], stdout=subprocess.PIPE)
result = subprocess.run(['bluetoothctl', 'pair', address], stdout=subprocess.PIPE)
result=subprocess.run(['bluetoothctl', 'connect', address], stdout=subprocess.PIPE)
print(result)
engine.say("蓝牙连接已完成")
engine.runAndWait()
def is_connected(device_mac):
# 获取已配对的设备列表
result = subprocess.run(['bluetoothctl', 'paired-devices'], stdout=subprocess.PIPE)
paired_devices = result.stdout.decode().strip().split('\n')[1:] # 跳过标题行
# 遍历已配对的设备,检查MAC地址
for device in paired_devices:
if device_mac in device:
# 如果设备已配对,检查是否已连接
result = subprocess.run(['bluetoothctl', 'info', device_mac], stdout=subprocess.PIPE)
info = result.stdout.decode().strip().split('\n')
for line in info:
if "Connected: yes" in line:
return True
return False
# 你的蓝牙音箱的MAC地址
speaker_mac = "08:D0:03:96:70:8D"#收音机音箱
#speaker_mac ="41:42:BE:4A:B6:C1"#海螺音箱
if not(is_connected(speaker_mac)):
connect_bluetooth(speaker_mac)
else:
engine.say("蓝牙已连接")
engine.runAndWait()
bs=1
# 接收到的消息存储在这里
received_frames = []
frame_count=0
# 事件回调函数
def on_message_callback(client, userdata, msg):
global bs2,received_frames,frame_count
re_msg=msg.payload.decode()
if re_msg=="stop":
bs2=2
if bs2==1:
frame_data = bytes.fromhex(re_msg)
received_frames.append(frame_data)
frame_count+=1
显示.config(text="接收中:"+str(frame_count)+"frame")
if re_msg=="start":
bs2=1
received_frames = [] # 重置接收缓冲区
frame_count=0
def send_wave(FILE_PATH):
with wave.open(FILE_PATH, 'rb') as wav_file:
# 获取文件大小
file_size = os.path.getsize(FILE_PATH)
# 读取数据并发送
frame_count = 0
siot.publish(topic="z4ksqL6Ig", data="start")
while True:
frame = wav_file.readframes(1024) # 读取1024字节
if not frame:
break
siot.publish(topic="z4ksqL6Ig", data=frame.hex())
frame_count += 1
显示.config(text="正在发送:"+str(frame_count)+"frame")
siot.publish(topic="z28640zNg", data="stop")
# 事件回调函数
def on_buttona_click_callback():
global bs
wave_path="record.wav"
if bs==1:
bs=0
显示.config(text="开始讲话")
u_audio1.play("ding.wav")
u_audio1.start_record("record.wav")
else:
bs=1
显示.config(text="讲话结束")
u_audio1.stop_record()
send_wave(wave_path)
u_audio1.play("ding.wav")
u_gui=GUI()
u_audio1 = Audio()
u_audio2 = Audio()
u_gui.on_a_click(on_buttona_click_callback)
显示=u_gui.draw_text(text="行空板语音对讲",x=10,y=60,font_size=30, color="#0000FF")
siot.init(client_id="14603802900222362",server="iot.dfrobot.com.cn",port=1883,user="AVNLqL6SR",password="04HYqY6IRz")
siot.connect()
siot.loop()
siot.set_callback(on_message_callback)
siot.getsubscribe(topic="z4ksqL6Ig")
bs2=0
while True:
if bs2==2:
js=0
bs2=0
# 重新组装WAV文件
u_audio2.play("ding.wav")
显示.config(text="输出中……")
FILE_NAME = "received.wav"
with wave.open(FILE_NAME, 'wb') as out_file:
out_file.setnchannels(1) # 单声道
out_file.setsampwidth(2) # 采样宽度2字节
out_file.setframerate(16000) # 采样率44100Hz
for frame in received_frames:
out_file.writeframes(frame)
js+=1
print(js)
u_audio2.play(FILE_NAME)
显示.config(text="行空板语音对讲")
复制代码
【调试优化】
在测试过程中,成员们可能会遇到各种问题,如音频质量不佳、传输延迟等,他们需要不断调试和优化代码,以提高系统的性能。
【项目展示】
项目完成后,社团将组织一个展示活动,让成员们向同学、老师和其他社团展示他们的成果,分享他们在项目中学到的知识和经验。
通过本项目的学习和实践,学生不仅能够获得宝贵的技术知识和实践经验,还能够体验到从零到一创造一个工作系统的过程,从而激发他们对科技和创新的热情。此外,项目的成功实施也将为创客社团增添一个展示其创新成果的亮点,吸引更多的学生参与到创客活动中来。