• 基于香橙派和SU-03T 使用Linux实现语音控制刷抖音


    硬件介绍

    SU-03T之前在小车的时候使用过,详见:语音小车---6 + 最终整合_mjmmm的博客-CSDN博客

    按照下图进行接线:

    项目需求 

    通过语音指令来控制安卓手机刷抖音,可以实现视频切换和点赞等功能:

    1. 开机播报“你好,我是你的刷抖音助手

    1. 当说出“你好抖音助手"可以唤醒模块,模块回复“抖音助手在

    2. 当超过10s没有指令或说出“退下”时,模块会进入休眠模式,并回复“有需要再叫我

    3. 当说出“下一个视频”或“这个不好看”时,模块回复“切换至下一个视频”,并划到下一个视频

    4. 当说出“上一个视频”或“刚刚那个挺好看”时,模块回复“切换至上一个视频”,并划回上一个视频

    5. 当说出“点个赞”或“这个视频不错”时,模块回复“以为您点赞”,并点赞当前视频

    6. 当说出“不想看了”时,模块回复“以为您关闭屏幕”,并关闭手机屏幕

    SU-03T的设置和烧写

    设置和烧写的详细步骤也参考之前写的博文,此处只展示关键信息:

    1. 创建产品:

    2. 设置PIN脚为串口模式:

    对于SU-03T,串口的RX和TX分别对应B6和B7

    并设置相应的波特率

    3.  设置唤醒词:

    4.  设置指令语句:

    5. 设置控制详情:

    参数的设置就是行为的名字 -> 大写字母 -> 16进制ASCII码,已空格分开

     

    next -> 4E 45 58 54

    pre -> 50 52 45

    zan -> 5A 41 4E

    guan -> 47 55 41 4E

     6. 其他配置,如声音,开机播报,主动退出等,都是按喜好设置,这里不再详细展示:

     7. 下载SDK并烧写进入SU-03T

    详细步骤仍参考之前的博文:

    8. 测试:

    此时,可以打开串口助手来测试一下,分别说出对应的指令,看看SU-03T是否会向串口发送对应的字符:

    我分别说出了四条指令,可见串口输出正确!

    编写香橙派代码的框架

    SU-03T设置完成后,就可以将SU-03T接到香橙派并进行Linux部分的代码编写:

    由于在这个项目中,SU-03T只负责发送,香橙派只负责接收,所以除了电源外,只需要将SU-03T的TX(B7)接到香橙派的RX就可以,算上电源共三根线:

    新创建一个“douyin”文件夹,将语音刷抖音项目的代码放在这里面:

    然后将一些代码拷贝进来方便修改:

     重新编译一下,并说出4条控制语句:

    可见,SU-03T成功识别了指令,香橙派成功的接收了SU-03T通过串口打印的字符!

    现在,就需要修改serial_douyin.c中接收的代码,添加数据处理的部分

    先简单写一个数据处理的框架:

    serial_douyin.c -> void *write_serial(void *arg):

    1. void *write_serial(void *arg)
    2. {
    3. char readbuf[32] = {'\0'};
    4. while(1){
    5. while(serialDataAvail (*((int *)arg))){
    6. serialGetstring (*((int *)arg),readbuf) ;
    7. if(strcmp(readbuf,"NEXT") == 0 ){
    8. printf("收到下一条视频指令\n");
    9. }else if(strcmp(readbuf,"PRE") == 0){
    10. printf("收到上一条视频指令\n");
    11. }else if(strcmp(readbuf,"ZAN") == 0){
    12. printf("收到点赞指令\n");
    13. }else if(strcmp(readbuf,"GUAN") == 0){
    14. printf("收到关闭指令\n");
    15. }else{
    16. printf("未知指令\n");
    17. }
    18. memset(readbuf,'\0',32);
    19. }
    20. }
    21. pthread_exit(NULL);
    22. }

    然后再次编译运行,说出四句指令:

    可见,函数框架正确,接下来只需要将printf替换成真正的操作手机的代码就可以了 

    将手机接入香橙派

    将我破旧的小米5C再次拿出哈哈哈,然后通过 TYPE-C -- USB 连接到香橙派:

    然后进行如下操作:

    1.  香橙派输入dmesg指令查看手机接入情况:

    可见已经成功识别

    2.  安装adb:

    由于安卓手机的底层也是用Linux系统来操作的,所以可以通过香橙派来直接进入控制手机shell的界面,但需要先安装adb工具,adb是做安卓开发中常用的工具:

    sudo apt-get install adb

    安装完之后,执行”adb devices“指令:

    发现好像权限不太对,因此需要在安卓手机上设置权限

    3. 设置手机权限

    报错的本质原因是香橙派系统还不支持USB设备的热拔插UDEV的机制

    解决办法:在 /etc/udev/rules.d 文件夹下创建规则文件:

    1. cd /etc/udev/rules.d/
    2. sudo vim 51-android.rules

    然后在文件中添加内容:

    SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0666" 

     

    然后重新拔插手机!!

    现在再次执行”adb devices“指令:

    没有像刚刚那样报错了,但是仍然显示执行”adb devices“指令:限

    解决办法:打开手机,允许调试:

    此时,再再次执行”adb devices“指令:

    没有任何报错了,此时”adb shell“指令:

    连接成功!! 

    此时如果“ls”一下:

    可以看到很多文件没有权限,因为没有root 

    小插曲:什么是udev?

    • udev是一个设备管理工具,udev以守护进程的形式运行,通过侦听内核发出来的uevent来管理/dev目录下的设备文件。udev在用户空间运行,而不在内核空间 运行。它能够根据系统中的硬 件设备的状态动态更新设备文件,包括设备文件的创建,删除等。设备文件通常放在/dev目录下。使用udev后,在/dev目录下就只包含系统中真正存在的设备。

    4. 使用shell指令来模拟手滑屏幕

    现在可以成功的连入手机内部的系统,关键就在于对于滑动或点击屏幕的指令模拟了:

    • adb shell input swipe <起始x坐标> <起始y坐标> <结束x坐标> <结束y坐标> <滑动持续时间ms>
    • adb shell input keyevent <按键事件的常量>
    1. adb shell input swipe 540 1300 540 500 500 //下滑
    2. adb shell input swipe 540 500 540 1300 500 //上滑
    3. adb shell "seq 3 | while read i;do input tap 350 1050 & input tap 350 1050 &sleep 0.01;done;" //点赞
    4. adb shell input keyevent 26 //锁屏

    最终代码的编写

    现在有了基本的代码模型,和控制手机的具体指令,接下来的工作就是在数据处理的部分,执行adb指令了,显然,使用system函数就可以:

    serial_douyin.c:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include "mjm_uart_tool.h"
    16. void *read_serial(void *arg)
    17. {
    18. char *sendbuf;
    19. sendbuf = (char *)malloc(32*sizeof(char));
    20. while(1){
    21. memset(sendbuf,'\0',32*sizeof(char));
    22. fgets(sendbuf,sizeof(sendbuf),stdin);
    23. serialSendstring (*((int *)arg), sendbuf) ;
    24. }
    25. pthread_exit(NULL);
    26. }
    27. void *write_serial(void *arg)
    28. {
    29. char readbuf[32] = {'\0'};
    30. while(1){
    31. while(serialDataAvail (*((int *)arg))){
    32. serialGetstring (*((int *)arg),readbuf) ;
    33. //printf("-> %s\n",readbuf);
    34. if(strcmp(readbuf,"NEXT") == 0 ){
    35. printf("收到下一条视频指令\n");
    36. system("adb shell input swipe 540 1300 540 500 500");
    37. }else if(strcmp(readbuf,"PRE") == 0){
    38. printf("收到上一条视频指令\n");
    39. system("adb shell input swipe 540 500 540 1300 500");
    40. }else if(strcmp(readbuf,"ZAN") == 0){
    41. printf("收到点赞指令\n");
    42. system("adb shell \"seq 3 | while read i;do input tap 350 1050 & input tap 350 1050 &sleep 0.01;done;\"");
    43. }else if(strcmp(readbuf,"GUAN") == 0){
    44. printf("收到关闭指令\n");
    45. system("adb shell input keyevent 26");
    46. }else{
    47. printf("未知指令\n");
    48. }
    49. memset(readbuf,'\0',32);
    50. }
    51. }
    52. pthread_exit(NULL);
    53. }
    54. int main ()
    55. {
    56. int fd ;
    57. int ret;
    58. pthread_t read_thread;
    59. pthread_t write_thread;
    60. if ((fd = myserialOpen ("/dev/ttyS5", 115200)) < 0) //打开驱动文件,配置波特率
    61. {
    62. fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
    63. return 1 ;
    64. }
    65. /* if (wiringPiSetup () == -1)
    66. {
    67. fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
    68. return 1 ;
    69. }*/
    70. ret = pthread_create(&read_thread,NULL,read_serial,(void *)&fd);
    71. if(ret != 0){
    72. printf("read_serial create error\n");
    73. return 1;
    74. }
    75. ret = pthread_create(&write_thread,NULL,write_serial,(void *)&fd);
    76. if(ret != 0){
    77. printf("write_serial create error\n");
    78. return 1;
    79. }
    80. pthread_join(read_thread,NULL);
    81. pthread_join(write_thread,NULL);
    82. return 0 ;
    83. }

    实现效果: 

    和项目需求一致,可见,我的手并没有碰到手机屏幕,只是说出了对应的指令,手机就会有所反应:

    并且在香橙派终端也可以看到指令历史:

  • 相关阅读:
    Eureka服务注册与发现
    Linux内核之completion机制
    vue-7-vuex
    购物网站系统
    springmvc有哪几种请求参数的方式呢?
    中国各朝代行政区划、点位矢量数据下载与背景介绍
    想要好身材,你不得不看的高蛋白饮食计划
    lv11 嵌入式开发 ARM体系结构理论基础(寄存器)3
    Flume的简介
    强制用户使用定向推送功能是什么意思?整改措施请收好
  • 原文地址:https://blog.csdn.net/mjmmm/article/details/132927900