每次完成一個demo都需要記下小筆記,防止忘記,實驗如圖:
第一張圖中是紅綠相接的部分是通訊結果,$表示接受完整,這裏力傳感器的頻率爲100hz,通過定時器每10ms向socket發送數據(只能有一個定時器運行!!不然發送時間不準,有滯後),機器人的同步運行週期設爲了0.008s,最小控制週期是4ms,同步運行週期必須是其整數倍。
在下位機的start()函數裏創建兩個同步任務,一個用來讀取socket,一個用來更新機器人示教器上的UI界面
本次實驗以機器人爲客戶端,地址如圖,電腦爲服務端,監聽端口號1000
下位機代碼如下:
從start()開始,(同步運行任務好像有行數限制,所以儘量多用子函數,否則會報錯!!)
begin
userPage()
cls()
gotoxy(0,0)
put("Socket sensorRead測試程序:")
taskCreateSync "readSocket",0.008,bSupervisor,readSocket(nError,nNum_FX,nNum_FY,nNum_FZ,nNum_TX,nNum_TY,nNum_TZ)
taskCreateSync "UI",0.008,bSupervisor,UI(nNum_FX,nNum_FY,nNum_FZ,nNum_TX,nNum_TY,nNum_TZ)
end
readsocket()
begin
// This program gets the parts sent by the other robot.
// The parts arrive via a socket on a telegram with the format
// {ID=i,X=x.xxx,Y=y.yyy,RZ=r.rrr,L=l.llllll},
// where "{" is the initial character, "i" is the ID of the
// detected object, "x.xxx" is the value on X, "y.yyy" is the
// value on Y, "r.rrr" is the value on RZ, "l.llllll" is the
// latched encoder value, "," is the separator character and "}"
// is the end character. At the end, it sends the character "$"
// as confirmation of good reception.
// The format of the telegram is defined at the program
// sendToNextRobot at the Motion library.
//
// Input Param
// none :
//
// Output Param
// x_nID : ID of the detected object
// x_trObjectPos : Transformation of the detected object
// x_nEncLatchVal: Encoder latched value of the detected object
// x_nError :
// 0 = no error, one part detected.
// >1 = Number of parameters in error with in the
// telegram read. It wasn't possible to fully
// convert into a numerical value one of the
// parameter within the telegram.
//
//{X=x.xxx,Y=y.yyy,Z=z.zzz,Rx=rx.xxx,Ry=ry.yyy,RZ=rz.zzz}
//
//----------------------------------------------------------------
//
//Init Variables
x_nNum_FX = 0
x_nNum_FY = 0
x_nNum_FZ = 0
x_nNum_TX = 0
x_nNum_TY = 0
x_nNum_TZ = 0
x_nError=0
//
while true
// Looks for int Character
call waitCharOnSk("{")
//
// Looks for beginig of first value
call waitCharOnSk("=")
//
// Recover X value
call readValFromSk(",",x_nNum_FX,x_nError)
if x_nError>0
logMsg("(readSocket)>>"+sErrorCode[0])
endIf
//
// Looks for beginig of next value
call waitCharOnSk("=")
//
// Recover Y value
call readValFromSk(",",x_nNum_FY,x_nError)
if x_nError>0
logMsg("(readSocket)>>"+sErrorCode[1])
endIf
//
// Looks for beginig of next value
call waitCharOnSk("=")
//
// Recover Z value
call readValFromSk(",",x_nNum_FZ,x_nError)
if x_nError>0
logMsg("(readSocket)>>"+sErrorCode[2])
endIf
//
// Looks for beginig of next value
call waitCharOnSk("=")
//
//Recover Z value
call readValFromSk(",",x_nNum_TX,x_nError)
if x_nError>0
logMsg("(readSocket)>>"+sErrorCode[3])
endIf
//
// Looks for beginig of next value
call waitCharOnSk("=")
//
//Recover Z value
call readValFromSk(",",x_nNum_TY,x_nError)
if x_nError>0
logMsg("(readSocket)>>"+sErrorCode[4])
endIf
//
// Looks for beginig of next value
call waitCharOnSk("=")
//
//Recover Z value
call readValFromSk("}",x_nNum_TZ,x_nError)
if x_nError>0
logMsg("(readSocket)>>"+sErrorCode[5])
endIf
//
//
// Sends the character "$" as confirmation of good reception.
sioSet(skFromPc,asc("$",0))
delay(0)
endWhile
//
end
readvalFromSk()
begin
// This program reads character by character on the socket until
// it finds a separator character. All the characters founded before
// this separator character are transformed on an integer value.
// The socket must be a socket server with timeout=0
//
// Input Param
// x_sCharacter : Character to find
//
// Output Param
// x_nValue : Integer value read from the socket
// x_nError :
// 0 = No error
// +1 = Not possible to convert the string read into
// a numerical value, or the string doesn't have
// the right format.
//
//----------------------------------------------------------------
//
l_sStringRead=""
l_sCharRead=""
//
// Read character by character until finds specific character.
while l_sCharRead!=x_sCharacter
// Reads one character from socket
sioGet(skFromPc,l_nAsciiCode)
l_sCharRead=chr(l_nAsciiCode)
// If the character read is not the separator character, the
// character read will be added to the previous characters read.
if l_sCharRead!=x_sCharacter
l_sStringRead=l_sStringRead+l_sCharRead
endIf
endWhile
//
// Convert string to num
l_sStringRead=toNum(l_sStringRead,l_nValueRead,l_bResult)
// If convertion Ok, modify parameter.
if (l_sStringRead=="" and l_bResult==true)
x_nValue=l_nValueRead
else
x_nError=x_nError+1
endIf
//
end
waitCharonSk()
begin
// This program reads character by character on the socket until
// it finds a specific character. The socket must be a socket
// server with timeout=0
//
// Input Param
// x_sCharacter : Character to find
//
// Output Param
// none :
//
//----------------------------------------------------------------
//
l_sCharRead=""
//
// Read character by character until finds specific character
while l_sCharRead!=x_sCharacter
// Reads one character from socket
sioGet(skFromPc,l_nAsciiCode)
l_sCharRead=chr(l_nAsciiCode)
endWhile
//
end
UI()
begin
while true
call renew_ui(x_nNumFX,x_nNumFY,x_nNumFZ,x_nNumTX,x_nNumTY,x_nNumTZ)
delay(0)
endWhile
end
renew_ui()
begin
gotoxy(2,2)
put("FX:")
put(toString(".3",x_nNumFX))
//
gotoxy(2,3)
put("FY:")
put(toString(".3",x_nNumFY))
//
gotoxy(2,4)
put("FZ:")
put(toString(".3",x_nNumFZ))
//
gotoxy(2,5)
put("TX:")
put(toString(".3",x_nNumTX))
//
gotoxy(2,6)
put("TY:")
put(toString(".3",x_nNumTY))
//
gotoxy(2,7)
put("TZ:")
put(toString(".3",x_nNumTZ))
end
這裏就是用子函數 call renew_ui(x_nNumFX,x_nNumFY,x_nNumFZ,x_nNumTX,x_nNumTY,x_nNumTZ),不這麼弄會報錯!!!!
stop() 裏面不用寫任何東西
begin
end
上位機是由qt+vs2010寫的 主要用到dockwidget , Coin3D ,多線程,定時器,QWT繪圖,qsocket, Optoforce API,和staublisoap
1.docketwidget框架:
主要這上面的代碼:
https://blog.csdn.net/czyt1988/article/details/51209619
去掉中間窗口的代碼, setDockNestingEnabled(true)就可以互相嵌套了
QWidget* p = takeCentralWidget();
if (p)
delete p;
//允許嵌套dock
setDockNestingEnabled(true);
initDocks();
ui 界面拖QDockewidget
這裏控件都是動態創建的,所以自己寫了個initDocks()函數進行初始化
public:
//移除並隱藏所有dock
void removeAllDock();
//顯示dock窗口
void showDock(const QList<int>& index = QList<int>());
void initDocks(); //初始化界面
void initDock_Osg();
void initDock_Forcesensor();
void initDock_Coin3d();
void initDock_Output();
void initDock_Robot_soap_socket();
void initDock_Emulator();
void initDock_Example();
void initDock_sensorFXview();
void initDock_sensorFYview();
void initDock_sensorFZview();
void initDock_sensorTXview();
void initDock_sensorTYview();
void initDock_sensorTZview();
void initDock_Socket_sendsensordata();//socket通訊發送力信號給機器人
下次每新建一個dock都要來這初始化下
void zlc_robotplatform::initDocks()
{
initDock_Coin3d();
initDock_Emulator();
initDock_Example();
initDock_Osg();
initDock_Output();
initDock_Robot_soap_socket();
initDock_Forcesensor();
initDock_sensorFXview();
initDock_sensorFYview();
initDock_sensorFZview();
initDock_sensorTXview();
initDock_sensorTYview();
initDock_sensorTZview();
initDock_Socket_sendsensordata();
m_docks.append(ui.dockWidget_coin3d); //0 COIN3d視圖
m_docks.append(ui.dockWidget_osg); //1 osg視圖
m_docks.append(ui.dockWidget_emulator); //2虛擬模擬器視圖
m_docks.append(ui.dockWidget_robot_soap_socket);//3機器人通訊
m_docks.append(ui.dockWidget_forcesensor); //4 力傳感器通訊
m_docks.append(ui.dockWidget_output); //5 輸出欄
m_docks.append(ui.dockWidget_example); //6 示例
m_docks.append(ui.dockWidget_sensorviewFX); //7 sensorFX視圖
m_docks.append(ui.dockWidget_sensorviewFY); //8 sensorFY視圖
m_docks.append(ui.dockWidget_sensorviewFZ); //9 sensorFZ視圖
m_docks.append(ui.dockWidget_sensorviewTX); //10 sensorTX視圖
m_docks.append(ui.dockWidget_sensorviewTY); //11 sensorTY視圖
m_docks.append(ui.dockWidget_sensorviewTZ); //12 sensorTZ視圖
m_docks.append(ui.dockWidget_socket_send_forcesensor); //13 socket send forcedata to robot
removeAllDock();
addDockWidget(Qt::LeftDockWidgetArea, ui.dockWidget_forcesensor);
splitDockWidget(ui.dockWidget_forcesensor, ui.dockWidget_coin3d, Qt::Horizontal);
splitDockWidget(ui.dockWidget_coin3d, ui.dockWidget_emulator, Qt::Horizontal);
splitDockWidget(ui.dockWidget_coin3d, ui.dockWidget_output, Qt::Vertical);
tabifyDockWidget(ui.dockWidget_forcesensor, ui.dockWidget_example);
tabifyDockWidget(ui.dockWidget_emulator, ui.dockWidget_robot_soap_socket);
showDock(QList<int>() << 0 << 2 << 3<< 4 << 5 << 6 );
}
以fx視圖爲例:
1.首先ui裏拖一個dock,改名dockWidget_sensorviewFX,在頭文件裏建個函數
public:
void initDock_sensorFXview();
void zlc_robotplatform::initDocks()
{
initDock_sensorFXview();
m_docks.append(ui.dockWidget_sensorviewFZ); //9 sensorFZ視圖
}
- 初始化 dock 這裏可以給dock加滾輪 QScrollArea* scro_sensorFX,之前筆者想用Qcustom來繪圖的,但是發現開了4個以上界面會卡死(用的是多線程裏面emit信號,利用slot來更新ui界面,用定時器不會,但是定時器是要用在socket上,所以選擇qwt)!!!
void zlc_robotplatform::initDock_sensorFXview()
{
// QScrollArea* scro_sensorFX = new QScrollArea(ui.dockWidget_sensorviewFX); //這個滾動窗口在dockewidget_4上
// ui.dockWidget_sensorviewFX->setWidget(scro_sensorFX);
// sensor_custuomPlotFXview = new QCustomPlot(scro_sensorFX);
// scro_sensorFX->setWidget(sensor_custuomPlotFXview);
// sensor_custuomPlotFXview->setGeometry(0, 0, 500, 200);
// ui.dockWidget_sensorviewFX->setWindowTitle(tr("力傳感器FX 5s實時數據動態繪製"));
// sensor_GraphFX = sensor_custuomPlotFXview->addGraph();
// sensor_custuomPlotFXview->graph(0)->setPen(QPen(Qt::gray));
// sensor_custuomPlotFXview->yAxis->setLabel(tr("FX (N)"));
// sensor_custuomPlotFXview->xAxis->setLabel(tr("t (s)"));
// sensor_custuomPlotFXview->xAxis->setTickLabelType(QCPAxis::ltDateTime);
// sensor_custuomPlotFXview->xAxis->setDateTimeFormat("mm:ss");
// sensor_custuomPlotFXview->xAxis->setAutoTickStep(false);
// sensor_custuomPlotFXview->xAxis->setRange(0, 5);
// sensor_custuomPlotFXview->xAxis->setTickStep(1);
// sensor_custuomPlotFXview->replot();
QScrollArea* scro_sensorFX = new QScrollArea(ui.dockWidget_sensorviewFX); //這個滾動窗口在dockewidget_4上
ui.dockWidget_sensorviewFX->setWidget(scro_sensorFX);
qwtplotFX = new QwtPlot(scro_sensorFX);
scro_sensorFX->setWidget(qwtplotFX);
qwtplotFX->setGeometry(0, 0, 500, 200);
//初始化xdata,x對應長度爲5的座標,y初始全爲0
for (int i = 0; i < 500; i++)
{
num_data.append(i);
sensor_FX_data.append(0);
}
//qwtplotFX->setTitle("The force of X");
qwtplotFX->setCanvasBackground(Qt::white);//背景
qwtcurve_FX = new QwtPlotCurve();
qwtcurve_FX->setPen(Qt::gray, 1); //曲線的顏色 寬度;
//設置刻度
qwtplotFX->setAxisScale(QwtPlot::yLeft, -1, 1, 1); //設置刻度範圍-2到2,間隔是1
qwtplotFX->setAxisScale(QwtPlot::xBottom, 0, 500, 100);
//設置網格
QwtPlotGrid *grid = new QwtPlotGrid();
//grid->enableX(true);//設置網格線
grid->enableY(true);
grid->setMajorPen(Qt::black, 0, Qt::DotLine);
grid->attach(qwtplotFX);
qwtcurve_FX->setSamples(num_data, sensor_FX_data);
qwtcurve_FX->attach(qwtplotFX);
qwtplotFX->setAxisTitle(QwtPlot::yLeft, QStringLiteral("FX (N)"));
//qwtplotFX->setAxisTitle(QwtPlot::xBottom, QStringLiteral("500組實時數據"));
qwtplotFX->setTitle(tr("力傳感器FX實時數據"));
//qwtplotFX->plotLayout();
qwtplotFX->replot();
}
因爲我默認佈局窗口是這些showDock(QList() << 0 << 2 << 3<< 4 << 5 << 6 );
而 m_docks.append(ui.dockWidget_sensorviewFX); //7 sensorFX視圖,所以需要加個按鈕來顯示
添加槽函數
public slots:
void on_action_Fxviewer();
connect一下
connect(ui.action_Fxviewer,SIGNAL(triggered()),this,SLOT(on_action_Fxviewer()));
槽函數內容如下:
void zlc_robotplatform::on_action_Fxviewer()
{
ui.dockWidget_sensorviewFX->hide();
ui.dockWidget_sensorviewFX->setFloating(true);
ui.dockWidget_sensorviewFX->show();
}
如圖:帶滾輪的dock就出來了
2.多線程動態繪圖
還是以繪製Fx爲例
多線程抄誰的代碼忘記錄了。。。反正這麼寫可以安全使用該線程
signals: void myplotThread_Signal(); 是發射信號,用來更新UI
//myplotthread
class myplotThread : public QThread
{
Q_OBJECT
public:
myplotThread(QObject *parent = 0);
void run();
void stop();
bool m_isExist; //控制線程退出;
QMutex m_mutex;
signals:
void myplotThread_Signal();
};
//plotthread
myplotThread::myplotThread(QObject *parent)
:QThread(parent),
m_isExist(false)
{
}
void myplotThread::run()
{
while (true)
{
m_mutex.lock();
if (m_isExist)
break;
m_mutex.unlock();
emit myplotThread_Signal();
MySleep(10); //這裏是我自定義的函數
}
m_mutex.unlock();
}
void myplotThread::stop()
{
m_mutex.lock();
m_isExist = true;
m_mutex.unlock();
}
定義跟新ui的槽
public:
myplotThread* m_plotthread;
public slots:
void Plotthreadslot();
connect(m_plotthread, SIGNAL(myplotThread_Signal()), this, SLOT(Plotthreadslot()), Qt::QueuedConnection);
qwtplotFX->setAxisScale(QwtPlot::yLeft, minValueFX - 1, maxValueFX + 1);這裏就可以基本讓曲線在圖的中間位置而不是滿屏
void zlc_robotplatform::Plotthreadslot()
{
sensor_FX_data.erase(sensor_FX_data.begin());
sensor_FX_data.append(m_sensorthread->pack6D.Fx*0.1);
qwtcurve_FX->setSamples(num_data, sensor_FX_data);
qwtcurve_FX->attach(qwtplotFX);
double maxValueFX = *max_element(sensor_FX_data.begin(), sensor_FX_data.end());
double minValueFX = *min_element(sensor_FX_data.begin(), sensor_FX_data.end());
//qwtplotFX->setAxisAutoScale(QwtPlot::yLeft, true);
qwtplotFX->setAxisScale(QwtPlot::yLeft, minValueFX - 1, maxValueFX + 1);
qwtplotFX->replot();
}
3.qwt的安裝與使用
http://blog.sina.com.cn/s/blog_a6fb6cc90101gks5.html
這裏是已經編譯好的版本只需按下圖配置即可,親測可用vs2010+qt5.3.1
4.optoforce力傳感器API使用(windows32位)
下載鏈接:
反正這麼用沒問題,用以前的代碼FZ會出一個大的端口號(不知道是不是有bug)
//sensor thread
void MySleep(unsigned long p_uMillisecs)
{
Sleep(p_uMillisecs);
}
typedef unsigned long long mytime_t;
mytime_t Now()
{
LARGE_INTEGER frequency;
LARGE_INTEGER timeStamp;
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&timeStamp);
timeStamp.QuadPart *= 1000;
timeStamp.QuadPart /= frequency.QuadPart;
return (mytime_t)timeStamp.QuadPart;
}
mytime_t NowMicro()
{
LARGE_INTEGER frequency;
LARGE_INTEGER timeStamp;
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&timeStamp);
timeStamp.QuadPart *= 1000000;
timeStamp.QuadPart /= frequency.QuadPart;
return (unsigned long long)timeStamp.QuadPart;
}
mytime_t ElapsedTime(mytime_t p_tTime)
{
return Now() - p_tTime;
}
mytime_t ElapsedTimeMicro(mytime_t p_tTime)
{
return NowMicro() - p_tTime;
}
/*
* Set the config to the DAQ
* it is a blocking function; returns true, if the sending of
* configuration is succeeded otherwise it returns false
*/
bool SetConfig(OptoDAQ & p_optoDAQ, int p_iSpeed, int p_iFilter)
{
SensorConfig sensorConfig;
sensorConfig.setSpeed(p_iSpeed);
sensorConfig.setFilter(p_iFilter);
mytime_t tNow = Now();
bool bSuccess = false;
do {
bSuccess = p_optoDAQ.sendConfig(sensorConfig);
if (bSuccess) {
return true;
}
if (ElapsedTime(tNow) > 1000) {
// 1 sec timeout
return false;
}
MySleep(1);
} while (bSuccess == false);
return false;
}
/*
* Opens the desired port
* it returns true if port could be opened otherwise returns false
*/
bool OpenPort(OptoDAQ & p_optoDAQ, OptoPorts & p_Ports, int p_iIndex)
{
MySleep(2500); // We wait some ms to be sure about OptoPorts enumerated PortList
OPort * portList = p_Ports.listPorts(true);
int iLastSize = p_Ports.getLastSize();
if (p_iIndex >= iLastSize) {
// index overflow
return false;
}
bool bSuccess = p_optoDAQ.open(portList[p_iIndex]);
if (bSuccess) {
//ShowInformation(p_optoDAQ, portList[p_iIndex]);
}
return bSuccess;
}
mysensorThread::mysensorThread(QObject*parent)
:QThread(parent),
m_isExist(false),
writeflag(false),
SendDataflag(false)
{
}
void mysensorThread::run()
{
// Changeable values, feel free to play with them
int iPortIndex = 0; // The index of the port which will be opened
//mytime_t tRunningTime = 600 * 1000; // Total running time in milliseconds
int iSpeed = 100; // Speed in Hz
int iFilter = 15; // Filter in Hz
///////////////////
if (OpenPort(optoDaq, optoPorts, iPortIndex) == false) {
std::cout << "Could not open port" << std::endl;
emit sensorthreadfailedSignal();
return ;
}
bool bConfig = SetConfig(optoDaq, iSpeed, iFilter);
if (bConfig == false) {
std::cout << "Could not set config" << std::endl;
emit sensorthreadfailedSignal();
optoDaq.close();
return ;
}
//ReadPackage6D(optoDaq,pack6D);
int iSize = -1;
mytime_t tNow = Now();
QTextStream in(&file);
for (;;) {
m_mutex.lock();
if (m_isExist)
break;
m_mutex.unlock();
iSize = optoDaq.read6D(pack6D, false);
if (iSize < 0) {
break;
}
if (writeflag)
{
GetLocalTime(&sys);
in << sys.wHour<<":" << sys.wMinute << ":" << sys.wSecond << "." << sys.wMilliseconds << " " << pack6D.Fx*0.1 << " " << pack6D.Fy *0.1<< " " << pack6D.Fz *0.1<< " " << pack6D.Tx*0.001 << " " << pack6D.Ty*0.001 << " " << pack6D.Tz *0.001<< endl;
}
emit sensorthreadSignal();
emit sensor_fxviewerUpdateSignal();
emit sensor_fyviewerUpdateSignal();
emit sensor_fzviewerUpdateSignal();
emit sensor_txviewerUpdateSignal();
emit sensor_tyviewerUpdateSignal();
emit sensor_tzviewerUpdateSignal();
MySleep(10); //10ms
}
m_mutex.unlock();
optoDaq.close();
return ;
}
void mysensorThread::stop()
{
m_mutex.lock();
m_isExist = true;
m_mutex.unlock();
}
5. staublisoapAPI
. 以前是使用C#動態庫,發現不是那麼好用,並且不跨平臺,目前該API暫時用於反饋機器人狀態,更多功能還在探索
6.socket通訊
qtsocket網絡通訊非常好用,github上也有很多非常好的例子,抄的關鍵代碼如下:
//socket通訊區
public:
QTcpServer *tcpServer;//監聽套接字
QTcpSocket *tcpSocket;//通信套接字
//qtsocket通訊用的槽
private slots:
void socketReadData();
void socketDisconnected();
void sever_new_connect();
tcpServer = new QTcpServer;
connect(tcpServer, &QTcpServer::newConnection, this, &zlc_robotplatform::sever_new_connect); //qt4的寫法?
zlc_robotplatform::~zlc_robotplatform()
{
if (myviewer != NULL)
{
delete myviewer;
zlc_tx90->root->unref();
}
tcpServer->close();
tcpServer->deleteLater();
}
void zlc_robotplatform::socketReadData() //讀取傳過來的數據
{
QByteArray buffer;
buffer = tcpSocket->readAll();
if (!buffer.isEmpty())
{
QString str = tr(buffer);
Socket_Text_append(1, str);
}
}
void zlc_robotplatform::sever_new_connect()
{
tcpSocket = tcpServer->nextPendingConnection();
QObject::connect(tcpSocket, &QTcpSocket::readyRead, this, &zlc_robotplatform::socketReadData);
QObject::connect(tcpSocket, &QTcpSocket::disconnected, this, &zlc_robotplatform::socketDisconnected);
Socket_Text_append(0, "server connect");
PushButton_socket_sendforcedata->setEnabled(true);
PushButton_socket_sendforcedata_ontime->setEnabled(true);
}
void zlc_robotplatform::socketDisconnected()
{
}
void zlc_robotplatform::on_PushButton_socket_sendforcedata_lisen_clicked()
{
if (PushButton_socket_sendforcedata_lisen->text() == tr("監聽"))
{
int port = 1000;
if (!tcpServer->listen(QHostAddress::Any, port))
{
ui.statusBar->showMessage(tr("socket連接失敗"), 1000);
//return;
}
PushButton_socket_sendforcedata_lisen->setText(tr("取消監聽"));
ui.statusBar->showMessage(tr("listening..."), 1000);
return;
}
else
{
if (tcpSocket->ConnectedState) //如果tcp是連上的
{
tcpServer->close();
PushButton_socket_sendforcedata_lisen->setText(tr("監聽"));
Socket_Text_append(1, "server_disconnect");
socket_senddatatimer->stop();
PushButton_socket_sendforcedata->setEnabled(false);
PushButton_socket_sendforcedata_ontime->setEnabled(false);
return;
}
tcpSocket->disconnectFromHost();
tcpServer->close();
PushButton_socket_sendforcedata_lisen->setText(tr("監聽"));
Socket_Text_append(1, "server_disconnect");
PushButton_socket_sendforcedata->setEnabled(false);
PushButton_socket_sendforcedata_ontime->setEnabled(false);
//qDebug() << "cancel listen sucessful!!";
ui.statusBar->showMessage(tr("disconnected"), 1000);
}
}
void zlc_robotplatform::on_PushButton_socket_sendforcedata_ontime_clicked()
{
if (PushButton_socket_sendforcedata_ontime->text()==tr("定時發送"))
{
//m_sensorthread->SendDataflag = true;
//sensortimer->stop(); //只能有一個定時器運行啊!不然送的數據不準!!
//this->killTimer(id_plot);//只能有一個定時器運行啊!不然送的數據不準!
socket_senddatatimer->start(10);////只能有一個定時器運行啊!不然送的數據不準!!
PushButton_socket_sendforcedata_ontime->setText(tr("取消定時"));
return;
}
if (PushButton_socket_sendforcedata_ontime->text() == tr("取消定時"))
{
socket_senddatatimer->stop();
PushButton_socket_sendforcedata_ontime->setText(tr("定時發送"));
return;
}
}
void zlc_robotplatform::on_PushButton_socket_sendforcedata_clear_clicked()
{
Socket_Text_append(1,"",true);
}
void zlc_robotplatform::on_PushButton_socket_sendforcedata_clicked()
{
QString value;
value = QString("{Fx=%1,Fy=%2,Fz=%3,Fx=%4,Fy=%5,Fz=%6}").arg(m_sensorthread->pack6D.Fx*0.1)
.arg(m_sensorthread->pack6D.Fy*0.1).arg(m_sensorthread->pack6D.Fz*0.1).arg(m_sensorthread->pack6D.Tx*0.001)
.arg(m_sensorthread->pack6D.Ty*0.001).arg(m_sensorthread->pack6D.Tz*0.001);
QByteArray block = value.toLatin1();
tcpSocket->write(block);
tcpSocket->flush();
Socket_Text_append(0, value);
}
7 coin3d在qt上的使用
qt上使用coin3D比在MFC上使用簡單的多!!!!關鍵代碼如下:
void zlc_robotplatform::initDock_Coin3d()
{
SoQt::init(""); //一定要放到最前面
zlc_tx90 = new TX90_robot;
QWidget * coin3Dwidget = new QWidget;
ui.dockWidget_coin3d->setWidget(coin3Dwidget);
zlc_tx90->makeScene();
myviewer = new SoQtExaminerViewer(coin3Dwidget);
myviewer->setSceneGraph(zlc_tx90->root);
myviewer->setBackgroundColor(SbColor(0.35, 0.35, 0.35));
myviewer->show();
myviewer->viewAll();
SoQt::show(coin3Dwidget);
}
zlc_robotplatform::~zlc_robotplatform()
{
if (myviewer != NULL)
{
delete myviewer;
zlc_tx90->root->unref();
}
tcpServer->close();
tcpServer->deleteLater();
}
8.vs2010+qt5.3.1中文的使用
網上說好像是要安裝vs2010補丁sp1,可以下載試下,我的是卡在office上,不知道安裝成功了沒,然後在頭文件加下面的命令即可使用中文:
// QT版本低於qt5
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
// VS版本低於VS2010
#if defined(_MSC_VER) && (_MSC_VER < 1600)
QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));
#else
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
#endif
#else
#if _MSC_VER >= 1600
#pragma execution_character_set("UTF-8")
#endif
#endif
// #if _MSC_VER >= 1600
// #define _MSC_STDINT_H_
// #endif
//上述代碼可解決中文問題
9.一個困擾蠻久常見的錯誤
vs2010+qt4編譯出現error LNK2001: 無法解析的外部符號 "public: virtual struct QMetaObject等錯誤
https://www.cnblogs.com/lovebay/p/9337528.htm
這個錯誤出現在我添加qcustom ,和添加帶Q_Object的類的時候
解決方法如下:右擊帶Q_Object的頭文件,自定義生成工具,添加如下:
命令行:
"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DSOQT_DLL -DCOIN_DLL -DSOWIN_DLL -DQWT_DLL "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-IC:\Eigen3" "-I$(QTDIR)\include\QWT" "-I$(NOINHERIT)\."
說明:
Moc%27ing zlc_robotplatform.h...
輸出:
.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
附加依賴項:
$(QTDIR)\bin\moc.exe;%(FullPath)
然後在GeneratedFiles中找到該文件,包含進項目中即可