DuerOS 应用实战示例——机器狗DIY
【引子】我的专辑《DuerOS 的AI 实战》涵盖了DuerOS应用中较多方向的内容,有点有面,已经有39篇文字,本文是第40篇。四十不惑,如果读者目前还无法掌握DuerOS的应用全貌,或许这一篇文字能给大家提供帮助。
如果是一个硬件产品,如何能够通过语音与它交互呢? 马上出现在脑海里一个词——人工智能(AI)。实现一个具有人工智能的产品是不是太难了呢?幸运的是,拥有了DuerOS,这件事远没有你想象中的那么困难。当前,前提是这个产品有对外的通信接口,否则,就没有了与之交互的可能性。
为了展示DuerOS 的能力,本文以DIY 一个机器狗为例,描述如何让一只机器狗听懂你说的话, 并做出相应的动作。一只机器狗变成了真正听话的电子宠物,嗯, 这一定是一件挺开心的事。
别急,实际上需求或者目标的描述并没有那么清楚。如果我通过与手机或者智能音箱的语音交互, 远程控制机器狗,可以么?还是要给机器狗配上麦克风、扬声器,直接交互呢?不同的目标意味着不同的实现方案,也意味不同的设计权衡,前者的方式可以在《DuerOS 的AI 实战》中找到相关的指导性文字,这里是DIY,当然要展示从硬件到软件的全部过程。
整个实战是一个循序渐进的过程,不断返工才会极大地影响效率和心情,主要步骤如下:
选择一只机器狗,验证机器狗是否动作正常
为了简化流程,选择串口通信,实现电脑简单地控制机器狗
深入通信协议,丰富机器狗的动作
通过串口协议,小度音箱直接控制机器狗
通过DBP 平台创建bot,语音简单控制机器狗
丰富话术,完善机器狗的语音交互
等不及了, 正式开始——
1.机器狗的选择与验证
先要有一个硬件,然后再通过DuerOS 赋能,选择了一个创业团队的机器狗——Xgo(https://www.xgorobot.com/2021/08/15/XGOmini/)。
“勿在浮沙筑高塔”,硬件的验证非常重要,如果硬件自身出了问题,一切免谈。那么,如何验证Xgo是否工作正常呢?根据官网的说明,可以通过对应的手机App 完成功能的展示。 下载手机App,根据操作说明,采用蓝牙连接Xgo, 就可以实现一般的操控了,详见官网说明, 这里就不赘述了。
2.串口通信,电脑控制
为了简化开发的流程,这里选择了串口通信,目的是电脑通过串口通信来控制机器狗,为后面的语音控制奠定基础。
2.1 确定机器狗的串口端口
Xgo 是一个机器狗,那么串口端口在哪呢?需要拆机,到京东上买个内梅花螺丝刀(https://item.jd.com/4859309.html ),打开外壳,串口的端口就在主板上。
主板丝印中 PC6 是TX, PC7 是RX,右下G 为地线。
串口端口找到了, 杜邦线连接,而Mac 电脑是Type-c,如何连接呢?
2.2 Mac 电脑与Xgo 的串口连接
一时没有找到 串口到Type-c 的适配器,只得先将串口转成USB(
https://ic-item.jd.com/10028368158142.html),再将USB转成Type-C(
https://item.jd.com/100009644462.html),为了调试方便,还使用的UBB 延长线(https://item.jd.com/4721781.html), 最后的物理连接如下:
需要注意的是, 一定要地线对接,否则TTL 电平无法正常工作。
大家经常谈到面向测试的设计或者面向接口的设计,在硬件领域更是如此,每个环节和步骤都需要验证的。
如何验证串口是否正常呢?
登录苹果的AppStore,有很多串口调试工具,找一个免费的即可,这里选择了“串口调试助手”。安装完成后,线路连接好,打开串口,测试是否正常响应。
如果响应正常,表明串口链路是正常的,接下来才是如何在Mac 电脑上控制机器狗。
2.3 串口驱动 与 API 控制
安装串口驱动,下载 http://www.prolific.com.tw/US/ShowProduct.aspx?p_id=229&pcid=41 ,然后安装。Mac上可没有windows平台的Com1 和Com2,那么驱动安装成功后,可编程的COM口是哪一个呢?
的 dev 目录下 检查一下所有的tty, 初步就可以判断当前的com端口是 tty.usbserial-A50285BI。
Xgo 提供的编程库有基于Python 的(https://github.com/Xgorobot/mini-pythonlib),简单且友好。
写个简单的例子,3行代码,机器狗就可以原地踏步了。
import xgolib
xgomini = xgolib.XGO("/dev/tty.usbserial-A50285BI")#此处填写与机器狗相连接的端口
xgomini.mark_time(25)
这3行代码命名为test_mark.py, 执行python test_mark.py 即可看到效果。
如何才能执行更复杂的操控呢?
3.机器狗的串口协议
基于串口协议,可以实现不同的指令或者指令组合,进而实现机器狗的复杂一些的动作和控制。
知己知彼,百战不殆。机器狗Xgo 的串口协议位于 https://www.xgorobot.com/XgoWiki/wiki/1%20XGO-Mini%20Edu/%E4%BA%8C%E6%AC%A1%E5%BC%80%E5%8F%91/%E4%B8%B2%E5%8F%A3%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE/ 。阅读这个串口协议,共7种模式,共57条协议指令,库xgolib.py 中实现了20多条指令。
协议格式如下:
字头 | 长度(Length) | 指令类型 | 首地址 | 数据 | 校验和(CheckSum) | 字尾 |
以action 为例,实现趴下指令,初始值为"ACTION": [0x3E, 0], 指令趴下的参数的1,所以action 指令列表为 "ACTION": [0x3E, 1]调用_send方法组装串口协议, 写操作的模式是0x01,指令是0x3E,指令参数是0x01,协议payload的字头为 0x55 0x00 ,字尾是 0x00 0xAA,长度0x09,首地址代表0x01,校验和 0x09+0x01+0x3E+0x01 = 0x49, 低字节两位取反,得到0xA6最终发送的数据流为:
0x55 0x00 0x09 0x01 0x3E 0x01 0xA6 0x00 0xAA
Action 指令支持近20种动作, 已经在一定程度上满足了要求。
现在,已经可以通过电脑控制机器狗完成复杂的动作,那么,离语言控制机器狗还有多远呢?别急,饭还要一口一口的吃。
4. 小度直接控制机器狗
既然电脑可以控制机器狗, 再进一步,小度有屏音箱代替电脑完成与机器狗的连接,通过触摸屏是否可以同样控制机器狗呢?
在专辑《DuerOS 的AI 实战》的《一个安卓App,如何成为DuerOS 上的技能应用呢?》一文中,已经给出了具体的方法,只需写一个android 的应用即可,这个Android App 完成串口通信就实现了控制机器狗的目的。
4.1 小度设备与机器狗的物理连接
前提同样是硬件连接,找一台有屏音箱,同样把主板上的串口端口引出飞线来,结果像这样:
4.2 小度上的Android 应用
写个Android App 并不复杂, 与一般App 的区别在于这个App 要读写串口,因此要用到NDK 和JNI。
参考 https://github.com/cepr/android-serialport-api,开发过程如下:
在Android Studio中配置NDK, 选择 File | Settings | Appearance & Behavior | System Settings | Android SDK | SDK Tools ,选择CMake,NDK
创建测试工程 MySerial, File | New | New Project 选择Native C++
找到jni的文件夹中的 SerialPort.c和SerialPort.h文件复制到\app\src\main\cpp文件夹中
在Java下新建文件夹android_serialport_api,将SerialPort.java和SerialPortFinder.java 复制到该文件夹中,修改SerialPort.java中的最后一行代码:serial_port ---->> SerialPort
修改CMakeLists.txt里面的代码,对应改为SerialPort
编译一下工程,然后在MyApplication\app\build\intermediates\cmake\debug\obj\armeabi-v7a\libSerialPort.so目录下生成一个so文件,直接把这个so文件复制到libs目录下
至此 NDK 和JNI 开发完成,接下来,完成这个apk,通过按钮菜单来控制机器狗。
代码完成后,安装apk 到设备:
adb install -t -r /Users/caohongwei01/MySerial/app/build/outputs/apk/debug/app-debug.apk
在设备上启动apk:
adb shell am start com.abel.myserial/.MainActivity
启动logcat,查看输出日志, serial_port 代表了c 语言的输出日志, com.serial_port 代表了java 代码的输出日志。
显示连接和发送都成功了,但是机器狗没有动作,为什么呢?是串口连接的不对么?尝试连接 ttyS0,和ttyS1, 设备上的apk 都被系统强制终止了!
4.3 Android 应用的troubleshooting
没有什么事是一帆风顺的,debug 和 troubleshooting 无所不在。
需要逐一排查定位并解决问题,方法及过程如下:
1)mac 直连xgo, python 执行指令, 查看指令的内容,对比与我们java 串口通信的指令内容是否一致?
原地踏步的指令字节是 [85, 0, 9, 1, 60, 153, 32, 0, 170] , 与java 代码输出的字节流是一样的, 不是这个问题。
2)查看 android 设备,到底写了哪个串口,是否可以输出内容到Mac 上?
鉴于只有一个 usb到Type-C 的转接头,采用ADB 的wifi 连接,然后设备的飞线串口连接我的mac。
adb shell 进入设备后, 依次执行 echo hello2 > /dev/ttyS2, echo hello1 > /dev/ttyS1, echo hellohello > /dev/ttyS0, 确定飞线的串口为ttyS0,至此,小度设备可以通过串口输出数据了。
3)apk 是否能够通过串口将数据写到 Mac电脑?
检查apk 是否加载了 串口库:
adb shell
ps -ef 找到 apk 的pid 如 3406:
more /proc/3405/maps |grep libSerialPort.so
确认,apk 已经加载了串口库。
修改apk, 写『hello,xgo!』到串口, mac端仍以 『串口调试助手』接收。连接ttyS0, apk 被强制退出, 在 连接串口的时候 增加 catch (Exeception e), 并将tracestack 输出到日志。
通过 adb logcat |grep serial_port 看日志, 发现是 java.lang.SecurityException 异常,看代码,是设备不可读写。
串口本质上就是一个文件IO, 简化起见,直接修改/dev/ttyS0 的权限,
chmod 766 /dev/ttyS0
然后,再次安装测试,“串口调试助手“终于收到了Android App 发出的字符串“hello,xgo!“。
4)将小度设备的串口线与机器狗对接,为机器狗加电,重新安装并启apk, 连接ttyS0,然后发送『原地踏步』指令,机器狗终于按照预期动起来了。
至此,本阶段工作完成,核心是通过Android App的触摸按钮来触发动作, 建立通信链路环境来控制机器狗。
5. 小度语音控制机器狗
前面的准备工作已经完成, 可以通过语音来控制机器狗了,还是先从简单的动作开始,建一个bot 吧!
在此之前,为了提高机器狗的移动范围,让小度脱离电源插座,需要拆掉小度设备的外壳,把主板和扬声器粘绑在机器狗的背上,同时采用可充电的电池组为其供电,样子稍显古怪。
虽然这只小机器狗的负重没有问题,这还是限制了机器狗的滚动能力,当然,美中不足的事情还有很多。
5.1 支持语音交互的Bot 服务
在DBP 平台创建apk 技能:随身机器狗,得到bot-id:f5069014-39e4-1e4c-9642-65d23a11adf1,包名:com.dueros.xgo
在DBP平台,先创建两个意图(具体可以参考:
xgo_mark:原地踏步
xgo_stop: 停止运动
并适当补充常用的表达。
找一台云上的服务器,搭建bot服务,为了复用xgolib.py 的指令,这里同样使用Python 来搭建bot 服务。下载并安装Bot SDK 的python 版本:
git clone https://github.com/jokenwang/bot-sdk-python.git
然后 安装 python sdk 所需的依赖:
pip3 install pyOpenSSL
pip3 install requests
pip3 install pycryptodeme
进入bot-sdk-python:
python3 setup.py install
创建项目目录pybot4xgo, 创建HttpServer, ServerBot, XgoBot,至此,bot 端的创建基本完成,不断地丰富 XgoBot.py, 来支持更多的意图和指令即可。
5.2 构建一个新的APK,引入bot client sdk
参考4.2 的方式创建一个android NDK工程,包名:com.dueros.xgo。
在项目build.gradle中新增 maven库依赖:
maven{ url 'https://dueros.baidu.com/maven/repository/maven-releases/'}
在app/build.gradle加入依赖:
implementation 'com.alibaba:fastjson:1.1.71.android'
implementation 'com.baidu.duer.botsdk:bot-sdk-android:1.51.1'
混淆配置文件proguard_rules.pro 中添加:
-keep class com.baidu.duer.** {*;}
-keep class com.baidu.operationsdk.**{*;}
代码实现,复制 https://github.com/dueros/AndroidBotSdkDemo/tree/master/app/src/main/java/com/baidu/duer/test_botsdk 中的utils,和botsdk 代码到工程中,在mainactivity 中增加:
ContextUtil.setContext(this);
// 初始化BotSDK
// HeartBeatReporter.getInstance().setShouldUploadHeartBeatByApp(false);
BotSdk.getInstance().init(this);
BotSdk.getInstance().register(BotMessageListener.getInstance(), BotConstants.BOTID,
"1001", BotSDKUtils.sign("1001"), "1024", BotSDKUtils.sign("1024"));
// 打开BotSDK的Log开关,开发阶段建议打开Log开关,便于排查问题
BotSdk.enableLog(true);
onAttach(this);
实现 onAttach,onDetach,handleIntent,onClickLink 和 onHandleScreenNavigatorEvent, 修改相关代码,build apk。
5.3 联调,语音控制机器狗
首先,可以先不部署后台服务,由DuerOS 对已经设置的意图直接代理(参考DuerOS中的代理机制),测试步骤如下:
1)q= 打开技能调试模式
2)q= 打开随身机器狗
3)q= 原地踏步
4)q= 停止运动
至此,机器狗就实现了简单的原地踏步动作,证明语音控制链路没有问题。
然后,部署后台服务,由xgobot 完成对意图的处理,服务器启动:
nohup python3 HttpServer.py &
但是,语音操控, 机器狗没有动作,又到了troubleshooting 的环节。
检查小度设备:
adb logcat |tee log.txt|grep -iE --color "botsdk|receive directive"
发现 APK中的bot client sdk 没有收到Intent,只收到了原始query, 检查bot, 原来没有增加botappsdk 所属的directive,在xgobot 中增加 class handleIntent(baseDirective) 及其实现,并在launchRequest 中发送LaunchApp 的directive, 至此, 可以语音启动 App 并收到对应的intent 了,进而调用串口指令,操控机器狗运动了。
6. 面向自然语言交互的机器狗
为了简化开发流程,可以在 android 端实现各种机器狗串口通信的指令代码,然后,需要在DBP 配置对应于之指令的意图和各种常用表达,最后,在bot服务中完成对应的处理逻辑,下发handleIntent 指令。
随着指令和话术的丰富,就拥有了一只面向自然语音交互的机器狗。
7. 本文小结
文中展示了DuerOS 为硬件产品赋能的一个示例,使我们能够通过DuerOS的机制与机器狗实现对话,让机器狗听得懂人话,像个乖巧的电子宠物,为DuerOS 的应用提供了更多的可能性。
最后,在此感谢合作伙伴和开发者们对DuerOS 的关心和爱护,感谢大家为人们的生活带来了更多的便捷和快乐!
【关联阅读】——【DuerOS 的AI 实战】