使用 Qt for Android 获取并利用手机传感器数据(下篇)使用C++实现功能

news2024/9/21 18:34:03

在上一篇,我们搭建了开发环境。本篇,使用C++代码真正实现功能。我们使用UDP协议从手机上指定发送的目的地、端口。效果如下图,完整工程参考https://gitcode.net/coloreaglestdio/qtcpp_demo/-/tree/master/android/sensors2pc:

移动端1移动端2桌面
APP1App在这里插入图片描述

1. 在PC端实现程序并调试

我们建立一个Qt的Widgets程序,添加 position, sensors模块。
GUI

  • 界面里支持设置目的地址、端口。
  • 界面里可以设置GPS与各个传感器的刷新速度。
  • 传感器使用Qt枚举,并创建刷新函数。

传感器的主对话框类如下:

#ifndef DLGSTP_H
#define DLGSTP_H

#include <QDialog>
#include <QGeoPositionInfoSource>
#include <QStandardItemModel>
#include <QUdpSocket>
#include <QSensor>
#include <functional>
QT_BEGIN_NAMESPACE
namespace Ui { class DlgSTP; }
QT_END_NAMESPACE

class DlgSTP : public QDialog
{
	Q_OBJECT
public:
	DlgSTP(QWidget *parent = nullptr);
	~DlgSTP();
	void EnumSensors();
	void openGPS();
protected:
	void timerEvent(QTimerEvent * evt) override;
private:
	Ui::DlgSTP *ui;
	QStandardItemModel * m_pMsgMod = 0;
	int m_nTimer = -1;
protected:
	//Sensors Update Lambdas
	QList<std::function<void (void)> > m_sensorUpdaters;
protected:
	//GPS
	QGeoPositionInfoSource *m_pos_source = 0;
protected:
	//Net Send
	QUdpSocket * m_psock = 0;
	QStringList m_listInfo;
};
#endif // DLGSTP_H

//cpp

DlgSTP::DlgSTP(QWidget *parent)
	: QDialog(parent)
	, ui(new Ui::DlgSTP)
	, m_pMsgMod(new QStandardItemModel(this))
	, m_psock(new QUdpSocket(this))
{
	ui->setupUi(this);
	ui->listView_msg->setModel(m_pMsgMod);
	showMaximized();
	//Open GPS Device
	openGPS();
	//Enum all sensors
	EnumSensors();
	loadSettings();
	m_nTimer = startTimer(20);
}

1.1 枚举传感器并建立界面

通过Qt的Sensors可以枚举到传感器的取值。

void DlgSTP::EnumSensors()
{
	QList<QByteArray> sensors = QSensor::sensorTypes();
	QString strSensors = "Sensors:\n";
	for (QByteArray stp : sensors)
	{
		QSensor * sensor = new QSensor(stp);
		sensor->start();
		//添加界面刷新
		QListView * lstView = new QListView(this);
		QStandardItemModel * m_pMod = new QStandardItemModel(this);
		lstView->setModel(m_pMod);
		QString name = stp;
		ui->tabWidget->addTab(lstView,name);
		//设置刷新函数(供定时器调用),使用Lamdba后期调用,省的建立函数了。
		m_sensorUpdaters<<[sensor,m_pMod,this,lstView,name](void)->void
		{
			QSensorReading *reading = sensor->reading();
			QString str = "SENSOR="+name + ";\n";
			//获取当前传感器有多少数值
			int n = reading->valueCount();
			for (int i=0;i<n;++i)
			{
				QVariant vt = reading->value(i);
				str += QString("%1").arg(vt.toString());
			}
			//消息写入m_listInfo,后续发送
			m_listInfo << str;
			m_pMod->appendRow(new QStandardItem(str));
			lstView->scrollToBottom();
		};
	}
}

值得注意的是,上面的代码是在实际代码中进行了简化。实际代码里为了避免频繁刷新界面的同时,迅速吞吐传感器数据,进行了一些处理。可参考实际源码。

1.2 初始化GPS

