最近需要测量水平倾角,就从网上找了个 DXL360 倾角仪。就是下面照片里这东西。
这东西说实话挺山寨的,我现在也没搞明白网上那么多品牌到底是谁山寨谁。反正就是买了几个,凑合用吧。
这东西提供了个 USB 接口,插在电脑上之后会虚拟出个Serial port。因此读取数据就是从串口中获取数据之后解析一下。没什么难度,代码放这里做个备忘,希望对大家也能有用。
DXL360 通过串口传来的数据格式为 X+0000Y+0000, 其中 “+” 可以为“+” 或 “-”。表示的是角度的正负号。
“0000” 是具体的数据,实际的角度值为这个数除以 100,单位为度。
DXL360 通电之后就发送数据,数据间隔大约为 0.5s。串口设置为 9600,N,8,1
下面是头文件。具体的用法请读注释。
#ifndef DXL360COMM_H
#define DXL360COMM_H
/// @file dxl360comm.h
/// @details DXL360 是一款双轴倾角仪,也可以叫做数显角度尺。DXL360Comm 是用来接收 DXL360 发送的数据的软件模块。
/// DXL360 本身无法与电脑直接相连,需要额外配置通讯模块,常见的通讯模块为蓝牙模块和 232 串口模块。
/// 蓝牙模块实际上也是模拟了电脑上的一个 232 串口,对于软件来说还是只需要读取串口的数据。
/// DXL360 通过串口传来的数据格式为 X+0000Y+0000, 其中 “+” 可以为“+” 或 “-”。表示的是角度的正负号。
/// “0000” 是具体的数据,实际的角度值为这个数除以 100,单位为度。
/// DXL360 通电之后就发送数据,数据间隔大约为 0.5s。串口设置为 9600,N,8,1
#include <QSerialPort>
#include <QPair>
#include <QDateTime>
/**
* @brief The DXL360Comm class
*/
class DXL360Comm: public QObject
{
Q_OBJECT
public:
DXL360Comm();
~DXL360Comm();
/**
* @brief value 获取倾角仪的数据
* @param x X 轴的角度
* @param y Y 轴的角度
* @return true 表示返回的值是在 1s 之内获得的数值。
* false 表示获得数值是更早时刻的,正常情况下 DXL360每隔 0.5s 返回一组数据。1s 之内都没有数据表明通讯出了问题。
*/
bool value(double &x, double &y);
public slots:
/**
* @brief setPortName 指定读取那个串口,格式类似:"COM1"、"COM2"
* @param name,串口号,取值可为:"COM1"、"COM2"、"COM3"、"COM4"...
*/
void setPortName(QString name);
/**
* @brief start 打开串口,开始收取数据
*/
bool start();
/**
* @brief stop 关闭串口,不再接收数据
*/
void stop();
signals:
/**
* @brief dataReady 每次收到一组数据时就会发出这个信号
* @param x
* @param y
*/
void dataReady(double x, double y);
private slots:
void on_readyRead();
private:
void stateMachine(char x);
QSerialPort m_port;
int m_state;
int m_count;
char m_bufferX[6];
char m_bufferY[6];
QDateTime m_time;
double m_x;
double m_y;
};
#endif // DXL360COMM_H
下面是 cpp 文件:
#include "dxl360comm.h"
DXL360Comm::DXL360Comm()
:m_state(0),
m_x(NAN),
m_y(NAN)
{
m_bufferX[5] = 0;
m_bufferY[5] = 0;
connect(&m_port, SIGNAL(readyRead()), this, SLOT(on_readyRead()));
}
void DXL360Comm::stop()
{
m_port.close();
}
void DXL360Comm::setPortName(QString name)
{
m_port.setPortName(name);
}
bool DXL360Comm::value(double &x, double &y)
{
x = m_x;
y = m_y;
QDateTime t = QDateTime::currentDateTime();
return (t.msecsTo(m_time) > -1000);
}
DXL360Comm::~DXL360Comm()
{
m_port.close();
disconnect(&m_port, SIGNAL(readyRead()), this, SLOT(on_readyRead()));
}
bool DXL360Comm::start()
{
m_port.setBaudRate(QSerialPort::Baud9600);
return m_port.open(QIODevice::ReadOnly);
}
void DXL360Comm::stateMachine(char x)
{
switch (m_state)
{
case 0:
if(x == 'X')
{
m_state = 'X';
m_count = 0;
}
break;
case 'X':
if(x == 'Y')
{
m_state = 'Y';
m_count = 0;
}
else if(m_count >= 5) //
{
m_state = 0; //到这里说明有问题了。
m_count = 0;
}
else
{
m_bufferX[m_count] = x;
m_count++;
}
break;
case 'Y':
m_bufferY[m_count] = x;
m_count++;
if(m_count == 5)
{
m_state = 0;
m_x = atoi(m_bufferX) / 100.0;
m_y = atoi(m_bufferY) / 100.0;
m_time = QDateTime::currentDateTime();
emit dataReady(m_x, m_y);
}
break;
default:
m_state = 0;
break;
}
}
void DXL360Comm::on_readyRead()
{
QByteArray data = m_port.readAll();
QByteArray::const_iterator it;
for (it = data.constBegin(); it != data.constEnd(); ++it)
{
stateMachine(*it);
}
}