Practical RTOS Project Ideas for Real-World Applications"

Hello everyone

I’ve been immersing myself in the fascinating realm of Real-Time Operating Systems (RTOS) with a focus on FreeRTOS. The concepts of task scheduling, synchronization, and multitasking have got me intrigued, but now I’m on the hunt for exciting project ideas to put theory into practice.

Please keep in mind that I’m looking for projects that are within my reach and not too advanced, so projects like radar systems, air traffic control, and satellites are a bit beyond my current capabilities.

Already asked here RTOS Learning Journey: Project Idea needed - Page 1

Do you have any project suggestions that would be a perfect fit for a RTOS? I’d really appreciate it!

@richard-damon @rtel @aggarg

Your expertise could help me take the next step in my learning journey! Thank you in advance for your valuable suggestions.

Hi kittu,

looking at your forum history, I can’t help but feel that you ask the same basic question every few months… could it be that you are searching for something to help you tie all those loose ends together?

Every real life project you may wish to tackle requires peripherals which is hardware, so you need to become clear about what hardware you are able to/ want to build your sample project on. Typical stand-alone projects that fit the bill would be sensor driven systems such as weather stations, smoke detectors or very rudimentary model train controllers. Those must also fit your personal preferences and intersts, of course.

Then again, very few embedded systems these days exist without host communication channels to concentrators, smartphones or PCs, typically network or UART based, so you should pick a target hardware also with that in mind.

Thank you for your thoughtful response. I am looking for real-world examples to better understand the practical benefits of using RTOS. While projects like smoke detectors and temperature-humidity monitoring over UART i don’t think they are real time system, This forum seems like an ideal place to tap into the expertise of developers who have experience with RTOS. I hope to gain a deeper understanding of why and how they leverage RTOS over bare-metal coding. Your input has been valuable, and I’m open to further suggestions.

@Kittu20 Do you have more detailed asks on what sort of project you’d like? It seems like you’d like a example where an RTOS does a vastly better job than just a routine running on hardware, gathering from your response. What about a controller for a robot car (one that is small)? That could simulate a real-life automotive control system.

P.S. In my opinion, whether to design something as a real-time system (with a starter project) is, a lot of times, your choice. Of course, flight controls or satellite communication probably has to be designed as a real-time system with its real-life requirements, but a weather sensor/smoke detector that connects to the internet and reports temperature can just as well be real-time if you design it to be. Whenever you start having to deal with networking, responding to sensor information, etc. that all competes for CPU time, an RTOS becomes superior.

1 Like

Thank you for your thoughtful response.

Let’s talk RTOS and bare metal choices. Remember, having a tool doesn’t guarantee it’s the best fit.

Picture this: a task as simple as flashing an LED with different flash rates. Can you imagine choosing FreeRTOS for such a seemingly simple task? Or does it require “bare metal coding style”? Let’s look at the reasoning behind our choice.

Share your insights and let’s explore the art of picking the perfect tool for each job!

Looking forward to your thoughts,

Lets refine the problem.

When you say “with different flash rates”, what is deciding that different flash rates?

If somehow the program is, a “typical” baremetal flashing is done with a counting delay loop, so the CPU is busy while flashing, so can’t do any thing else, or the timing is off.

If it check an on chip timer periodically, your “flash rate” may not be accurate, and you need to be real careful what you do between the checks to not take too long.

With an RTOS, you make a high priority task (or timer call back) that handles the flashing, which allows a low priority task to be deciding on what rate to flash at, without needing to worry about breaking its work into small pieces that can execute quick enough to not affect flash rate too much.

If it is just one single flash rate, or.a simple programming pattern that can easily be done, then perhaps the RTOS doesn’t help much, but it does provide tools that make the programming perhaps simpler, and since the processor isn’t counting the time, we can perhaps put the processor to sleep between flashing operations and save power, or have the ability to add more functionality later.

Yes, the “bare metal” code could do the same thing, but then you have to write all the code yourself and not lean on the already provided framework for all of this.

Oh, that is what you are getting at. We had this many many times before: If the system you need to realize can meaningfully be modelled by several mostly independent logical strands of execution, an RTOS will help you sort out the control flow. If all your system needs to do can be modelled via a linear deterministic sequence of actions (eg read sensor->communicate sensor to host->sleep->repeat), you do not necessarily need an RTOS (although parts of that sequence, eg the host communication, may bear some hidden concurrency, in which case an RTOS, again, is the tool of choice).

Most current embedded systems generally serve more than one logical strand of execution, so there are very few use cases of single-threaded embedded systems.

The other issue you mentioned was hard real time. Admittedly, very few systems require true hard real time, but one of the benefits of RTOS over more complex operating systems is that they allow you to design your system such that an upper bound can be guaranteed for most time critical operations (that is the traditional definition of real time).

Please consult with one of the many many resources that discuss RTOS before putting up such elementary questions on this forum. You can also browse previous threads here and will find that the basics and rudimentaries of RTOS have been explained here several times before.

