c++ grab in position signal
Qthread send --->mdi xyz command---->wayting for reply
linuxcnc--->when end the previous mdi xyz command ---> send a reply to Qthread
Bear in mind that LinuxCNC won't execute the next MDI command until the previous MDI command is completed, and when the MDI command completes the system _will_ be at the requested position.
I think that your external code ought to hook into the HAL shared-memory region and watch HAL pins directly.
Please Log in or Create an account to join the conversation.
k-1 wrote:
Qthread send --->mdi xyz command---->wayting for reply
linuxcnc--->when end the previous mdi xyz command ---> send a reply to Qthread
Bear in mind that LinuxCNC won't execute the next MDI command until the previous MDI command is completed, and when the MDI command completes the system _will_ be at the requested position.
Yes this is what I told you right at the beginning, unless there is some special reason for it, you do not need to know the command has finished, if all you are going to do is send another command.
If you know several moves in advance, you can send all of them, one after another and there will be no delay between moves.
ArcEye wrote:
One command will not execute until the previous one completes, even directly using the MDI window of Axis.
If it does not complete, most likely there will be a following error and it will switch off anyway.
axis-remote hacks into Axis and does things without any user interaction, but does it the same way.
I still get the feeling there is something else involved you have not mentioned, like the opencv requiring to know it is in the commanded place for the next scan or whatever.
regards
Please Log in or Create an account to join the conversation.
I'm very curious of the results obtained using emcStatus on Qt ... if you want to suggest how to declare emcStatus in my .h file ... I would try.
EMC_STAT *emcStatus == 0L;
..
..
// try to connect to EMC status
if (emcStatusBuffer == 0)
{
emcStatusBuffer = new RCS_STAT_CHANNEL(emcFormat, "emcStatus", "xemc", emc_nmlfile);
if (!emcStatusBuffer->valid())
{
delete emcStatusBuffer;
emcStatusBuffer = 0;
emcStatus = 0;
retval = -1;
}
else
emcStatus = (EMC_STAT *) emcStatusBuffer->get_address();
}
}
But you are going to have to study the existing code to see how this fits in.
Look at src/emc/usr_intf/xemc.cc to see the full picture of how this pointer is obtained and used
regards
Please Log in or Create an account to join the conversation.
. Yes this is what I told you right at the beginning, unless there
is some special reason for it, you do not need to know the
command has finished, if all you are going to do is send
another command.
If you know several moves in advance, you can send all of
them, one after another and there will be no delay between
moves.
all right if the target object have static position ..... but my target is move .... then I need to send it position one by one ( in case of more than one target).
. Bear in mind that LinuxCNC won't execute the next MDI
command until the previous MDI command is completed, and
when the MDI command completes the system _will_ be at the
requested position.
yes it's right .... but in this case is opencv that send mdi command .... from a thread .... opencv " see" a lot of target ..... every target is possible to send MDI command ..... I have some row of code that choose the most convenient target than send the relative MDI command ..... if linuxcnc not send to my thread a feedback command .....when it send the next MDI command with position of next target? ..... opencv "see" but is not an decision maker.
tomorrow I test emcStatus "method" in thread ......
another idea is built an component that built an TCP connection, grab axis.....cmd and axis.....FD from hal file, compare they and at the right moment send a new MDI command ...... similar to ArkEye have suggested me some post ago.
Any suggestion are all wellcome.
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
Please Log in or Create an account to join the conversation.
I have written a TCP server in Qt5, which feeds moves in gcode to a TCP socket, that bit works OK.
I now have to look at encapsulating the C code of a component in such a way that it can be used inside a Qt userspace program containing the socket,
to preserve the signal/slot mechanisms that the QTcpSocket relies upon.
I have libraries that do similar things, but they are complete overkill for this and only private work in progress, not released in any way.
Will come back to you when I have something you can try to build on.
regards
Please Log in or Create an account to join the conversation.
I keep you posted and you me too ....bye and thank you!
Please Log in or Create an account to join the conversation.
I have encapsulated the necessary rtai processes to create a userspace component, into a Qt class that also contains a QTcpSocket.
A remote TcpServer is started and then linuxcnc is started, with the component loaded from the hal file.
Once the machine is switched on and Z axis homed it executes the commands it was sent, until finished.
The below video demonstrates the program in use.
The code is based roughly upon the same lines as the sample comp file I did earlier, so you have a reference point.
It will not do exactly what you want at present, but will give you a framework to build upon.
I will post a zip of all the code a bit later.
regards
Please Log in or Create an account to join the conversation.
This is the main .cpp file.
All the files are in the zip, including a config to test it with.
You will need to change the .pro files so that they point to where your rtai libs and includes are kept.
(you will require ALL headers from src/rtapi to be in the includes because they contain the defines of the types used)
I used Qt5, some of the Qt includes will be different if you are using an earlier version.
/*****************************************************************************
Specimen program to show the calls necessary to create a hal userspace
component, within a Qt5 class.
The component runs a QTcpSocket to receive commands from a remote
source and then executes them via axis-remote --mdi calls
(c) ArcEye 10/09/2014 <arceyeATmgwareDOTcoDOTuk>
Licence GPL
*******************************************************************************/
#include "tcpsocket.h"
#include <QHostAddress>
TcpSocket::TcpSocket(int argc, char** argv, QObject *parent) :
QObject(parent)
{
int r;
progress = 0;
socket = new QTcpSocket(this);
connect(socket, SIGNAL(readyRead()),this, SLOT(readyRead()));
qDebug() << "connecting to socket...";
socket->connectToHost(QHostAddress::LocalHost, 9999);
if(!socket->waitForConnected(5000))
qDebug() << "Error: " << socket->errorString();
// rt stuff
strcpy(prefix, "tcpsocket\0"); // used later in pins
comp_id = hal_init("tcpsocket");
if(comp_id < 0)
exit(-1);
if((r = connectPins()))
hal_exit(comp_id);
else
{
hal_ready(comp_id);
qDebug() << "Component registered and ready" << "comp_ID " << comp_id;
}
startTimer();
}
TcpSocket::~TcpSocket()
{
socket->close();
hal_exit(comp_id);
}
int TcpSocket::connectPins()
{
int r = 0;
int sz = sizeof(struct __comp_state) + 2; //fudge factor
inst = (struct __comp_state*)hal_malloc(sz);
memset(inst, 0, sz);
if( (r = hal_pin_bit_newf(HAL_IN, &(inst->homed), comp_id,"%s.homed", prefix)) != 0)
return -1;
*(inst->homed) = 0;
if( (r = hal_pin_bit_newf(HAL_IN, &(inst->machineon), comp_id,"%s.machineon", prefix)) != 0)
return -1;
*(inst->machineon) = 0;
if( (r = hal_pin_bit_newf(HAL_IN, &(inst->finished), comp_id,"%s.finished", prefix)) != 0)
return -1;
*(inst->finished) = 0;
return 0;
}
void TcpSocket::startTimer()
{
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(eventsLoop()));
timer->start(250);
}
void TcpSocket::eventsLoop()
{
char cmdline[80];
char line[80];
if(*(inst->homed) && *(inst->machineon))
{
switch(progress)
{
case 0:
if(*(inst->finished) && cmdList.size())
{
QStrncpy(line, cmdList[0], (cmdList[0]).size() );
sprintf(cmdline, "axis-remote --mdi '%s'", line);
system(cmdline);
cmdList.removeFirst();
progress = 1;
}
break;
case 1: if(!*(inst->finished))
break;
else
progress = 0;
default:
break;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This function is called by signal / slot mechanism and is outside the QTimer switched loop that checks pins and
// implements the commands fetched here
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void TcpSocket::readyRead()
{
QString str, str1;
qDebug() << "reading...";
if(socket->bytesAvailable())
{
str1 = socket->readLine();
if(str1.contains("NAK") )
{
qDebug() << "NAK received - Exiting";
socket->close();
//exit(0); don't exit in a component, with socket closed will not come back here again
}
else
{
// first connection send back ACK
if(!str1.contains("ACK"))
{
cmdList.append(str1);
}
qDebug() << "Received " << str1;
str = "ACK\n";
writeOut(str);
}
}
}
void TcpSocket::writeOut(QString& str)
{
socket->write(str.toLatin1());
socket->flush();
socket->waitForBytesWritten(3000);
}
////////////////////////////////////////////////////////////////
//
// helper to save problems translating QStrings to char*
void TcpSocket::QStrncpy(char* str, QString& qstr, int num)
{
int x;
for(x = 0; x < num; x++)
{
str[x] = (char)qstr.at(x).unicode();
}
str[x] = 0;
}
regards
Please Log in or Create an account to join the conversation.