Question

Hi guys I'm writing an application in C# that gets data from an accelerometer (inside a wiimote), and then processes and graphs it. I'm using Brian Peek's Wiimote library, so I'm using an event handler to get the data:

void wiimote_WiimoteChanged(object sender, WiimoteChangedEventArgs e)
{
    X = e.WiimoteState.AccelState.Values.X;
    Y = e.WiimoteState.AccelState.Values.Y;
    Z = e.WiimoteState.AccelState.Values.Z;          

}

I want to graph/save/process the data at a rate of 100Hz, so I created a timer object (WiiTimer), set it's "Tick Interval" to 10ms, then on every tick, of the timer the data is stored/processed:

private void WiiTimer_Tick(object sender, EventArgs e)
{

   //Signal Processing (Some median and low pass filtering etc.) Ive removed the code for that since it is irrelevant here

    sw.WriteLine((X * 9.8).ToString() + ", " + (Y * 9.8).ToString() + ", " + (Z*9.8).ToString() );
  //Write Processed Data to file            

}

Now the problem is, the data isnt actualy saved at 100Hz, since the Signal Processing takes some time, the timer doesnt manage to call its OnTick event handler EVERY 10ms. and hence the data storage rate depends on how fast a machine you're running the code on, how many other programs you have running etc.

How do I solve this? I thought of running the timer on a separate thread, but that would cause other problems, as someone pointed out on another question here: "Your timer event is likely to want to access objects from the other thread. But to do so will result in race conditions."

Any ideas?

Was it helpful?

Solution

Timers aren't particularly exact, so the best way to do this if you actually want 100 samples per second is something like this:

private class Result
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }
}

private Result lastResult;

void wiimote_WiimoteChanged(object sender, WiimoteChangedEventArgs e)
{
    Result newResult = new Result {
        X = e.WiimoteState.AccelState.Values.X,
        Y = e.WiimoteState.AccelState.Values.Y,
        Z = e.WiimoteState.AccelState.Values.Z,
    } 

    lastResult = newResult;
}

void MainLoop()
{
    DateTime nextResultTime = DateTime.Now.AddMilliseconds(10);

    while(true)
    {
        if (DateTime.Now >= nextResultTime)
        {
            AddResult(lastResult);
            nextResultTime = nextResultTime.AddMilliseconds(10);
        }
        else
        {
            Thread.Sleep(1);
        }
    }
}

Just run MainLoop on a background thread (this might not be necessary if the wii events fire on a background thread).

This will get you exactly 100 samples per second unless the machine just can't handle doing AddResult that fast. In that case I think you have to lighten the load inside AddResult and do some post processing after you have captured your data - either the machine is fast enough to do it real time or it just isn't.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top