GPS是手机的一个重要功能。通过初始化GPS,可以实时获取位置、时刻。

void DlgSTP::openGPS()
{
	m_pos_source = QGeoPositionInfoSource::createDefaultSource(0);
	if (m_pos_source)
	{
		//Add Tab
		QListView * lstView = new QListView(this);
		QStandardItemModel * m_pMod = new QStandardItemModel(this);
		lstView->setModel(m_pMod);
		ui->tabWidget->addTab(lstView,"GPS");
		//直接把GPS刷新信号绑定到Lambda
		connect (m_pos_source,
				 &QGeoPositionInfoSource::positionUpdated,
				 [lstView,m_pMod,this](const QGeoPositionInfo &update)->void
		{
			double lat = update.coordinate().latitude();
			double lon = update.coordinate().longitude();
			QDateTime dtm = update.timestamp();
			QString str = QString("SENSOR=GPS;\nGMT_TIME=%1;\nLAT=%2;\nLON=%3;\n")
					.arg(dtm.toString("yyyy-MM-dd HH:mm:ss"))
					.arg(lat,0,'f',7)
					.arg(lon,0,'f',7);
				//消息写入m_listInfo,后续发送
				m_listInfo << str;
			m_pMod->appendRow(new QStandardItem(str));
			lstView->scrollToBottom();
		});
		//即使出错了,也继续开始,把出错的信息绑定到Lambda
		connect (m_pos_source,
				 &QGeoPositionInfoSource::errorOccurred,
				 [this](QGeoPositionInfoSource::Error pe)->void{
			m_pos_source->startUpdates();
			m_pMsgMod->appendRow(new QStandardItem(QString("GPS Err Code %1.").arg(int(pe))));
		});
		//开启GPS
		m_pos_source->setUpdateInterval(ui->horizontalSlider_gps->value());
		m_pos_source->startUpdates();
	}
	else
		m_pMsgMod->appendRow(new QStandardItem("No GPS Found!"));
}

1.3 发送UDP

设置一个定时器,进行UDP发射。定时器的尺度是20ms的整数倍,可以调整。

void  DlgSTP::timerEvent(QTimerEvent * evt)
{
	if (evt->timerId()==m_nTimer)
	{
		++m_clk;
		//UDP Send
		const int updateITV = ui->horizontalSlider_freq->value();
		const int updateGUI = (50 / (updateITV>50?50:updateITV) )* updateITV;
		if (m_clk % updateITV ==0 )
		{
			//调用各个Lambda刷新传感器,消息写入m_listInfo
			foreach(auto fn, m_sensorUpdaters)
				fn();
			//发送
			QHostAddress addr (ui->lineEdit_ip->text());
			int port = ui->spinBox_port->value();
			foreach(QString i, m_listInfo)
				m_psock->writeDatagram(i.toLocal8Bit(),addr,port);
			m_nTotalSent += m_listInfo.size();
			m_listInfo.clear();
			//适时更新界面
			if (m_clk % updateGUI==0)
			{
				m_pMsgMod->appendRow(new QStandardItem(QString("%1>%2 items sent.")
													   .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
													   .arg(m_nTotalSent)));
				if (m_pMsgMod->rowCount()>MAX_ROWS_LSTV)
					m_pMsgMod->removeRows(0,m_pMsgMod->rowCount()-MAX_ROWS_LSTV);
				ui->listView_msg->scrollToBottom();
			}
		}
	}
}

我们在PC上可以先调试,发现PC上竟然也有很多传感器。
在这里插入图片描述

2 部署到Android 手机

我们在手机上打开调试模式,一般是连续击打系统版本号,即可打开。打开后,手机会提示允不允许USB调试,点击允许即可。

如果编译Debug版本,是不需要证书签名的。如果是Release,需要签名。

2.1 设置应用程序的名字和图标

在项目设置里,直接创建app的manifest

Add创建后,即可编辑名字、图标:
在这里插入图片描述

2.2 创建证书

