1. 程式人生 > >windows下使用MFC對六維力感測器資料採集與繪製

windows下使用MFC對六維力感測器資料採集與繪製

本文主要通過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