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