在构建选项里,选择创建证书,输入必要信息后完成创建。注意,Release版本如果构建不成功,就要重新开启一下签名。为了安全,QtCreator会确保是你本人在烧写程序。

在这里插入图片描述创建后,选择“”包签名“”即可开启签名。注意,Release版本如果构建不成功,就要重新开启一下签名。为了安全,QtCreator会确保是你本人在烧写程序,会经常清除这个选项,以便您再次输入密码。

2.3 部署并运行程序

确保在Qt的编译栏选取了适当的设备(API版本一致),且绿色按钮出现(而非红色)

在这里插入图片描述

3 在PC上接收数据

当计算机、手机处于一个局域网,或者是处于IP可达的网络时,在PC端就可以接收到消息了。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/57795.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全志T3 ARM+Ethercat+Codesys工业控制器设计方案

目前codesys EtherCAT驱动 做运动控制很有优势。现在总线式运动控制基本都是这种配置。 Codesys 号称PLC界的安卓&#xff0c;国内造PLC的 基本都用Codesys内核了。 如&#xff1a;汇川 &#xff0c;合信&#xff0c; 和利时 &#xff0c;英威腾&#xff0c; 台达。 包…

原子范数初探:以到达角估计为例

到达方向&#xff08;Direction-of-arrival, DOA&#xff09;估计是指从形成传感器阵列的多个接收天线的输出中检索若干电磁波/源的方向信息的过程。DOA估计是阵列信号处理中的一个主要问题&#xff0c;在雷达、声纳、无线通信中有着广泛的应用。 基本数学模型 考虑KKK个窄带…

Java项目:ssm流浪猫狗救助管理系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 流浪猫狗救助管理系统。该项目分为前后台&#xff1b; 前台主要功能包括&#xff1a;会员的注册登陆,流浪猫狗知识&#xff0c;领养中心&#…

[附源码]计算机毕业设计JAVA学生实习管理系统

[附源码]计算机毕业设计JAVA学生实习管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybati…

80W美团架构师整理分享出了Spring5企业级开发实战文档

前言 都说程序员工资高、待遇好&#xff0c; 2022 金九银十到了&#xff0c;你的小目标是 30K、40K&#xff0c;还是 16薪的 20K&#xff1f;作为一名 Java 开发工程师&#xff0c;当能力可以满足公司业务需求时&#xff0c;拿到超预期的 Offer 并不算难。然而&#xff0c;提升…

U盘插入提示格式化才能使用,但里面有数据无法复制出来怎么解决?

U盘作为移动储存硬盘&#xff0c;避免不了出现各种问题&#xff0c;特别是莫名提示格式化&#xff0c;无法打开&#xff0c;要使用的话只能先将其格式化。 只要电脑还能正常识别出U盘&#xff0c;那都是有概率恢复出来数据的。先不要点“格式化”&#xff01; 如果一旦出现点…

4.JVM垃圾收集机制

1. 垃圾收集算法 1.1 分代收集理论 当前虚拟机的垃圾收集都采用分代收集算法&#xff0c;这种算法&#xff0c;没有什么新的思想&#xff0c;只是根据对象存活周期的不同将内存分成几块。一般将JAVA堆分为新生代、老年代&#xff0c;这样我们就可以根据各个年代的特点选择合适…

【注意力机制】Self-attention注意力机制理论知识

注意力机制目录输入输出类别&#xff08;N指向量个数&#xff09;&#xff1a;Self-attention引入self-attention架构self-attention怎么产生bbb例子&#xff1a;产生b1b^{1}b1例子&#xff1a;产生b2b^{2}b2self-attention 总结&#xff1a;Multi-head Self-attentionPosition…

使用 Learner Lab - 使用 API Gateway 与 Lambda 上传图片到 S3

使用 Learner Lab - 使用 API Gateway 与 Lambda 上传图片到 S3 AWS Academy Learner Lab 是提供一个帐号让学生可以自行使用 AWS 的服务&#xff0c;让学生可以在 100 USD的金额下&#xff0c;自行练习所要使用的 AWS 服务&#xff0c;如何进入 Learner Lab 请参考 使用 Lear…

