1

I have about 6 sensors (GPS, IMU, etc.) that I need to constantly collect data from. For my purposes, I need a reading from each (within a small time frame) to have a complete data packet. Right now I am using interrupts, but this results in more data from certain sensors than others, and, as mentioned, I need to have the data matched up.

Would it be better to move to a polling-based system in which I could poll each sensor in a set order? This way I could have data from each sensor every 'cycle'.

I am, however, worried about the speed of polling because this system needs to operate close to real time.

neophyte
  • 55
  • 6
  • 3
    so the question is...? Test your polling loop time and see if it match your requirements... – LPs Jun 05 '17 at 14:59
  • Personally I don't like polling. Don't your sensors have interrupts? – Alex D Jun 05 '17 at 16:37
  • neither polling only nor interrupt only have anything to do with real-time, you have to do your system engineering, this will give all the answers. polling is certainly easiest you determine the time of each event path and so long as the slowest one does not interfere with the requirements of the others, you are good. sometimes you can do this with polling only or interrupts only but likely to end up somewhere in the middle. interrupts doesnt mean you handle them there btw, that is at times not good, so there is no one answer. – old_timer Jun 05 '17 at 18:08

2 Answers2

1

Polling combined with a "master timer interrupt" could be your friend here. Let's say that your "slowest" sensor can provide data on 20ms intervals, and that the others can be read faster. That's 50 updates per second. If that's close enough to real-time (probably is close for an IMU), perhaps you proceed like this:

  1. Set up a 20ms timer.
  2. When the timer goes off, set a flag inside an interrupt service routine:

    volatile uint8_t timerFlag = 0;
    
    ISR(TIMER_ISR_whatever)
    {
        timerFlag = 1;  // nothing but a semaphore for later...
    }
    
  3. Then, in your main loop act when timerFlag says it's time:

    while(1)
    {
        if(timerFlag == 1)
        {
            <read first device>
            <read second device>
            <you get the idea ;) >
            timerflag = 0;
        }
    }
    

In this way you can read each device and keep their readings synched up. This is a typical way to solve this problem in the embedded space. Now, if you need data faster than 20ms, then you shorten the timer, etc. The big question, as it always is in situations like this, is "how fast can you poll" vs. "how fast do you need to poll." Only experimentation and knowing the characteristics and timing of your various devices can tell you that. But what I propose is a general solution when all the timings "fit."

EDIT, A DIFFERENT APPROACH

A more interrupt-based example:

volatile uint8_t device1Read = 0;
volatile uint8_t device2Read = 0;
etc...

ISR(device 1)
{
    <read device>
    device1Read = 1;
}
ISR(device 2)
{
    <read device>
    device2Read = 1;
}
etc...


// main loop
while(1)
{
    if(device1Read == 1 && device2Read == 1 && etc...)
    {
        //< do something with your "packet" of data>
        device1Read = 0;
        device2Read = 0;
        etc...
    }
}

In this example, all your devices can be interrupt-driven but the main-loop processing is still governed, paced, by the cadence of the slowest interrupt. The latest complete reading from each device, regardless of speed or latency, can be used. Is this pattern closer to what you had in mind?

TomServo
  • 7,248
  • 5
  • 30
  • 47
  • 1
    @Clifford Indeed. What I've done in situations like that, where peripherals have wildly different sampling rates, is to "gear down" the timerFlag using a counter. An IMU for a balancing robot might need 50 updates/sec to stay upright, whereas the GPS can only be polled 1 out of 50 times. – TomServo Jun 05 '17 at 16:06
  • 1
    That's why I don't like polling. With this approach you have to calculate the data processing latency of all sensors combined and make sure that you do not exceed 20ms (as an example) for the polling interval of the 1st one. As soon as you add a new sensor in the future, or the sensor changes in terms of data processing or polling interval, all your loop scheme goes to hell and becomes completely unmaintainable and unscalable. – Alex D Jun 05 '17 at 16:43
  • 1
    @Alex agreed. I prefer interrupts where possible. However, the OP's question was about polling in particular, and the truth is, it might be possible to do it that way. OP may not be interested in scaling anything here, just a one-off solution. So without judging I answered her question with a possible solution. – TomServo Jun 05 '17 at 16:48
  • 1
    @JLH I'd prefer to use interrupts as well. I am, however, unsure of how I could ensure that I got a reading from each sensor per 'cycle'. Each data chunk in my system has to have data from each of the six sensors. Is there an interrupts-based solution that would ease scalability? – neophyte Jun 05 '17 at 17:35
  • 1
    @Ana This is your quandary -- separate interrupts for each device mean data arrives at different times. A single master interrupt like the one I proposed will let you get them all together. Neither approach is ideal. Engineering is about finding a suitable solution to different -- often competing -- goals. I don't think anyone here could offer an authoritative solution without knowing every detail of your platform and all the devices you intend to use. I've been doing microcontroller work for a decade and many projects present similar challenges. – TomServo Jun 05 '17 at 17:42
  • @Ana your repeated reference to 'cycle' though suggests another approach... let me put it in an example.... – TomServo Jun 05 '17 at 17:44
1

Polling is a pretty good and easy to implement idea in case your sensors can provide data practically instantly (in comparison to your desired output frequency). It does get into a nightmare when you have data sources that need a significant (or even variable) time to provide a reading or require an asynchronous "initiate/collect" cycle. You'd have to sort your polling cycles to accommodate the "slowest" data source.

What might be a solution in case you know the average "data conversion rate" of each of your sources, is to set up a number of timers (per data source) that trigger at poll time - data conversion rate and kick in the measurement from those timer ISRs. Then have one last timer that triggers at poll timer + some safety margin that collects all the conversion results.

On the other hand, your apparent problem of "having too many measurements" from the "fast" data sources wouldn't bother me too much as long as you don't have anything reasonable to do with that wasted CPU/sensor load.

A last and easier approach, in case you have some cycles to waste, is: Simply sort the data sources from "slowest" to "fastest" and initiate a measurement in that order, then wait for results in the same order and poll.

tofro
  • 5,640
  • 14
  • 31