物联网是一种连接各种各样的传感器的网络,与之对应的是20世纪60年代开始研究的计算机网络,后者将分散于不同地理位置的计算机连接起来。物联网传感器可以采集的信息包括声音、光线、温度、湿度、位置、速度、加速度等。
物联网系统则是在物联网之上,利用各类传感器所提供的信息,通过信息综合、决策判断后形成控制信息,从而做出反应的信息系统。目前的物联网家居系统还处于初始阶段,各类智能家电正在发展。如小米科技的小爱同学,实际为一台智能音箱,可以通过语音获取信息、控制家电通断等。
首先,该系统依旧无法体现出智能家居的优势,即智能度不够。所谓智能,即不受人干预的自主信息搜集、自主判断、自主执行的系统。当我们已经明确知道需要哪台设备通断时,直接打开设备的开关就可以,无需通过智能音箱中转。
举个例子,当你深夜回家时,本能的反应是在黑暗中寻找开关,这时如果再让小爱同学开灯就过于牵强,为智能而智能。真正智能的家居系统应当在你回家开门的那个瞬间,就自己完成了开灯动作,无需命令。
其次,目前的系统可以执行的动作过少。根据中国电子信息产业发展研究院发布的《2019年中国家电市场报告》,我国家电市场零售额规模达到8910亿元,电磁炉、电饭煲、微波炉、洗衣机等设备已经走进千家万户。在激烈的市场竞争下,各类家电的设计早已非常适合人类操作。一般上,我们只需要将家电所需的“原料”放入,给予适当的“加工工序”,家电就可以产出合适的“产品”。仔细观察就会发现,甚至有些家电已经把“加工工序”免去了。比如洗衣机从早先时候的双缸变为现在的单缸,不需要手动将湿衣物挪动到脱水缸。并且有些洗衣机自带烘干功能,脏衣服进去干净可穿的衣物出来。智能家居可以着重在如何自动放入“原料”以及取出“成品”上做研发。
最后,目前的系统过于封闭,自成一派;家电存量大,无法快速推进智能化。在开放性上,目前小米智能家居提供各种接入支持,但需要将控制终端集中到米家APP上,这对其他品牌的智能家电不友好。在智能化的推进上,目前大部分的智能设备都需要新购,无法将旧家电设备纳入到智能家居体系中来。
本系统将在上述分析的基础上,使用无损伤智能化的模式,将旧家电改造为智能家电;使用舵机、电机等设备构建简单的机械臂用于挪动物品,实现无需干预的添加“原料”的功能。
LoRa是一种应用于广域低功耗无线网的标准,在低功耗的前提上有效地提高了传输距离。由该标准的特性可知,LoRa设备在城镇的传输距离可达2-5Km郊区可达15Km。所使用的频率为433MHz、868MHz、915MHz等,无需申请频谱执照。在接入容量上,一个LoRa网关可以容纳数千个节点,远远大于现有的WiFi路由器。若考虑到传输速率,LoRa标准可以达到几百到几十Kbps. LoRa标准的种种特性决定了它是一种比较适合物联网环境的通信标准。
语音识别并不是新鲜事,早在1952年,由贝尔实验室研制的自动数字识别机“Audrey”就可以识别基本的音素。该设备体型巨大,占据了一个6英尺高的继电器机架,耗电量巨大,连接着成群的电线。一般上,实现语音交互需要语音识别与语音合成两部分内容。语音识别需要经过语音转文字与自然语言处理过程,语音合成需要注意音调、语调等内容。幸运的是,语音交互已经非常成熟,我们可以直接接入公有云服务来实现。
考虑到扩大智能家居的控制范围,我们需要寻找合适的控制机构,自动售货机或许是一个不错的研究对象。
下图是自动售货机的外观图。
我们主要研究自动售货机与出货相关的机械结构。售货机内的电脑系统便会传达指令给机器”抓手“,对特定的商品轨道进行”推出“和”旋转“的动作,让商品可以掉落。为了确保商品在操作之下有成功被运出,售货机的底部还设有10道红外线光速。若是红外线没有探测到掉落的商品,那售货机便会自行再次”推落“商品,以确保客人可以拿到他购买的东西。
下图是自动售货机的出货机械结构。
可以看到,商品放到支撑架上,通过弹簧的旋转来形成推力,将商品推下,并由重力带到取货仓。
这里的机械手主要指由多个关节组成的多轴机械臂,该机械结构可以取代自动售货机的旋转弹簧来挪动物体。一般的机械臂有6自由度、4自由度、3自由度等。
下图是一台工业用6轴机械臂。
使用机械臂较为复杂,涉及到机械、电气、控制三大部分。机械部分可以采用开源的设计图,电气部分采用步进电机或者舵机(大型机械臂使用伺服电机,小型机械臂使用步进电机,而微型机械臂使用舵机),控制部分包含运动学逆解与路径规划。
opencv是一个开源的计算机视觉代码库,提供简单易用的python、ruby、matlab等语言的接口,在1999年由Intel建立,现在由Willow Garage维护。可以完成很多复杂的任务,如图片读取、图像处理、目标识别等。不需要自己辛苦研究,就可以使用先进的识别算法。
值得注意的是opencv的坐标系,如下定义:
本项目需要实现一个智能家居系统,其功能是通过语音控制,实现物品的加热等功能。首先,通过小程序采集用户语音输入,然后将数据上传到腾讯云实现语音转文字;文字再通过自然语言处理得到词法分析结果,根据名词之间的关系以及动词来判断需要实现的动作,由云服务器下发到树莓派与物联网平台。树莓派获得任务指令后,拍摄照片获得物品之间的相互位置关系,然后指挥机械臂挪动物品到指定位置。物联网平台连接有若干LoRa设备,根据指令下发开启与关断的数据。
注意在语音转文字、词法分析上的实际处理流程为小程序将语音通过插件转换为文字,再把文字发送到云服务器,之后由云服务器发送到自然语言处理接口得到词法分析结果。为了简洁按数据的流向绘制出整体框图。
首先是开关量的接入。有两种接入方式,一种是通过继电器模块控制总电源的方式,和市场上的智能插座类似;第二种是使用舵机模拟人工的方式按开关。
传感器数据输出,接入温度传感器与水位传感器,并通过单片机读出即可。
在语音交互方案上,本项目采用小程序采集用户语音,然后由腾讯云转换为文字的方式。为简化开发流程,直接使用腾讯开源的面对面翻译小程序,它直接内置了语音转文字接口。修改源代码,使得翻译后文字上传到服务器,实现语音转文字功能。
// 本函数原本仅用于显示翻译文字(已经将语音转换为文字),增加wx.request向服务器发送该文字
translateText: function(item, index) {
let lfrom = item.lfrom || 'zh_CN';
let lto = item.lto || 'en_US';
wx.request({
url: "https://***.stackoverflow.***:8008/miniprogram",
data: { "wd": item.text },
fail: (res)=>{
wx.showModal({
title: '发送失败',
content: ' ',
})
this.setData({
bottomButtonDisabled: false,
recording: false,
});
},
success: (res)=>{
let tmpDialogList = this.data.dialogList.slice(0);
this.setData({
dialogList: tmpDialogList,
bottomButtonDisabled: false,
recording: false,
});
let tmpTranslate = Object.assign({}, item, {
autoPlay: false, // 自动播放背景音乐
translateText: res.data.status,
translateVoicePath: "",
translateVoiceExpiredTime: 0
})
tmpDialogList[index] = tmpTranslate
this.scrollToNew();
}
})
词法分析的主要功能是
1、智能分词:将连续的自然语言文本,切分成具有语义合理性和完整性的词汇序列;
2、词性标注:为每一个词附上对应的词性,例如名词、代词、形容词、动词等;
3、命名实体识别:快速识别文本中的实体,例如人名、地名、机构名等。
这些功能可以让我们准确识别说话人意图。注意与早些年固定语句的语音识别,使用词法分析处理自然语言,而不是一经设定就不可更改的语音指令。可以在API Explorer上快速探索词法分析。
针对自然语言把酸奶放到水壶上, 词法分析的结果如下所示:
"PosTokens": [
{
"BeginOffset": 0,
"Word": "把",
"Length": 1,
"Pos": "p"
},
{
"BeginOffset": 1,
"Word": "酸奶",
"Length": 2,
"Pos": "n"
},
{
"BeginOffset": 3,
"Word": "放到",
"Length": 2,
"Pos": "v"
},
{
"BeginOffset": 5,
"Word": "水壶",
"Length": 2,
"Pos": "n"
},
{
"BeginOffset": 7,
"Word": "上",
"Length": 1,
"Pos": "f"
}
],
这样我们就知晓说话人谈到了几个物品,对物品的动作是什么。
借鉴自动售货机的内部结构,购买旋转弹簧、步进电机、驱动模块,从而实现一个将物品从储存仓拿出放到加热设备的机械结构。
使用该机械结构的主要目的就是执行更多的功能,从而解放双手,尽力做到无需人工介入的真实物理场景的自动化。
本项目中,采用MeARM开源微型机械臂。在机械结构上,廉价的MeARM零件一般由亚克力或者木板经激光切割而成,具有一定的机械强度,末端可承载的最大负重约为100克左右。
下图为MeARM的原理示意图:
下图为木质机械臂实物图:
电气结构部分,使用四个SG90舵机,分别安装在末端爪、远臂、近臂、底座上。其中末端舵机控制机械爪的张开与闭合,远臂控制上下,近臂控制前后,底座控制方向。
控制部分,使用树莓派4配合一只USB摄像头完成机械臂的视觉识别、自主规划等功能。由于没有双目摄像头,所以需要提取准备好各物体的高度信息。摄像头从俯视图上提取各物体的位置,然后通过运动学逆解得到舵机的旋转角度,根据预存的物品高度信息调整末端高度,最终完成抓取。将物体从原来的位置挪动到指定位置需要做路径规划,但是此处为了简化,直接对目标位置进行运动学逆解并运动到目标位置。
运动学逆解的部分较为复杂,基本思想是通过一些列三角计算将舵机的角度与末端的位置联系起来。通过舵机角度计算末端位置成为运动学正解,通过预期的末端位置得到舵机应该旋转的角度成为运动学逆解。运动学逆解会存在多个解的情况,需要根据机械臂的姿态选择合适的解。在本项目中由于Upper Arm与Forearm之间的角度限制为0-180度,不存在多个解的情况。
下图为meArm的各部分定义与臂长的测量方式。
下图为在真实机械臂中的各臂长测量方式。
本项目采用了开源的meArm运动学逆解库,只需要测量各臂长并调整舵机角度即可。meArm运动学逆解库需要输入的末端位置由三个数构成,分别为底座旋转角度(度)、前后位置(毫米)、上下位置(毫米)。
2. 位置信息提取
提前拍摄好俯视图形式的物品图片,然后再从采集过来的图像中做匹配,可以返回目标物体所在的位置信息(摄像头的位置需要固定,并且需要量出整幅画面所对应的物理尺寸),经过换算后可知实际位置信息。
在图片获取上使用opencv的cap.read()
函数。将USB摄像头连接到树莓派,然后就可以获取到图片。
在目标识别中采用了opencv的模板匹配函数。首先拍摄整张图片,然后从图片中截取待识别的目标。在识别的时候,先从摄像头中读取十张图片做平均,用于减少噪声;再与模板进行匹配,返回模板在整张图片的位置。
def match_template(target_img, template_key, show=False):
# print(templates[template_key])
template = cv2.imread(templates[template_key])
theight, twidth = template.shape[:2]
#执行模板匹配,采用的匹配方式cv2.TM_SQDIFF_NORMED
result = cv2.matchTemplate(target_img,template,cv2.TM_SQDIFF_NORMED)
#归一化处理
cv2.normalize( result, result, 0, 1, cv2.NORM_MINMAX, -1 )
#寻找矩阵(一维数组当做向量,用Mat定义)中的最大值和最小值的匹配结果及其位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
# 返回左上角,模板宽,模板长
return min_loc, [twidth, theight]
计算两点之间的实际距离。
def distance(point1, point2, scale_base, baseplate_width, baseplate_height):
# 计算两点之间的像素距离,并换算为真实距离
# 其中 scale_base为底部托盘的[图像宽度、图像高度]
# baseplate_width, baseplate_height为底部托盘的真实宽度、真实高度
dx = (point1[0] - point2[0]) / scale_base[0] * baseplate_width
dy = (point1[1] - point2[1]) / scale_base[1] * baseplate_height
return math.sqrt(math.pow(dx, 2) + math.pow(dy, 2))
计算角度。由于底座中心的匹配较为困难,这里采用直接手工标注的方式。在拍摄好的照片中找出底座中心的图像坐标,作为参数放入代码中。同时作为参数的还有底部托盘的长与宽,适合抓取物品的高度。
# 根据三角形公式,计算角度
# 设底座中心(basepoint)为A点, 末端(gripper)为C点,待抓取的物品为B点, 那么a,b,c边随之确定
# cosA = (b^2 + c^2 - a^2)/(2*b*c)
# 下面的location1为gripper, location2为B点
a = distance(location1_center, location2_center, scale_base, baseplate_width, baseplate_height)
b = distance(location1_center, basepoint, scale_base, baseplate_width, baseplate_height)
c = distance(location2_center, basepoint, scale_base, baseplate_width, baseplate_height)
print("a,b,c=", a, b, c)
# 弧度
A = math.acos((b*b + c*c - a*a) / (2*b*c) )
print("A=", A)
# 角度
A = A / math.pi * 180
print("A in du=", A)
# c一定是正数,而A有可能是负角度
A = (location2[0] - basepoint[0]) / abs(location2[0] - basepoint[0]) * A
print("Final A=", A)
# c是gripper中心和待抓取物中心之间的距离,会偏大
# 实际使用发现使用gripper中心和待抓取物的 下端中点会比较好
# 下端中点指的是在opencv坐标系中y值较大的边的中点
short_c = distance([location2_center[0], location2_center[1] + scale2[1]/2], basepoint, scale_base, baseplate_width, baseplate_height)
3.获取命令
在python中每隔1秒向服务器发送心跳包,并获取下发的任务。如果有任务,就将物品移动到指定位置,然后返回原点。
在完成了语音识别、词法分析、物品搬移等部件之后,我们还需要一台云服务器将各个部件整合起来,并根据词法分析结果下发任务指令给树莓派与物联网平台。
本项目使用轻量的Flask作为应用服务器,用Caddy做代理服务器并提供https入口,以满足小程序的https连接要求。设置/arm
, /miniprogram
两个路由用于处理机械臂与小程序上传数据。收到小程序上传的自然语言指令后,送到词法分析接口并获取结果。鉴于目前较为简单的应用需求,如果结果中有两个名词,那么就会根据名词出现的先后顺序组合为机械臂指令,并下发给树莓派;如果只有一个名词,并且该名词为水壶,那么就判断动词是否为打开或者关闭,然后送到物联网平台接口。
注意小程序要求所有服务器都为https访问,并且域名备案&小程序添加信任域名。https访问可以使用Caddy做一层反向代理,Caddy是一款由go语言编写的轻量高效server.
完成了一台自动加热食材的家居系统,可以用语音交互控制设备,使其完成取物品、加热一系列动作,全过程除语音输入指令外无需人工介入。
使用3D打印降低机械手臂与机械手的成本,并增加机械臂的载重。机械手臂与机械手可以大大降低设备的接入门槛,并且只要是人类可操作的设备该机械结构就可以操作。借助于计算器视觉的已有成果,可以方便地用语音来完成各种家务。
感谢腾讯云提供的P-NUCLEO-LRWAN3开发套件, 本项目使用其制作了加热水壶部分;感谢opencv的开发者,本项目用其实现了物品识别、定位;感谢开源硬件meArm的开发者,本项目用其完成了物品搬移机构;感谢RorschachUK开源的meArmPi, 本项目使用了部分运动学逆解代码与舵机控制代码。
meArm机械臂运动学逆解 https://github.com/RorschachUK/meArmPi
面对面翻译小程序 https://github.com/Tencent/Face2FaceTranslator
Caddy https://caddyserver.com/
TencentOS tiny https://github.com/Tencent/TencentOS-tiny
OpenCV https://opencv.org/
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。