【车载开发系列】UDS诊断---读取数据($0x22)

【车载开发系列】UDS诊断—读取数据&#xff08;$0x22&#xff09; UDS诊断---读取数据&#xff08;$0x22&#xff09;【车载开发系列】UDS诊断---读取数据&#xff08;$0x22&#xff09;一.概念定义二.报文格式1&#xff09;请求2&#xff09;肯定响应3&#xff09;否定响应三…

Vue中$nextTick实现源码解析

这篇文章主要为大家介绍了Vue中$nextTick实现源码解析&#xff0c;有需要的朋友可以借鉴参考下&#xff01; 先看一个简单的问题 {{ text }} 此时打印的结果是什么呢&#xff1f;是 old。如果想让它打印 new&#xff0c;使用 nextTick 稍加改造就可以 this.$nextTick(() >…

【计组笔记】06_指令系统

5.1 指令系统概述及指令格式 1. 指令的基本概念 2. 指令的分类 根据计算机层次结构分类 根据指令中地址码字段的个数分类 根据指令中操作数的物理位置分类 根据指令的功能分类 3. 指令格式 4. 指令的再认识 5. 指令格式举例 5.2 寻址方式及指令寻址 1. 寻址方式的概念 2.…

[论文阅读] 颜色迁移-Correlated Color Space

[论文阅读] 颜色迁移-Correlated Color Space 文章: Color transfer in correlated color space, [paper], [matlab code], [opencv code] 1-算法原理 本文算法比较简单, 其原理是把原始图像本身的空间分布进行归一化, 然后通过旋转平移缩放等变换, 变换到目标图像的空间分布…

WMS手动配货和自动配货的区别

手动配货 不知道配货流程的朋友可以看一下前面的文章链接: 深入浅出WMS之出库流程里面有对出库的解释说明&#xff0c;其中也有对配货的解释。前端页面也可以在前面的那篇文章中看到&#xff0c;这里我们来说一下后端部分。 查 手动配货是选中出库单的某条数据&#xff0c;然…

一文教你从Linux内核角度探秘JDK NIO文件读写本质(上)

1. 前言 在深入讲解Netty那些事儿之从内核角度看IO模型一文中曾对 Socket 文件在内核中的相关数据结构为大家做了详尽的阐述。 Socket内核结构.png 又在此基础之上介绍了针对 socket 文件的相关操作及其对应在内核中的处理流程&#xff1a; 系统IO调用结构.png 并与 epoll 的…

由阿里三位专家撰写:数据库高效优化:架构、规范SQL技巧文档

引言 学习是一种基础性的能力。然而&#xff0c;“吾生也有涯&#xff0c;而知也无涯。”&#xff0c;如果学习不注意方法&#xff0c;则会“以有涯随无涯&#xff0c;殆矣”。 学习就像吃饭睡觉一样&#xff0c;是人的一种本能&#xff0c;人人都有学习的能力。我们在刚出生…

[附源码]计算机毕业设计springboot作业管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

词袋模型(Bag-of-words model)

词袋模型词袋模型简介示例计算机视觉中的词袋模型词袋模型 简介 词袋模型&#xff08;Bag-of-words model&#xff09;是用于自然语言处理和信息检索中的一种简单的文档表示方法。通过这一模型&#xff0c;一篇文档可以通过统计所有单词的数目来表示&#xff0c;这种方法不考…

redis安装

版本号&#xff1a;redis-6.2.1 下载redis-6.2.1.tar.gz放/opt目录 解压命令&#xff1a;tar -zxvf redis-6.2.1.tar.gz 解压完成后进入目录&#xff1a;cd redis-6.2.1 在redis-6.2.1目录下执行make命令 出现make test 执行make install 查看redis默认安装路径&#xff1a;/u…

二、CANdelaStudio入门-版本介绍

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio的各个版本,欢迎各位朋友订阅、评论,可以…