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

硬件介绍

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

按照下图进行接线:

项目需求

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

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

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

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

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

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

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

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

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):

cpp 复制代码
void *write_serial(void *arg)
{
    char readbuf[32] = {'\0'};
    while(1){
        while(serialDataAvail (*((int *)arg))){
            serialGetstring (*((int *)arg),readbuf) ;

            if(strcmp(readbuf,"NEXT") == 0 ){
                printf("收到下一条视频指令\n");
            }else if(strcmp(readbuf,"PRE") == 0){
                printf("收到上一条视频指令\n");
            }else if(strcmp(readbuf,"ZAN") == 0){
                printf("收到点赞指令\n");
            }else if(strcmp(readbuf,"GUAN") == 0){
                printf("收到关闭指令\n");
            }else{
                printf("未知指令\n");
            }

            memset(readbuf,'\0',32);
        }
    }

    pthread_exit(NULL);
}

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

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

将手机接入香橙派

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

然后进行如下操作:

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

可见已经成功识别

2. 安装adb:

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

cpp 复制代码
sudo apt-get install adb

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

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

3. 设置手机权限

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

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

cpp 复制代码
cd /etc/udev/rules.d/
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 <按键事件的常量>
cpp 复制代码
adb shell input swipe 540 1300 540 500 500 //下滑
adb shell input swipe 540 500 540 1300 500 //上滑
adb shell "seq 3 | while read i;do input tap 350 1050 & input tap 350 1050 &sleep 0.01;done;" //点赞
adb shell input keyevent 26 //锁屏

最终代码的编写

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

serial_douyin.c:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include "mjm_uart_tool.h"

void *read_serial(void *arg)
{
	char *sendbuf;
	sendbuf = (char *)malloc(32*sizeof(char));

	while(1){
		memset(sendbuf,'\0',32*sizeof(char));
		fgets(sendbuf,sizeof(sendbuf),stdin);
		serialSendstring (*((int *)arg), sendbuf) ;
	}

	pthread_exit(NULL);

}


void *write_serial(void *arg)
{
	char readbuf[32] = {'\0'};
	while(1){
		while(serialDataAvail (*((int *)arg))){
			serialGetstring (*((int *)arg),readbuf) ;
			//printf("-> %s\n",readbuf);
			
			if(strcmp(readbuf,"NEXT") == 0 ){
				printf("收到下一条视频指令\n");
				system("adb shell input swipe 540 1300 540 500 500");
			}else if(strcmp(readbuf,"PRE") == 0){
				printf("收到上一条视频指令\n");
				system("adb shell input swipe 540 500 540 1300 500");
			}else if(strcmp(readbuf,"ZAN") == 0){
                printf("收到点赞指令\n");
				system("adb shell \"seq 3 | while read i;do input tap 350 1050 & input tap 350 1050 &sleep 0.01;done;\"");
            }else if(strcmp(readbuf,"GUAN") == 0){
                printf("收到关闭指令\n");
				system("adb shell input keyevent 26");
            }else{
				printf("未知指令\n");
			}

			memset(readbuf,'\0',32);
		}
	}

	pthread_exit(NULL);
}



int main ()
{
	int fd ;

	int ret;
	pthread_t read_thread;
	pthread_t write_thread;

	if ((fd = myserialOpen ("/dev/ttyS5", 115200)) < 0) //打开驱动文件,配置波特率
	{
		fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
		return 1 ;
	}

	/*	if (wiringPiSetup () == -1)
		{
		fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
		return 1 ;
		}*/

	ret = pthread_create(&read_thread,NULL,read_serial,(void *)&fd);
	if(ret != 0){
		printf("read_serial create error\n");
		return 1;
	}
	ret = pthread_create(&write_thread,NULL,write_serial,(void *)&fd);
	if(ret != 0){
		printf("write_serial create error\n");
		return 1;
	}

	pthread_join(read_thread,NULL);
	pthread_join(write_thread,NULL);

	return 0 ;
}

实现效果:

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

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

相关推荐
大树881 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠1 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质2 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5202 天前
Linux 11 动态监控指令top
linux
小宇宙Zz2 天前
Maven依赖冲突
java·服务器·maven
Inhand陈工2 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智2 天前
ARP代理--工作原理
运维·网络·arp·arp代理
不会C语言的男孩2 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
shushangyun_2 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化