Thanks.

Hi @Kittu20,

Your question is actually more than one questions:

  1. Why choose FreeRTOS vs other RTOSes ?
    Answer: Why choose an Arduino, or a Raspberry Pi? Simply because it is actively maintained, which a large user base and has an active support community.

  2. If everything can be done baremetal, why choose an RTOS at all?
    Answer: A baremetal application is fast and efficient, and can be flexible if coded that way. However, most baremetal applications are designed for a specific purpose and lack this flexibility that using a scheduler gives you. I’ll give you a real-world example: After deploying an application, the users want a new feature to be added than wasn’t originally planned. With a baremetal implementation, adding a new task is a big ordeal which can screw up the timing of all other tasks in the system. With FreeRTOS you simply create a new task, assign it a priority and go refill your coffee cup. Therefore with an RTOS it is much easier to achieve maintainability.
    Another added benefit of using an RTOS is that having multiple developers work on the same project simultaneously is much easier to achieve, and easier to merge.

  3. But please, give me a real-world example!
    Answer: Assume that you have an action camera with 3 computing units: an application processor, an image processor and a microcontroller for the sensor sub-system and collecting user input from buttons/touchscreen. The microcontroller communicates the two other processors using SPI. Sensor data is gathered using I²C and SPI, based on timer polling and interrupt.
    Let’s list all the tasks that the microcontroller has to do:
    Task1: Poll battery temperature at 2Hz via I²C and interrupt the application processor in case of overheat condition.
    Task2: After the application processor triggers the recording, read gyroscope data at 6.4kHz (interrupt-based) and send it to the image processor with minimal latency for image stabilization.
    Task3: (Polling or interrupt-based): Read accelerometer data at 100Hz and buffer it.
    Task4: At a low priority, run a portrait/landscape algorithm based on accelerometer data buffer.
    Task5: (Interrupt-based) collect user input from buttons and touchscreen and relay it to the application processor.

Now that we think we have collected all the requirement we choose whether or not we go baremetal or RTOS. Implement and test and we are done… until your manager calls you into a meeting saying that image stabilization performance is not good. Instead of sending the data directly to the image processor in real time, he wants you to modify the code so it timestamp the data precisely and sends it to the host instead, so they can run image stabilization in software instead.

It is much easier to partition the tasks, exchange data and events between them, concurrently run low-priority and high-priority taks, and maintain a system using an RTOS than doing it baremetal.

Full disclosure: This is my point of view only, as an embedded developer with 10 years of experience.

2 Likes

It may not be a suggestion for a project that you would do yourself, but I’ll give an overview of a project that I completed earlier this year using FreeRTOS and a PIC32MX microcontroller. I guess it could be an example of a real world application of using an RTOS.

I have a garage which is a short walk away from my house, I keep a motorbike in it. I dont have mains power there, so I have a solar panel on the roof which I can use to keep the battery of the motorbike charged during the colder months when I dont ride it regularly.

Now, I could have avoided this whole project by using a different type of charger, but wheres the fun in that … :slight_smile:

I decided to build a little “contraption” that turns a charger which is connected to the solar panel on and off on a daily basis if the motorbike battery is starting to get a little low and needs a top up. I also added some “nice to have” features like an LCD display that can show voltages and current, temperature, time, and some status icons, and a LoRaWAN module so that I could transmit some statistics back to the house and monitor the battery voltage remotely. Way over the top, but it all presented some nice challenges to build the logic, control, and sequencing using FreeRTOS features.

So some specifics:

The LCD is attached to the front panel of a case so that I can see it, and there are also some buttons. I have a task which periodically reads the status of the buttons and places them into a variable. A task that is “in control of the user interface” can read that variable to see what the buttons are doing and then decide what action it should take next (like scrolling through a menu, adjusting a setting, etc). As part of the user interface, I enable the LCD backlight when a button is pressed and use a timer to turn it off again after a short time if no buttons are pressed.

Another task is responsible for taking a buffer and updating the contents of the LCD. This can be quite a slow process, especially since I am using a 4 bit interface with it since I had little IO to spare to implement a full 8 bit interface. So a task can run in the background updating the LCD while everything else continues to function normally.

There is a temperature sensor connected to the I2C bus from the microcontroller, along with some voltage/current sensors, a real time clock, and IO expander. So I built some “infrastructure” that allows me to queue “buffer descriptors” to read/write I2C devices. A task that wants to read the temperature sensor for example can queue a buffer descriptor with the I2C task saying what address and how many bytes to read/write to or from a supplied buffer, the I2C task takes care of that and returns the data in a buffer supplied by the requesting task. Multiple tasks can therefore send in a bunch of buffer descriptors to the queue and they will all be processed in turn.

