If you've been following Tom Pyke's progress on his impressive Gluonpilot, you will have seen that he's implementing it with a realtime operating system (RTOS), rather than programming "straight to the iron" the way most autopilots are done, to gain maximum control over interrupts, timing and the like. He's using a relatively powerful dsPIC chip, which can handle the overhead of the RTOS (I think he's using FreeRTOS, but I've pinged him to find outUPDATE: yes, it's FreeRTOS. See below). Here, he makes the case for a RTOS:
"The main advantage of a real time OS is that you can use threads (which we will use tasks from now on). You don't need to bother anymore about the delay your telemetry processing can cause to your Kalman filter or PID control. No more need for timed loops or Timer interrupt routines. It looks perfect!
There are some things you need to keep in mind:
You need to prioritize every task
Every task has a separate stack. This stack is used for the task itself AND every interrupt routine that may be called during this task's execution
Thats about it! Let's take a look at the different tasks in gluonpilot:
--Telemetry: All the output needed for our groundstation
--ConsoleInput: Processing and answering all the commands you send to the autopilot
--Sensors: Gathers and processes (filters!) all the sensors (gyroscope, accelerometer, gps, pressure sensor) on our autopilot module
--Control: Sends the correct position to the servos! This handles both manual, stabilized and full autopilot modes."
The prioritization of the tasks is as follows:
Read on here.
UPDATE: In an email, Tom explains more:
"Yes I'm using FreeRTOS. Whether you should need to consider it [I had asked him if it would work on a 16Mhz Atmega--chris] is not easy to answer. 16MHz doesn't seem a lot. The dsPic runs at 80MHz (40MIPS) and - I think - has more memory. Using an RTOS does not cause an extreme amount of overhead, but you can no longer push the
processor to its limits:
- You need more memory because interrupts can be executed (and use
the stack) of any running task/thread (and you need to assign a stack
size to every task)
- You need enough spare CPU cycles to make sure all tasks can always
be handled in time.
- And the RTOS needs memory, flash and CPU time of its own
It may sound contradictory, but I started using FreeRTOS to make sure people can easier add code to the autopilot. In the last version without it, the code became complex and critical to change, because of all the timing-critical code and timed loops. Now with the RTOS, people can add lower priority tasks and I'm sure the manual control and time-critical filtering still works. However, you need to keep the design as simple as possible.
The only features I'm currently using is the scheduler (because it's easier than a timed loop) and a queue mechanism for pushing data from an interrupt to a sleeping thread.
There are some RTOS pitfalls such as priority inversions. But it's really up to you how far you want to go. Replacing your timer interrupt routine by a threads wonn't give you any problems you didn't have already. If you use mutexes for mutual exclusion all over your code, than you're down to a more challenging task :-)
In the end, I can only suggest that you play with it for a day or two... port some existing code to FreeRTOS and see how comfortable you are using it. It's not really that complex."
Sounds like a bunch of unnecessary overhead to me. The 2.5 code is in the branches folder. Feel free to fork that into a RTOS version and lets see what it can do.
A team from Argentina has integrated the FreeRTOS with the arduino environment. It is called DuinOS. You spend just a few minutes to convert the current Ardupilot code to a FreeRTOS enabled one.
The thing we have to do is run 3rd party libraries like picoc & libjpeg in their own processes so the flight controller doesn't crash when they encounter problems. We fully endorse FreeRTOS for the right uses. It's just not working out for our needs.
Tom: is that api documented ... I poked around the link that was posted by lionel, but nothing jumped out at me. If it's like you say it is, then that would be pretty slick.
@lionel: thanks for the link. That gives some good info on the scheduling / task control parameters that can be set. But please let me state my real question again in a slightly different way.
Let's say I have task #1 that I want to run at exactly 50hz and lower priority task #2 that I want to run at exactly 25hz (hopefully those are easy numbers since most of the systems I've worked with have a kernel tick rate of 100hz by default.) This is the sort of thing people *say* they want to do in real time systems. The original post implies that multiple tasks can run along side each other without having to worry about each (of course assuming everything fits within the cpu budget.)
So if I have a task #1 that I want to run at exactly 50hz, what is the mechanism to ensure that. Let's make it even simpler and say that I just have the one single task on the system and I want it to loop at exactly 50hz. What is the mechanism available to ensure that my task is fired off at exactly the desired rate?
Ok, I'm probably being a bit transparent here ... I've been in debates about the relative merits of threading before, and this is an area I honestly don't understand well ... but I don't think most of the people I've discussed this with understand it well either.
I want a task to loop at exactly 50hz. What is the best mechanism to do that and does this mechanism have anything to do with threads?
Hopefully this doesn't come off as adversarial or critical. I'm currently involved in an autopilot project on an embedded system (gumstix right now). I'm hard headed in some ways and if I make a change to my own code and scheduling approach, I want to understand why, and be able to convince myself that the added complexity and bugs-waiting-to-happen with thread based systems are worth enduring. And on the flip side, if I dig my heals in on my current approach, I want to fully understand the other options so I can make a clear and unambiguous defense of my own approach.
I could blab on ... most of the text book threading examples I've seen have been in the computer science / operating system world. These sorts of programs tend to be reader/writer sorts of tasks that need to take some input on one end, do something, and spit out something on the other end. So tasks that sit around and block on input/output and run when there is something to do can make a lot of sense and work well.
But in a real time environment where I have a set of possibly independent tasks and the key issue is that I want them to run at a very precise and fixed rate (and possibly a fixed order) ... i.e. 1. read sensor data, 2. estimate attitude/position, 3. drive actuators, 4. communicate with ground station, does a threaded application model really add all that much? Maybe this is a discussion that could/should be split off into a different thread, but I don't know how to do that here.
Or maybe no one really cares (?) :-) Maybe no one has any idea what I'm talking about ... that's fine too, I lose track of what I'm talking about once in a while myself. :-)
It's actually a lot simpler. You just tell the scheduler to run this function once every 10ms (for example). The scheduler does the rest (no matter how long your function takes to execute - assuming that your function finished in less than 10ms).
So I have these tasks:
- Telemetry: every 50ms
- UART input: triggered via a mutex on a queue
- Sensors: every 10ms
- Control: every 20ms
Our only problem with FreeRTOS is that it's not a POSIX interface. You couldn't write for FreeRTOS & get all the advantages of a full Linux ARM without serious rewriting. Microprocessors are at the point where someone could probably sell a bare chip with a full Linux OS instead of a NetBurner or Gumstix.
Still impressive that it's actually been ported to something as small as a dsPIC. Had a coworker using it on an ARM to run a web server that streamed HD video.
I have a question for Tom on task timing. What mechanism are you using to schedule your tasks and control the loop timing?
Are you using an interrupt/signal/timer sort of mechanism to launch each task at the appropriate rate? Are you using a sleep/delay at the end of each loop iteration? Are you using a network of intricately woven signal/wait constructs? Something else?
I've seen systems that use a delay at the end of each loop and in fact didn't get the actual loop rates they intended because they didn't account for the kernel tick timer rate and the amount of time required to execute the loop code.
I've seen systems that used an intricate network of signal/wait primitives for all the threads. The end result was that they had implemented a simple linear flow of control using a complicated threaded architecture and if any thread blocked the whole application blocked. They got all the complexity and brittleness of a threaded architecture with none of the benefits.
The only way I can see to do this sensibly and actually get some real benefit from threads is to have a hardware timer(s) generate an interrupt at a regular rate and use that to launch each loop iteration of each thread.
But I'm certainly no expert, so I'm curious what approach you used and curious to see if you've thought of a smarter approach than I've thought of (or that other's whose code I've seen have thought of.)
Comments
Curt.
Let's say I have task #1 that I want to run at exactly 50hz and lower priority task #2 that I want to run at exactly 25hz (hopefully those are easy numbers since most of the systems I've worked with have a kernel tick rate of 100hz by default.) This is the sort of thing people *say* they want to do in real time systems. The original post implies that multiple tasks can run along side each other without having to worry about each (of course assuming everything fits within the cpu budget.)
So if I have a task #1 that I want to run at exactly 50hz, what is the mechanism to ensure that. Let's make it even simpler and say that I just have the one single task on the system and I want it to loop at exactly 50hz. What is the mechanism available to ensure that my task is fired off at exactly the desired rate?
Ok, I'm probably being a bit transparent here ... I've been in debates about the relative merits of threading before, and this is an area I honestly don't understand well ... but I don't think most of the people I've discussed this with understand it well either.
I want a task to loop at exactly 50hz. What is the best mechanism to do that and does this mechanism have anything to do with threads?
Hopefully this doesn't come off as adversarial or critical. I'm currently involved in an autopilot project on an embedded system (gumstix right now). I'm hard headed in some ways and if I make a change to my own code and scheduling approach, I want to understand why, and be able to convince myself that the added complexity and bugs-waiting-to-happen with thread based systems are worth enduring. And on the flip side, if I dig my heals in on my current approach, I want to fully understand the other options so I can make a clear and unambiguous defense of my own approach.
I could blab on ... most of the text book threading examples I've seen have been in the computer science / operating system world. These sorts of programs tend to be reader/writer sorts of tasks that need to take some input on one end, do something, and spit out something on the other end. So tasks that sit around and block on input/output and run when there is something to do can make a lot of sense and work well.
But in a real time environment where I have a set of possibly independent tasks and the key issue is that I want them to run at a very precise and fixed rate (and possibly a fixed order) ... i.e. 1. read sensor data, 2. estimate attitude/position, 3. drive actuators, 4. communicate with ground station, does a threaded application model really add all that much? Maybe this is a discussion that could/should be split off into a different thread, but I don't know how to do that here.
Or maybe no one really cares (?) :-) Maybe no one has any idea what I'm talking about ... that's fine too, I lose track of what I'm talking about once in a while myself. :-)
Thanks,
Curt.
It's actually a lot simpler. You just tell the scheduler to run this function once every 10ms (for example). The scheduler does the rest (no matter how long your function takes to execute - assuming that your function finished in less than 10ms).
So I have these tasks:
- Telemetry: every 50ms
- UART input: triggered via a mutex on a queue
- Sensors: every 10ms
- Control: every 20ms
Still impressive that it's actually been ported to something as small as a dsPIC. Had a coworker using it on an ARM to run a web server that streamed HD video.
Are you using an interrupt/signal/timer sort of mechanism to launch each task at the appropriate rate? Are you using a sleep/delay at the end of each loop iteration? Are you using a network of intricately woven signal/wait constructs? Something else?
I've seen systems that use a delay at the end of each loop and in fact didn't get the actual loop rates they intended because they didn't account for the kernel tick timer rate and the amount of time required to execute the loop code.
I've seen systems that used an intricate network of signal/wait primitives for all the threads. The end result was that they had implemented a simple linear flow of control using a complicated threaded architecture and if any thread blocked the whole application blocked. They got all the complexity and brittleness of a threaded architecture with none of the benefits.
The only way I can see to do this sensibly and actually get some real benefit from threads is to have a hardware timer(s) generate an interrupt at a regular rate and use that to launch each loop iteration of each thread.
But I'm certainly no expert, so I'm curious what approach you used and curious to see if you've thought of a smarter approach than I've thought of (or that other's whose code I've seen have thought of.)
Thanks,
Curt.
-
1
-
2
of 2 Next