Serial Communication Running Slow in Unity - c#

I have connected IMU (Gyroscope&Acc&Magnetometer) to my Unity3D project and using serial communication via USB.
The problem is, when my script becomes little heavy with gaming codes, serial communication slows down - when values from IMU are supposed to change at certain point of time, they change after couple of seconds and as time goes, data stream cannot catch up with the game.
I am calling myPort.ReadLine() from Update function to read serial data from COM port.
What is the solution? - If I understand the problem right, I want the serial data reading not to be waiting to my app's next frame to receive new values.
May reducing Baud Rate of the IMU device work?

There are several things you can do for optimizing your project:
1) You can change the communication parameters. If you are sending pitch, yaw or roll, don't send them as string, instead use IEEE 754 format, send them as bytes. Also, if you are getting Quaternion values, do not loose time to convert them to Euler Angles.
2) Try to change your update rate in Unity from settings but be careful smaller update rate = slower unity frame rate.
3) Try to use high baud rate, such as 115200 or higher. If you reduce baud rate, your data from IMU can be corrupted.
4) In IMU code, you can toggle you serial port communication (you may not want to send all data continuously, you may send data shirkingly). I mean, you can downsample your data.
5) I don't know your data size but you can use Coroutines & Yield or Invoke. As you know, Unity does not allow us to use data received event but you can create your own event to understand if all of your data has been received.
(Also try discardInBuffer if you have problem with streaming)
6) You can write your own dll (c# dll does not make any bigger changes by the way so use C++). If you are using Windows, you can start searching with kernel32.Dll and ws2_32.dll.

So I figured the best solution for the problem - threading.
Since serial data has it's own speed and must not be depended on the game update frequency (otherwise it causes the serial stream to buffer and huge lagging accures), the following solution worked for me:
In the initialization function (init) I call invokeRepeating - timer that repeats itself every 0.01 seconds and in that timer, I call a thread for reading serial data.
Here is the pseudocode of the timer function:
void timerfunction ()
{
if (! threadAlive){
Start new thread - SerialThread ()
threadAlive = true;
}
}
void SerialThread ()
{
Read the Serial Data..
threadAlive = false:
}
This way, when there is a problem inside serial port, game won't lag because the thread takes the pressure on itself.
InvokeRepeating will make sure the threading (reading data) is attempted to be called every fixed (desirable) amount of time and therefore serial data will not buffer.
Worked just fine for me. Serial data speed was about 16Hz and gameplay framerate was - 10-100 fps.

Related

C# - slow float array processing (frame averaging)

i build an project in c# with winform GUI on the .net framework. The aim of the programm is to get data (image frames) from a frame grabber card and saving the data after doing some pre-processing on it.
The plugged camera is quite fast and has a pixel size of 640x480 with 16 Bit for each pixel and is working at 350 frames per second.
I added the library from the manufacturer that rises an event for every incoming frame and transfers the data as one-dimensional int16 array.
What i want to do is to average the bunch of frames for every second and saving the result in binary as an float array. Look here:
void Camera_OnRawImage(object sender, short[] data)
{
float[] frame = Array.ConvertAll(data, x => (float)x);
this.AverageProcess.AddImage(frame);
}
My problem is that there is a lot of data coming into my application. So the program is not able to process and save all the data before the next frames are pending to rise an event.
I already tried different approaches like:
- multiple threads to parallel calculate the arrays
- using marshalling methods for a better array access
- converting the arrays to MathNET arrays and using the INTEL MKL on MathNET library to speed up the process. look here:
internal void AddImage(float[] image)
{
currentFrameOfMeasurement++;
Vector<float> newImage = Vector<float>.Build.DenseOfArray(image);
newImage = newImage.Multiply(preAverageFactor);
var row = FrameMat.Column(currentFrameOfPeriod).Add(newImage);
FrameMat.SetColumn(currentFrameOfPeriod, row);
currentFrameOfPeriod++;
if (currentFrameOfPeriod >= this.Settings.FramesPerPeriod)
{
currentFrameOfPeriod = 0;
currentPeriodCount++;
}
}
But that is also a litte bit to slow. The RAM is increasing while grabbing the data. My methods need more than 10ms - wich is quite to slow.
To process and save the data must be possible. There is an application from the manufacturer wich is doing a lot of processing on the grabbed data. It seems like the program is written in delphi. Maybe they are using better library for doing all these operations.
My question ist now. Does anybody has an suggestion what i can do to speed up the process and calulation these arrays.
Thank you in advance
Use the Synchronized Queue (here) feature and queue in all the frames that come into your program and write a thread which can process the items in queue.

Fast approach to read and parse serial-data continuously

I've got a thread to read and parse serial data.
The messages are in binary format and start with either the character 'F', 'S', 'Q' or 'M'.
There are no newlines and there is no special ending character (the characters above state that a message is finished and everything before it is ready to be parsed).
How do I continuously read and parse the data?
All that comes to my mind is having a 4096 byte long input buffer (byte array) and then follow this procedure:
Track the position in the buffer manually
append available data to it via SerialPort.Read(buffer, position, byteCount)
try to parse as many messages as possible from the buffer
copy the rest to a temporary buffer
reset the input buffer
copy the contents of the temporary buffer to the original buffer
set the position in the buffer
Can you think of faster / easier approaches?
A very simple way to get ahead is to stop trying to make it faster. There is no point, serial port data rates are very, very low and modern computers are very, very fast. Your Read() call only ever returns a single byte, rarely 2.
Note that this is hard to see, when you debug and single-step through the code then you'll artificially slow down your program a great deal. Allowing more bytes to be received and thus more of them getting returned by the Read() call. But this doesn't happen when the program runs at normal speed.
So use SerialPort.BaseStream.ReadByte() instead. Makes the code very simple.
After acquiring some experience with SerialPort C# component
At the beginning: Take a serial port exclusevily.
Then:
1st parallel Task: Continues read entire buffer content after a regular
interval and pushes the read chunk into a "Gathering Collection" of data.
2nd parallel Task: Analyzes the "Gathering Collection" for a completed "phrase", delegates the clonned "phrase" to a "Phrase Manager" and excludes the phrase from the "Gathering Collection"
You have a freedom about "Gathering Collection" implementation, but what was important to me is that:
read all, but not a sized content from the Serial port buffer
to avoid losses and save an order in messages build your own port dispatcher rather let anybody open and close your port at any time for reading/writing.
detect the port read frequency experimenally. The more frequent read-operation will let your code detect fatser a "phrase" and start the proder handlind. Too frequent reading without detecting a "phrase" can cost you additional resource usage.

.Net SerialPort taking over 0.5 seconds to read byte when bytes available

I'm using the .Net SerialPort class in C# to read bytes from a port. On receipt of a DataReceived event I check the serial port to see if bytes are available to be read. However, even if bytes are available, the port can take over half a second to read a single byte. Code is roughtly as follows:
...
while(Port.BytesToRead > 0)
{
StopWatch.Restart();
Int32 BytesRead = Port.Read(Read, 0, 1);
StopWatch.Stop();
if (StopWatch.ElapsedMilliseconds > 100)
{
// Record the time. The stopwatch code
// was only added after performance issues were observed.
}
}
Note that the time which I've measured is not the time to read all bytes, rather the time to read a single byte. Frequently I'll receive a DataReceived event and have to wait 0.5 seconds for the first byte to be read.
I've actually tried setting the Port's ReadTimeout property to something smaller to prevent it from sitting there indefinitely, but this property seems to be ignored.
Any help greatly appreciated.
Turns out that running connected to the Debugger was causing the problem. Running outside of the debugger the maximum time recorded to read a byte was around 20ms, as opposed to up to 700ms when running within (no breakpoints, conditional or otherwise enabled).
Bit of a red herring, as the real cause of the comms problem when running a release build probably lay elsewhere.

Raise real time event at audio sample rate

I'm playing around doing some audio synthesis in real time with C# .Net.
I've got a VCO class that updates it's output waveform whenever the output waveform is read. In order to play a sound, I want to feed it into the DirectSound secondary buffer. I've played around doing this using a byte array not populated in real time.
However, in order to play my VCO in real time, I presume I need to read the output at the same rate as the sample rate specified for the direct sound object.
Is there a way I can have a timer or callback type function that raises an event at 1/sample rate so that the real time vco output can be matched to the direct sound sample rate ?
I suppose I can have a loop and interogate StopWatch.Ticks, but is there a neater way of having an event automatically raised, with no processor load in between ?

How to produce precisely-timed tone and silence?

I have a C# project that plays Morse code for RSS feeds. I write it using Managed DirectX, only to discover that Managed DirectX is old and deprecated. The task I have is to play pure sine wave bursts interspersed with silence periods (the code) which are precisely timed as to their duration. I need to be able to call a function which plays a pure tone for so many milliseconds, then Thread.Sleep() then play another, etc. At its fastest, the tones and spaces can be as short as 40ms.
It's working quite well in Managed DirectX. To get the precisely timed tone I create 1 sec. of sine wave into a secondary buffer, then to play a tone of a certain duration I seek forward to within x milliseconds of the end of the buffer then play.
I've tried System.Media.SoundPlayer. It's a loser [edit - see my answer below] because you have to Play(), Sleep(), then Stop() for arbitrary tone lengths. The result is a tone that is too long, variable by CPU load. It takes an indeterminate amount of time to actually stop the tone.
I then embarked on a lengthy attempt to use NAudio 1.3. I ended up with a memory resident stream providing the tone data, and again seeking forward leaving the desired length of tone remaining in the stream, then playing. This worked OK on the DirectSoundOut class for a while (see below) but the WaveOut class quickly dies with an internal assert saying that buffers are still on the queue despite PlayerStopped = true. This is odd since I play to the end then put a wait of the same duration between the end of the tone and the start of the next. You'd think that 80ms after starting Play of a 40 ms tone that it wouldn't have buffers on the queue.
DirectSoundOut works well for a while, but its problem is that for every tone burst Play() it spins off a separate thread. Eventually (5 min or so) it just stops working. You can see thread after thread after thread exiting in the Output window while running the project in VS2008 IDE. I don't create new objects during playing, I just Seek() the tone stream then call Play() over and over, so I don't think it's a problem with orphaned buffers/whatever piling up till it's choked.
I'm out of patience on this one, so I'm asking in the hopes that someone here has faced a similar requirement and can steer me in a direction with a likely solution.
I can't believe it... I went back to System.Media.SoundPlayer and got it to do just what I want... no giant dependency library with 95% unused code and/or quirks waiting to be discovered :-). Furthermore, it runs on MacOSX under Mono (2.6)!!! [wrong - no sound, will ask separate question]
I used a MemoryStream and BinaryWriter to crib a WAV file, complete with the RIFF header and chunking. No "fact" chunk needed, this is 16-bit samples at 44100Hz. So now I have a MemoryStream with 1000ms of samples in it, and wrapped by a BinaryReader.
In a RIFF file there are two 4-byte/32-bit lengths, the "overall" length which is 4 bytes into the stream (right after "RIFF" in ASCII), and a "data" length just before the sample data bytes. My strategy was to seek in the stream and use the BinaryWriter to alter the two lengths to fool the SoundPlayer into thinking the audio stream is just the length/duration I want, then Play() it. Next time, the duration is different, so once again overwrite the lengths in the MemoryStream with the BinaryWriter, Flush() it and once again call Play().
When I tried this, I couldn't get the SoundPlayer to see the changes to the stream, even if I set its Stream property. I was forced to create a new SoundPlayer... every 40 milliseconds??? No.
Well I want back to that code today and started looking at the SoundPlayer members. I saw "SoundLocation" and read it. There it said that a side effect of setting SoundLocation would be to null the Stream property, and vice versa for Stream. So I added a line of code to set the SOundLocation property to something bogus, "x", then set the Stream property to my (just modified) MemoryStream. Damn if it didn't pick that up and play a tone precisely as long as I asked for. There don't seem to be any crazy side effects like dead time afterward or increasing memory, or ??? It does take 1-2 milliseconds to do that tweaking of the WAV stream and then load/start the player, but it's very small and the price is right!
I also implemented a Frequency property which re-generates the samples and uses the Seek/BinaryWriter trick to overlay the old data in the RIFF/WAV MemoryStream with the same number of samples but for a different frequency, and again did the same thing for an Amplitude property.
This project is on SourceForge. You can get to the C# code for this hack in SPTones.CS from this page in the SVN browser. Thanks to everyone who provided info on this, including #arke whose thinking was close to mine. I do appreciate it.
It's best to just generate the sine waves and silence together into a buffer which you play. That is, always play something, but write whatever you need next into that buffer.
You know the samplerate, and given the samplerate, you can calculate the amount of samples you need to write.
uint numSamples = timeWantedInSeconds * sampleRate;
That's the amount of samples you need to generate a sine wave or silence, whichever. Then just fill the buffer as needed. That way, you get the most accurate possible timing.
Try using XNA.
You will have to provide a file, or a stream to a static tone, that you can loop. You can then change the pitch and volume of that tone.
Since XNA is made for games, it will have no problem at all with 40 ms delays.
It should be pretty easy to convert from ManagedDX to SlimDX ...
Edit: What stops you, btw, just pre-generating 'n' samples of sine wave? (Where n is the closest to the number of milliseconds you want). It really doesn't take all that long to generate the data. Further than that if you have a 22Khz buffer and you want the final 100 samples why don't you just submit 'buffer + 21950' and set the buffer length to 100 samples?

Categories

Resources