A winch moves a small rectangular object up and down.
Small server is connected to a winch. It receives encoder data and sends it via TCP.
The packets are ASCII with delimiter ‘-’ … (so its: 01594-01592-01590-)
I tested with netcat and the data is realtime, in sync with motion and there are no lags.
Now I have an ofApp which does almost the same thing as netcat for now. It connects to remote server via TCP, reads encoder data and renders values on the screen. And here I have a huge lag. The winch have already stopped and for almost 20 seconds I still recover the packets.
The code is very simple for now (and probably that’s why it doesn’t work)
I suspect this is related to the frequency at which update() and draw() are called.
I would imagine that I need to use a different thread and read my TCP/encoder data from there.
Am I thinking right, or there is something else ?
Yes, it is the same. However maybe I was too quick to ask for help. After reading previous posts related to TCP, it turned out that recieve() function is not very fast. So now I use recieveRawBytes() trying to grab as much as possible at once and it looks like timing is good. At least there is no visible delay. I check how it actually tracks the moving object tomorrow.
Hi,
In case the delimiter is the problem (or to find out if it is), you can try:
string data = clientEnc.recieveRaw();
cout << data << endl;
while(data.length() > 0){ // We read something, so let's see if there's more
data = clientEnc.recieveRaw(); // If not: data.length() will return 0 and break the while loop
cout << data << endl;
}
Which is based on this, from ofxTCPClient.ht
//no terminating string you will need to be sure
//you are receiving all the data by using a loop
std::string receiveRaw();
No, delimiter is not a problem at all. It works fine splitting where it should. It’s just painfully slow, but probably due to high speed at which data arrives and only 60 cycles/second at which update/draw being called. I’m going to move it all to a separate thread.
recieveRaw gives strange result, so I abandoned it. The highest performance I get in current configuration (calling from update()) is using receiveRawBytes…
Alright, good to know.
And a for a continues (high speed) data-stream UDP seems like a good candidate.
I’m curious what will do the trick eventually, so good luck!
My suggestion:
a) Use a separate thread to read the TCP stream.
Whenever this thread, because it has detected a delimiter, knows the new position, write this position into a global variable.
b) The value assignment of the new position into the global variable must be protected. With a lock.
c) In the main thread, more precisely in the update function, activate the lock as long as the global variable is read.
This causes:
The TCP stream is read with maximum speed.
The update function sees the newest value. But not all values.
The lock is expensive for the operating system, but otherwise there is the danger that a half written value is already read in an inconsistent manner.
(To avoid the lock the global variable could be atomic.)
Moved to separate thread, which greatly improved everything. However there is a still a visible lag. (visible I mean projection lags behind the moving object).
So I modified both server and switched to UDP.
There is no change in lag, it’s the same as with TCP.
However data arrives smoothly and all congestions and buffering is gone, which is great.
But lag is still there…approximately 33-40ms.
And i know that UDP gets delivered with 2-3ms lag. So the rest happends in OF probably.
Maybe another way is to read UDP externally, but it still will be C++… so I don’t think it will perform any better, than OpenFrameworks…
If the app is running at 60 fps. That is 16ms of lag right there between update calls. If you are running the UDP code in a thread then you might have a few ms lag between the data coming into the thread and being able to read it in the main thread. So I think 20ms could just be the app update rate + locking and copying over to the main thread.
Most projectors have at least 16ms of latency, with 30-50 being more typical. If your projector has a Game Mode that could help reduce the latency. Any image processing ( like a smooth motion mode ) will add latency.
If you are sleeping in the threadedFunction() you might want to play around with how long you sleep for and maybe also try disabling vertical sync on the main app. ( ofSetVerticalSync(false); )
If you want to time the latency at the OF end. You could attempt to send a timestamp in the UDP data ( once both received and sending machines are synched to the same time ) and print out the time received vs the timestamp of the UDP packet in the threadedFunction() call.
“If the app is running at 60 fps. That is 16ms of lag right there between update calls. If you are running the UDP code in a thread then you might have a few ms lag between the data coming into the thread and being able to read it in the main thread. So I think 20ms could just be the app update rate + locking and copying over to the main thread.”*
Yes, I did moved it in a seprate thread. I write it into a “global” variable and then get the latest value from “update()” call at 60fps.
“Most projectors have at least 16ms of latency, with 30-50 being more typical. If your projector has a Game Mode that could help reduce the latency. Any image processing ( like a smooth motion mode ) will add latency.”
Wow. This I didn’t know! I have a relatively old, but high-end projector Sanyo PDH-DHT8000L (same a Christy DHD800). I just checked the manual and it has nothing about latency.
“3. If you are sleeping in the threadedFunction() you might want to play around with how long you sleep for and maybe also try disabling vertical sync on the main app. ( ofSetVerticalSync(false); )”
Actually I don’t sleep. I read UDP continously and as soon as I get something, I read it into a variable.
For vertical sync will try.
But looks like no matter what, I still will have a 40ms latency. So I think at this point it’s better for me to concentrate on how I can anticipate data to make lag invisible to spectators, rather than try to shave off couple milliseconds.
curiosity: how are you measuring the latency?
Not sure if it helps but maybe reducing MTU size on your network for smaller packets (usually it is 1500 bytes)
well, I couldn’t find the MTU settings on the router itself, but found on the ethernet card of mac. didn’t make any difference.
however it’s been determined, that UDP arrives in less than 3ms. What takes another 40 ms remains a big mystery. Looks like it’s no OF either, because even a simple output of “nc -uvlkw 0 8888” also shows a 30-40ms lag.
it’s not a projector either, because I checked on notebook screen.
how I measure it… well, it’s a bit complicated.
The goal of the project is to project images on moving surfaces. Surfaces are moving up and down, activated by computer-controlled winches. So it’s like a video mapping.
Winches send encoder data from their motors. It’s serial at 115200. I then convert these numbers to UDP and send it to OF. The lag is visual - the mapping is trailing behind the moving planes, especially when speed is high.
ps. I did check projector. It does have low-latency setting, but didn’t change anything…
It’s dmx controlled winch, so I wrote a server, which triggers it. But it can be triggered from DMX lighting console. It doesn’t matter… the idea was that OF would get encoder data and move the alpha masks, projecting images on the surfaces regardless on who and how activates and moves the winch.
I need to add that winches can operate at pretty high speed (up to 1.5m /s). So at this speed any lag will be visible. However even at quarter this speed (35cm/s) the image still trails behind.
That’s what I’m working on now and probably this is the only course of action.
Of course it’s not that simple, because when I measure the current speed to anticipate the position, there is also a lag. This becomes visible on acceleration (when winch starts) and when the winch is stopping. But I’m getting there little by little…