The LoRaWAN stuff operates similarly, a task that wants to send a message over LoRaWAN queues a buffer descriptor containing the message to be transmitted, and waits for the LoRaWAN task to process it and signal back that it is complete, along with any error or status information. Since its nice to see what is happening with the LoRaWAN connection, the task supplies some status bits which the user interface task reads, allowing it to insert some icons onto the LCD to show whether the LoRaWAN connection is active, and whether it is transmitting. Importantly for the I2C and LoRaWAN tasks, this decouples the requirement of interfacing with those peripherals from each individual task and places it with some central tasks that can implement all of the required logic, taking some buffers as input or output for a given request. That helps to simplify those tasks and removes a lot of duplicated code.

And finally theres a task that turns the charger on and off at certain times of the day if the voltages that have been recorded suggest that it should be turned on.

Theres more to it, but thats just a sample of some of the ways Ive used tasks/queues/timers/etc to implement some of the processing and handling of peripherals etc. Its a bit complicated and probably way over done for sure, but it was a fun project to really sink my teeth into FreeRTOS and its features, and it was all made much easier by having a scheduler underneath my code that can put my tasks to sleep and wake them up as needed. And the result is something that Im very proud of. :slight_smile:

Heres a picture of it installed and operating.

4 Likes

Thank you so much for sharing your fascinating project and how you used FreeRTOS to handle the complexities. While I don’t have the exact same microcontroller setup, I’m curious to know how you would approach implementing FreeRTOS for a project with similar requirements, like the one I described:

Here are the project requirements:

Scenario: We have a garage a short walking distance from the house, where we charge a battery from a solar panel.

System Requirements:

  1. Monitor battery status, including voltage, current, and temperature.
  2. Display battery status on an LCD.
  3. Send battery status data to a House PC over Wi-Fi.
  4. The system consists of a microcontroller, LCD, buttons, temperature sensor, and an optional RTC (real-time clock) to display the current time and data on the LCD.
  5. Implement functionality to shut down the system via buttons.
  6. Provide emergency alerts, such as in the event of an attempted theft, by sending alert messages to a PC or Android app.

Given these requirements, could you please share your insights on how you would approach this scenario using FreeRTOS?

  1. Task Management: How would you recommend structuring these tasks in a more general sense for a project , which involves tasks for battery status monitoring, LCD display, Wi-Fi communication, and handling emergency alerts in FreeRTOS?
  2. Resource Sharing: what are resources and What strategies would you recommend for efficiently sharing resources.
  3. Interrupt Handling: did you handle interrupts in your project, especially those related to button or user input
  4. Task Priorities: How did you decide the priority of tasks for project? What would be sequence of priority for different tasks?

I’m keen to learn from your experience, as it you’ve successfully tackled a project with similar elements. Could you please elaborate further on how would tackled this specific challenge?

I’m very interested in understanding the design and development process, especially when it comes to using FreeRTOS to efficiently manage the various tasks and components of this system.

Thank you for your time and for sharing your knowledge!

Thats a huge question, and I feel like I addressed many parts of it at least at a high level in my first reply. Some of your questions relate to basic RTOS concepts so are probably best answered by reading RTOS documentation.

If you had more specific questions to ask then I can try to answer those, but otherwise this would need a “wall of text” response to cover all topics raised.

Could you please share:

  1. The list of tasks in your application.
  2. How many threads or tasks you used.
  3. The priorities assigned to each task.
  4. How you decided task execution time and deadlines time for each tasks.

13 tasks

  • Battery charger logic, priority 1
  • CLI, priority 1
  • Front panel button reader, priority 1
  • LCD controller, priority 1
  • LCD backlight controller, priority 0
  • I2C buffer descriptor handler, priority 2
  • Power measurement task, priority 2
  • LoRaWAN MAC manager, priority 2
  • LoRaWAN message handler, priority 2
  • RTC interrupt handler, priority 3
  • Temperature sensor reader, priority 2
  • User interface, priority 1
  • Watchdog service, priority 3

There are also 3 queues, 2 timers, 3 mutexes, and 1 stream buffer used by these tasks.

I dont really consider execution time, or deadlines. My tasks just run until they are done and start waiting on something. If they run for too long they will be pre-empted by the scheduler. I dont think I have anything that is particularly time critical, but I treat RTC interrupts and watchdog related things with high priority because the RTC interrupts are used to time other things (via alarms that can be subscribed to), and the watchdog needs to keep the system running.

If I have anything close to a deadline I guess it is just that tasks must check in with a watchdog service at least once every 2 seconds to ensure that the system continues running and doesnt get reset. The watchdog service only clears the watchdog timer if all expected tasks have checked in.

As for assigning priorities, I dont have a particularly scientific method. I guess I figured that anything that is just doing “processing work” can run with low priority because it’ll get there eventually. Anything taking readings that the processing tasks rely on runs at a higher priority so that the processing tasks will ideally always have access to the latest values and/or will get their values in a timely manner. And the LCD backlight with no priority - who cares really.

2 Likes