本文主要通过mfc建立一个对话框,新建个子线程读取传感器数据,在主线程中添加定时器和chartctrl控件进行动态曲线的绘制。运行效果与传感器自带软件效果如下:
1 使用控制台程序新建传感器接口的配置和数据的读写如下:
将OMD库放入根目录下
代码如下:
// ss.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <omd/opto.h>
#include <omd/sensorconfig.h>
#include <fstream>
#include<windows.h>
using namespace std;
int main(int argc, char *argv[])
{
OptoDAQ daq;
OptoPorts ports;
OPort* portlist=ports.listPorts(true);
SensorConfig sensor;
sensor.set(sensor_ok,speed_100hz,filter_15hz,mode_raw);
daq.sendConfig(sensor);
if (ports.getLastSize()>0)
{
daq.open(portlist[0]);
while (1)
{
Sleep(1000/100);
if ((daq.getVersion()!=_95) && (daq.getVersion()!=_64)) // It is a 3D sensor
{
OptoPackage pack3D;
ofstream datafile;
datafile.open("datafile.txt",ofstream::app);
int size=daq.read(pack3D,0); // Reading Sensor #0 (up to 16 Sensors)
std::cout<<"x: "<<pack3D.x<<" y: "<<pack3D.y<<" z: "<<pack3D.z<<std::endl;
datafile << "datafile.txt" << pack3D.x << "" << pack3D.y << "" << pack3D.z << endl;
}
else // It is a 6D sensor
{
OptoPackage6D pack6D;
ofstream datafile;
datafile.open("datafile.txt",ofstream::app);
int size=daq.read6D(pack6D,false);
std::cout<<"Fx: "<<pack6D.Fx<<" Fy: "<<pack6D.Fy<<" Fz: "<<pack6D.Fz<<" ";
std::cout<<"Tx: "<<pack6D.Tx<<" Ty: "<<pack6D.Ty<<" Tz: "<<pack6D.Tz<<std::endl;
datafile << pack6D.Fx << " " <<pack6D.Fy << " " << pack6D.Fz << " " << pack6D.Tx << " " << pack6D.Ty << " " << pack6D.Tz << endl;
}
}
daq.close();
}
else
{
std::cout<<"No sensor available"<<std::endl;
}
char key;
std::cin>>key;
return 0;
}
Sleep(1000/100) 表示10ms运行一次,与采样频率100HZ相对应
运行效果如下:
其中fx fy fz需要除以10,单位为N TXTYTZ需要除以1000, 单位为N/m
2. MFC对话框读取数据
如图,新建一个对话框,仿照上述控制台程序进行传感器的相关配置
添加以下控件,传感器的数据将传入这些编辑框内
控件ID和变量类型和变量名称如下
在sensor_mutithreadDlg.h下定义一个线程变量
在sensor_mutithreadDlg.cpp下定义一个结构体,线程函数,一个该结构体的全局变量和该主线程中的全局变量
该结构体放子线程里的变量,其中,结构体中的Csensor_mutithreadDlg* dlg 将对应主线程中的Csensor_mutithreadDlg* Pdlg;在oninitDialog()中对pdlg初始化。
双击start按钮,将子线程结构体里的dlg与主线程对话框的pdlg进行绑定
线程函数代码如下:
UINT ThreadFunc(LPVOID lpParam)
{
threadinfo* pinfo = (threadinfo*)lpParam;
pinfo->mysensor.set(sensor_ok,speed_100hz,filter_15hz,mode_raw);
pinfo->daq.sendConfig(pinfo->mysensor);
while(1)
{
Sleep(1000/100);
pinfo->portlist = pinfo->ports.listPorts(true);
pinfo->daq.open(pinfo->portlist[0]);
if (pinfo->ports.getLastSize()>0)
{
int size=pinfo->daq.read6D(pinfo->pack6D,false);
//这个无效,因为被后面Pdlg->GetDlgItem(IDC_EDIT_FX)->SetWindowTextW(editfx)覆盖掉
Pdlg->m_fx = pinfo->pack6D.Fx/10;
Pdlg->m_fy = pinfo->pack6D.Fy/10;
Pdlg->m_fz = pinfo->pack6D.Fz/10;
Pdlg->m_tx = pinfo->pack6D.Tx/100;
Pdlg->m_ty = pinfo->pack6D.Ty/100;
Pdlg->m_tz = pinfo->pack6D.Tz/100;
//此处由于FZ的读取有时非常大,原因不明,自动过滤掉
if (pinfo->pack6D.Fz>10000)
continue;
CString editfx;
editfx.Format(_T("%.2f"),float(pinfo->pack6D.Fx)/10);
Pdlg->GetDlgItem(IDC_EDIT_FX)->SetWindowTextW(editfx);
CString editfy;
editfy.Format(_T("%.2f"),float(pinfo->pack6D.Fy)/10);
Pdlg->GetDlgItem(IDC_EDIT_FY)->SetWindowTextW(editfy);
CString editfz;
editfz.Format(_T("%.2f"),float(pinfo->pack6D.Fz)/10);
Pdlg->GetDlgItem(IDC_EDIT_FZ)->SetWindowTextW(editfz);
CString edittx;
edittx.Format(_T("%.3f"),float(pinfo->pack6D.Tx)/1000);
Pdlg->GetDlgItem(IDC_EDIT_TX)->SetWindowTextW(edittx);
CString editty;
editty.Format(_T("%.3f"),float(pinfo->pack6D.Ty)/1000);
Pdlg->GetDlgItem(IDC_EDIT_TY)->SetWindowTextW(editty);
CString edittz;
edittz.Format(_T("%.3f"),float(pinfo->pack6D.Tz)/1000);
Pdlg->GetDlgItem(IDC_EDIT_TZ)->SetWindowTextW(edittz);
ofstream datafile;
datafile.open("datafile.txt",ofstream::app);
datafile << float(pinfo->pack6D.Fx)/10 << " " <<float(pinfo->pack6D.Fy)/10 << " " << float(pinfo->pack6D.Fz)/10 << " " << float(pinfo->pack6D.Tx)/1000 << " " <<float(pinfo->pack6D.Ty)/1000 << " " << float(pinfo->pack6D.Tz)/1000 << endl;
}
}
return 0;
}
此处pdlg->updata(false)会导致崩溃,可采用这种方法上传
CString edittz;
edittz.Format(_T("%.3f"),float(pinfo->pack6D.Tz)/1000);
Pdlg->GetDlgItem(IDC_EDIT_TZ)->SetWindowTextW(edittz);
至此,该控件可实时读取数据。
3.实时动态绘图
需要下载chartctrl源文件放置根目录下,通过添加现有项导入至目录
导入后会出现Cchart相关类
在对话框中添加绘图所需的头文件和一些定义
#include "chartctrl/ChartCtrl.h"
#include "chartctrl/ChartTitle.h"
#include "chartctrl/ChartAxisLabel.h"
#include "chartctrl/ChartLineSerie.h"
#if defined _UNICODE ||defined UNICODE
typedef std::wstring TChartString;
typedef std::wstringstream TChartStringStream;
#else
typedef std::string TChartString;
typedef std::stringstream TChartStringStream;
#endif
放置6个custom control控件用来放置图像
对应修改相关值
在对话框头文件里添加如下变量和函数
将Cchartctrl变量与custom control控件绑定,若绑定失败,在.cpp上加“resource.h”
Setupmychart_FX()代码如下,其他依次类推:
void Csensor_mutithreadDlg::setupmychart_FX()
{
//初始化FX数组
for (int i = 0; i<500; i++)
{
FX[i] = 0;
NUM[i] = i;
}
//建立X轴
CChartAxis* Paxis = NULL;
Paxis = m_chartctrl_FX.CreateStandardAxis(CChartCtrl::BottomAxis);
Paxis->SetAutomatic(true);
Paxis = m_chartctrl_FX.CreateStandardAxis(CChartCtrl::LeftAxis);
Paxis->SetAutomatic(true);
//设置表的标题
TChartString str1;
str1 = _T("六维力传感器 FX数据采集");
m_chartctrl_FX.GetTitle()->AddString(str1);
str1 = _T("FX (N)");
Paxis = m_chartctrl_FX.GetLeftAxis();
m_chartctrl_FX.GetLeftAxis()->GetLabel()->SetText(str1);
str1 = _T("500组实时数据");
Paxis = m_chartctrl_FX.GetBottomAxis();
m_chartctrl_FX.GetBottomAxis()->GetLabel()->SetText(str1);
m_chartctrl_FX.EnableRefresh(false);
//创建线序列
CChartLineSerie *pLineSerie1;
m_chartctrl_FX.RemoveAllSeries();//先清空
pLineSerie1 = m_chartctrl_FX.CreateLineSerie();
//绘制图
pLineSerie1->AddPoints(NUM, FX,500);
m_chartctrl_FX.EnableRefresh(true);
}
在OnInitDialog()中完成初始化
动态左移数组的函数如下:
添加定时器,设置刷新频率与传感器的采样频率一致,从而可以使数组不断左移
在start设置频率,即10毫秒刷新一次,对应频率100HZ
定时器代码如下
void Csensor_mutithreadDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CDialogEx::OnTimer(nIDEvent);
switch(nIDEvent)
{
case 1:
UpdateData(TRUE);
m_chartctrl_FX.EnableRefresh(false);
m_chartctrl_FY.EnableRefresh(false);
m_chartctrl_FZ.EnableRefresh(false);
m_chartctrl_TX.EnableRefresh(false);
m_chartctrl_TY.EnableRefresh(false);
m_chartctrl_TZ.EnableRefresh(false);
if (m_fz>10000)
{
break;
}
leftmove(FX, 500, m_fx);
leftmove(FY, 500, m_fy);
leftmove(FZ, 500, m_fz);
leftmove(TX, 500, m_tx);
leftmove(TY, 500, m_ty);
leftmove(TZ, 500, m_tz);
CChartLineSerie *pLineSerie1;
CChartLineSerie *pLineSerie2;
CChartLineSerie *pLineSerie3;
CChartLineSerie *pLineSerie4;
CChartLineSerie *pLineSerie5;
CChartLineSerie *pLineSerie6;
m_chartctrl_FX.RemoveAllSeries();//先清空
pLineSerie1 = m_chartctrl_FX.CreateLineSerie();
pLineSerie1->AddPoints(NUM, FX,500);
m_chartctrl_FY.RemoveAllSeries();//先清空
pLineSerie2 = m_chartctrl_FY.CreateLineSerie();
pLineSerie2->AddPoints(NUM, FY,500);
m_chartctrl_FZ.RemoveAllSeries();//先清空
pLineSerie3 = m_chartctrl_FZ.CreateLineSerie();
pLineSerie3->AddPoints(NUM, FZ,500);
m_chartctrl_TX.RemoveAllSeries();//先清空
pLineSerie4 = m_chartctrl_TX.CreateLineSerie();
pLineSerie4->AddPoints(NUM, TX,500);
m_chartctrl_TY.RemoveAllSeries();//先清空
pLineSerie5 = m_chartctrl_TY.CreateLineSerie();
pLineSerie5->AddPoints(NUM, TY,500);
m_chartctrl_TZ.RemoveAllSeries();//先清空
pLineSerie6 = m_chartctrl_TZ.CreateLineSerie();
pLineSerie6->AddPoints(NUM, TZ,500);
m_chartctrl_FX.EnableRefresh(true);
m_chartctrl_FY.EnableRefresh(true);
m_chartctrl_FZ.EnableRefresh(true);
m_chartctrl_TX.EnableRefresh(true);
m_chartctrl_TY.EnableRefresh(true);
m_chartctrl_TZ.EnableRefresh(true);
break;
default:
break ;
}
CDialog::OnTimer(nIDEvent);
}
文中是因为FZ采样时有时候会出来一个很大的值,自行过滤
至此完成本程序设计。
参考链接
https://blog.csdn.net/czyt1988/article/details/8740500