Do I need to use the Due Scheduler library?

Hello,
I am using an Arduino Due to stabilize a quadcopter.
The Due is working/communicating with an IMU, a ping sensor, 4 motor drivers by I2C, etc.
Timing is quite important, rigth now my loop() takes around 20ms, and I'd like to lower it.

So I found out that just calling the ping sensor and waiting the response wave can take up to 6ms, because that's the time the wave takes to travel from the sensor to the ground and come back.

Then I thought: "I can use the Scheduler library to make another task where the ping can be measuring in its own loop..." so I don't lose those 6 ms.

My 2 questions are:

  • Should I use the scheduler library or is there an easier way to accomplish this?

  • In case I use the Scheduler library... can I safely use in the main loop a variable that the ping loop is changing?? (first, is it even possible???) Wouldn't I need a semaphore?

Thank you very much! :slight_smile:

Anyone??

It's a tough topic.

The scheduler library is just an easy way to create a sort of simple cooperative tasking system. You could do the same basic thing yourself. Whether you use it or not depends on how you want to structure your code. What you really want to do is send a ping and then go off and do other things and then remember to come back to check it at some point. What you can do is create a loop that checks conditions (did I get a ping back? Is it time to send a ping? Is it time to do something to a servo?) but does not block. That is, you never sit in a loop and just wait for one thing. You create a main loop that checks for any condition that could happen and handles it quickly. If something needs to happen it does that thing and then returns to the loop as soon as possible. You can have a timer interrupt that ticks at, say, 1ms. Then, maybe you want to ping every 50ms. So, you count to 50 and then send a ping. The checking for replies happens as quickly as possible along with all other checks. Have I explained that properly? What I envision looks sort of like this:

void main(void) {
setup();

while (1==1) {
if (pongReply) processPong();
if (timeToPing) sendPing();
if (timeToAdjServo) adjustServo();
}
}

The key is to never spend long doing anything and to use interrupts as much as possible.

The answer to the second question: If you have multiple threads and they need to be able to change the same variable then the easiest thing is to declare it volatile. This will prevent the variable from being cached in a register and so each change will show up in RAM. Now, this still requires care to not interrupt a task in the middle of changing the variable or in the middle of a sensitive operation. As luck would have it, I am almost 100% sure the Scheduler library for Due does not support preemptive tasking so task switches will not happen unless you ask them to. In other words, don't intentionally do a task switch at a stupid time; have some common sense and you'll be fine. And, if you do it yourself you almost won't be preemptively tasking so it should still work out.

@Collin80
Thank you for your answer.
The method you describe in your example code is similat to the one I am using, so I am starting to think the Scheduler library won't fix my problem.
I think I did not explain myself rigth.

I have a sensor (ping) which takes up to 6 ms from the moment I ask him to give me the measurement to the moment I receive the measurement. During this 6ms I am using pulseIn to count how long a pin is HIGH, so the CPU is blocked (I believe so).
I don't need to get this measure too often, maybe every 100ms.

Then I have another sensor (IMU) which takes almost no time to give me the measure, but I would like to get this measure much more often, like every 1 or 2 ms.

What I am trying to do is to find a way that lets me keep reading the IMU sensor while waiting those 6ms for the ping sensor measure...
I thougth I could do it with the scheduler, so the waiting would not block my other tasks, but maybe it can't be done.

Another solution would be using an extra arduino to read ONLY the ping, and send its measure every 100ms, for example.

Any idea?

During this 6ms I am using pulseIn to count how long a pin is HIGH, so the CPU is blocked (I believe so).

You could use an interrupt to trigger when the pin goes low, and then check the value of millis() if you need to know how long the pin was high.