0

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?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
7VoltCrayon
  • 662
  • 1
  • 7
  • 22
  • Any idea how long signal processing is taking? Can it happen that signal processing itself would take >= 10 ms? – Alex M Nov 24 '12 at 17:46
  • @Aleksey I suspect that is exactly the problem, The Timer OnTick eventhandler processes the data, displays it on a chart in the windows form, and then saves it to a file, so I'm pretty sure it IS more than 10ms – 7VoltCrayon Nov 24 '12 at 17:48
  • I'm only interested in processing, not saving to file. As with saving to file you can group multiple results and flush to IO once per N times. – Alex M Nov 24 '12 at 17:51
  • EDIT: What I thought was, what I could do is only use the WiiTimer to SAVE the data, and then use another timer (potentially with a larger tick time) to do the signal processing/ writing to file on chunks of data, is this the right approach? – 7VoltCrayon Nov 24 '12 at 17:53
  • 1
    Can you try storing your incoming data from the WiiMote in a Queue then use your timer to process the Queue? – Mark Hall Nov 24 '12 at 17:55
  • Yes, I think that would be better option. But even though it will be relative (much closer to 10 ms intervals, but still relative) as you can't ensure the machine is not loaded by some other high priority process. – Alex M Nov 24 '12 at 17:57
  • @MarkHall I'm a tad bit confused,do you mean to say that I should use the WiiTimer ONLY to save the data in a queue, and use another timer to process it? Or do you mean I should save the data in a queue DIRECTLY inside the wiimote_WiimoteChanged event handler? – 7VoltCrayon Nov 24 '12 at 17:59
  • @Suleman Directly in the eventHandler then use your WiiTimer to process it – Mark Hall Nov 24 '12 at 18:00
  • @MarkHall Thankyou for your answer, but from what I can gather (and I might be wrong) the wiimote_WiimoteChanged triggers only when the acceleration value from the wiimote is changed, not at a fixed frequency, so the data in the queue wont be at 100Hz, thats why I resorted to using a timer in the first place – 7VoltCrayon Nov 24 '12 at 18:04
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Nov 24 '12 at 18:07
  • @Suleman then check if the queue is empty an repeat the previous value – Mark Hall Nov 24 '12 at 19:06
  • The Wii Remote does not send samples at a constant rate. If it did, you could just store each sample, and you automatically know at which times they occur. – Brad Nov 25 '12 at 02:33
  • @Brad, exactly why I used a timer in the first place, so any suggestions on what to do? – 7VoltCrayon Nov 25 '12 at 06:52

1 Answers1

1

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.

Mike Marynowski
  • 3,156
  • 22
  • 32