Lessons from Real-Time Programming class

Lessons from Real-Time Programming class

This post is about lessons I learnt in CS452 Real-Time Programming, a 4th year undergraduate class at the University of Waterloo. Better known as “trains” or “realtime” class.

“Easy stuff! You play with trains all day (literally, maybe even night). All you need to do is write one simple program to control multiple trains so they don’t crash!”

— chko on BirdCourses.com

The trains lab. Room 3018, 3rd floor Math & Computer building.

The class is a bit unconventional because it indirectly teaches other topics, like time management and teamwork, by providing a large amount of work — so that you have to learn these skills. I’ll talk about these lessons, hoping to address a more general audience.

History

This class has been around since at least the 80’s. Currently Bill Cowanteaches this class, and has been for over 20 years.

The equipment have evolved since then, but the underlying challenges have not.

For example, teamwork, setting priorities, and dealing with real (imperfect) systems.

Prof. Bill Cowan explains the why sensor pickup sometimes have trouble detecting slow moving trains. The gap between the contact points may cause the pickup switch to flip twice.

The early version of the QNX real-time operating system took off from a pair of students taking this class, Gordon Bell and Dan Dodge. They decided to expand the class project into a full-fledged commercial RTOS (real time operating system).

“You should try to find a partner for this class, it’ll be hard without one. Generally I’ve seen two outcomes:
(1) you become friends with your partner, or
(2) you stop being friends and hate each other.
I recommend not starting with a partner who is your friend, because you are already friends. Don’t risk it.”

— Prof. Bill Cowan

Curriculum

About 65% of the class involves building a small embedded kernel, with the other 35% working on the train management application.

You can choose to program in whatever language you want, because there aren’t any standard libraries provided. People generally program in C, because it’s known as a systems language, and the programming examples given in class. But there’s no reason why you can’t do it in Rust language, for example — although godspeed, you’re venturing into uncharted territory!

The kernel runs on a TS-7200 embedded system, and it talks to a Märklin Train System over RS232 type serial. The firmware is loaded on via RedBoot, a bootstrap environment for embedded systems.

The Märklin Train System. You can see the center console where the RS232 is attached. Off to the right is the grey box that houses the TS-7200.

The final exam is a take home 24 hour long exam, where you can use any resources you want, and you only need to do 3 of the 5 questions. The assignments and kernel make up 70% of the grade.

Optional Technical Info

The microkernel did very little; it

  • only kickstarts a couple of initial processes.
  • handled message passing between processes.
  • provided very basic interrupt handler and clock.
  • supports realtime operations; the scheduler is predictable (through priorities, and pre-emption).
  • avoided disk IO by loading kernel and programs into RAM directly.
  • needed to provide serial output to a PC terminal, to display graphics relating to the real-time actions being controlled, such as displaying position of trains on the track showing movement.

The realtime program is probably more work than the kernel. Because initially there were many constraints, but later on, assignments were of more guidelines than objectives.


Lessons

I’ll talk about some of the lessons I learnt, and provide some reasoning or backstory to them.

Don’t trust anything. Don’t make any assumptions.

One assumption that was made was while building a acceleration and deceleration profile for the train — that the train would stop where we expected to. Calibration was done by running the train at full speed around the tracks, and when it hits a sensor, tell it to stop.

That assumption turned out false: at max speed, the train varies its stopping distance quite a bit, up to ±3 cm. Not only that, the train accelerates and decelerates non-linearly!

Real systems are often imprecise. For example, look at the stopping distance of a train. In our experiments, it never stops in the same place — for a variety of reasons: such as buffering, interrupt handling, incorrect system timing.

This meant that over the course of several start and stop move commands, there can accumulate quite a difference between where you think the train is, and where it actually is.

Consequently, our model couldn’t be trusted. We’d assume it was safe to perform a certain operation, and it of course, wouldn’t be. And that causes accidents like multi-track drifting to occur.

Multi-track drifting. Happens when a track switch flips direction while the train has yet to clear both axles.

Multi-track drifting is when you thought it was safe to flip a switch, and then it wasn’t. The poor train comes to a sudden stop because the front axles and rear axles are going to different directions.

When your model of the world and the real world itself are different, you get problems. We couldn’t trust our model. We’d assume it was safe to perform a certain operation, thinking we knew where the train was, and it wasn’t safe.

This explains the comic that is pasted on the walls beside the train set. Now I get it!

A printed out version of this comic was taped to the wall beside the train tracks. The original multi-track drifting.

If this was a real train, this would result it some serious accidents. A lesson we learnt after trying to figure out how this happened.

Assumptions are going to be wrong! So it’s important to build in error correction and recovery.

Often assumptions are wrong, or become wrong during the course of real life usage. Real systems don’t always run in your ideal situations. You can’t always think of all the edge-cases. Errors are going to happen. Your best chance is to try to realize the error as early as possible and correct for it.

Instead of eagerly switching tracks for the next train, we switched tracks only if the train had ownership of the track.

Map of the train switches and segments. We had two tracks, A and B, and they have different configurations. We hard coded the map to build the train track reservation system.

To solve this, we ended up building in margin of error around where we think the train is, assigned the train to have ownership to tracks, and made sure when trains approach tracks that they didn’t own, it would stop.

You are as only good as your tools.

Building the path/route finding portion of the project, we were manually reading a map and trying to reason about what the shortest ways were. This took a long time, and felt complicated.

Route a train from point A to point B was not difficult, but factoring in what paths are currently, or will be, blocked by other trains made it harder. We often stared at the layout map for a long time, trying to figure out whether this was the quickest path through this or not.

This is the track layout map. It’s easy to find the shortest path visually, for one train. Now try imagine putting more trains on here. After two trains, becomes pretty difficult. Trains probably need to negotiate with each other, and it’s not enough to try to all take the shortest path.

After staring at this for a long time, and it was clear that reading a map like felt a lot of work. Time to make our life easier.

This map contains the same information as the track layout map, but represented as a tree. This way, we can easily figure out what were shortest paths by counting the least number of moves. This tree factored in backwards movements as well. Because point A and point B may be most easily reached by reversing direction.

This tree map didn’t take much more effort, it was generated by GraphViz in the Dot language.

Tools empower you to be more productive. As a programmer, you’re always thinking about how to make things automated, and easier. A commonly seen trait that programmers have is to be lazy, a desire to automate things and make their own lives easier. Determine how much time you spent doing some work, and see if you can build a tool to make it easier.

Invest in building better tools when you find yourself repeating a task, as a rule of thumb, more than three times.

It’s ok to take on technical debt. Keep it simple, stupid.™

For example, having fancy colorful terminals. Ours was initially very pretty, but we noticed a lot of things had to be changed. Towards the end of the projects, we had avoided building fancy graphics because they took a lot of work and are likely to be changed later.

If you wanted to have pretty looking terminals, lot of time had to be dedicated for it. If you’re really bored, and have time to kill, I suppose it’s fine.

Our colorful terminal. It was all pretty, initially. Later on, we couldn’t afford much time to make things look good.

Later on, we took on more technical debts with screen drawing. It no longer looked as nice, but it worked.

If there are technical debts with higher priority, they should be addressed before diving into a lesser problem.

This sounds intuitive, but sometimes people become irrational and just spend time on low priority issues. Like making things look pretty.

Pair programming is effective teamworking.

Initially we dividing up projects, and mostly worked separately. This was okay for well-defined problems, as it was the case for initial kernel implementation. But later on, the problems we needed to solve became so inter-dependent that it was no longer feasible to build something in the dark.

Many quick idea iterations were needed, and we needed each other to bounce ideas around. Having a comfy couch is important!

And towards the end, we were doing pair programming out of despair; we had to write working code, and we had to write it fast.

Pair programming produces quality code that is better thought out, and a rate that is comparable, if not faster, to separating out tasks and doing code reviews.

Summary

I think taking this class was very valuable, and was a very nice way to wrap up my Computer Science undergrad.

These lessons are ingrained in my memories, and helped shape my behavior.

For example, after pair programming, I subconsciously debate about solutions to problems and bounce ideas around. To an outsider, it may seem argumentative, but it’s really an effective way to solve problems.

Thank you for reading.

Lessons from Real-Time Programming class

This post is about lessons I learnt in CS452 Real-Time Programming, a 4th year undergraduate class at the University of Waterloo. Better known as “trains” or “realtime” class.

“Easy stuff! You play with trains all day (literally, maybe even night). All you need to do is write one simple program to control multiple trains so they don’t crash!”

— chko on BirdCourses.com

The trains lab. Room 3018, 3rd floor Math & Computer building.

The class is a bit unconventional because it indirectly teaches other topics, like time management and teamwork, by providing a large amount of work — so that you have to learn these skills. I’ll talk about these lessons, hoping to address a more general audience.

History

This class has been around since at least the 80’s. Currently Bill Cowan teaches this class, and has been for over 20 years.

The equipment have evolved since then, but the underlying challenges have not.

For example, teamwork, setting priorities, and dealing with real (imperfect) systems.

Prof. Bill Cowan explains the why sensor pickup sometimes have trouble detecting slow moving trains. The gap between the contact points may cause the pickup switch to flip twice.

The early version of the QNX real-time operating system took off from a pair of students taking this class, Gordon Bell and Dan Dodge. They decided to expand the class project into a full-fledged commercial RTOS (real time operating system).

“You should try to find a partner for this class, it’ll be hard without one. Generally I’ve seen two outcomes:
(1) you become friends with your partner, or
(2) you stop being friends and hate each other.
I recommend not starting with a partner who is your friend, because you are already friends. Don’t risk it.”

— Prof. Bill Cowan

Curriculum

About 65% of the class involves building a small embedded kernel, with the other 35% working on the train management application.

You can choose to program in whatever language you want, because there aren’t any standard libraries provided. People generally program in C, because it’s known as a systems language, and the programming examples given in class. But there’s no reason why you can’t do it in Rust language, for example — although godspeed, you’re venturing into uncharted territory!

The kernel runs on a TS-7200 embedded system, and it talks to a Märklin Train System over RS232 type serial. The firmware is loaded on via RedBoot, a bootstrap environment for embedded systems.

The Märklin Train System. You can see the center console where the RS232 is attached. Off to the right is the grey box that houses the TS-7200.

The final exam is a take home 24 hour long exam, where you can use any resources you want, and you only need to do 3 of the 5 questions. The assignments and kernel make up 70% of the grade.

Optional Technical Info

The microkernel did very little; it

  • only kickstarts a couple of initial processes.
  • handled message passing between processes.
  • provided very basic interrupt handler and clock.
  • supports realtime operations; the scheduler is predictable (through priorities, and pre-emption).
  • avoided disk IO by loading kernel and programs into RAM directly.
  • needed to provide serial output to a PC terminal, to display graphics relating to the real-time actions being controlled, such as displaying position of trains on the track showing movement.

The realtime program is probably more work than the kernel. Because initially there were many constraints, but later on, assignments were of more guidelines than objectives.

Lessons

I’ll talk about some of the lessons I learnt, and provide some reasoning or backstory to them.

Don’t trust anything. Don’t make any assumptions.

One assumption that was made was while building a acceleration and deceleration profile for the train — that the train would stop where we expected to. Calibration was done by running the train at full speed around the tracks, and when it hits a sensor, tell it to stop.

That assumption turned out false: at max speed, the train varies its stopping distance quite a bit, up to ±3 cm. Not only that, the train accelerates and decelerates non-linearly!

Real systems are often imprecise. For example, look at the stopping distance of a train. In our experiments, it never stops in the same place — for a variety of reasons: such as buffering, interrupt handling, incorrect system timing.

This meant that over the course of several start and stop move commands, there can accumulate quite a difference between where you think the train is, and where it actually is.

Consequently, our model couldn’t be trusted. We’d assume it was safe to perform a certain operation, and it of course, wouldn’t be. And that causes accidents like multi-track drifting to occur.

Multi-track drifting. Happens when a track switch flips direction while the train has yet to clear both axles.

Multi-track drifting is when you thought it was safe to flip a switch, and then it wasn’t. The poor train comes to a sudden stop because the front axles and rear axles are going to different directions.

When your model of the world and the real world itself are different, you get problems. We couldn’t trust our model. We’d assume it was safe to perform a certain operation, thinking we knew where the train was, and it wasn’t safe.

This explains the comic that is pasted on the walls beside the train set. Now I get it!

A printed out version of this comic was taped to the wall beside the train tracks. The original multi-track drifting.

If this was a real train, this would result it some serious accidents. A lesson we learnt after trying to figure out how this happened.

Assumptions are going to be wrong! So it’s important to build in error correction and recovery.

Often assumptions are wrong, or become wrong during the course of real life usage. Real systems don’t always run in your ideal situations. You can’t always think of all the edge-cases. Errors are going to happen. Your best chance is to try to realize the error as early as possible and correct for it.

Instead of eagerly switching tracks for the next train, we switched tracks only if the train had ownership of the track.

Map of the train switches and segments. We had two tracks, A and B, and they have different configurations. We hard coded the map to build the train track reservation system.

To solve this, we ended up building in margin of error around where we think the train is, assigned the train to have ownership to tracks, and made sure when trains approach tracks that they didn’t own, it would stop.

You are as only good as your tools.

Building the path/route finding portion of the project, we were manually reading a map and trying to reason about what the shortest ways were. This took a long time, and felt complicated.

Route a train from point A to point was not difficult, but factoring in what paths are currently, or will be, blocked by other trains made it harder. We often stared at the layout map for a long time, trying to figure out whether this was the quickest path through this or not.

This is the track layout map. It’s easy to find the shortest path visually, for one train. Now try imagine putting more trains on here. After two trains, becomes pretty difficult. Trains probably need to negotiate with each other, and it’s not enough to try to all take the shortest path.

After staring at this for a long time, and it was clear that reading a map like felt a lot of work. Time to make our life easier.

This map contains the same information as the track layout map, but represented as a tree. This way, we can easily figure out what were shortest paths by counting the least number of moves. This tree factored in backwards movements as well. Because point A and point B may be most easily reached by reversing direction.

This tree map didn’t take much more effort, it was generated by GraphViz in the Dot language.

Tools empower you to be more productive. As a programmer, you’re always thinking about how to make things automated, and easier. A commonly seen trait that programmers have is to be lazy, a desire to automate things and make their own lives easier. Determine how much time you spent doing some work, and see if you can build a tool to make it easier.

Invest in building better tools when you find yourself repeating a task, as a rule of thumb, more than three times.

It’s ok to take on technical debt. Keep it simple, stupid.™

For example, having fancy colorful terminals. Ours was initially very pretty, but we noticed a lot of things had to be changed. Towards the end of the projects, we had avoided building fancy graphics because they took a lot of work and are likely to be changed later.

If you wanted to have pretty looking terminals, lot of time had to be dedicated for it. If you’re really bored, and have time to kill, I suppose it’s fine.

Our colorful terminal. It was all pretty, initially. Later on, we couldn’t afford much time to make things look good.

Later on, we took on more technical debts with screen drawing. It no longer looked as nice, but it worked.

If there are technical debts with higher priority, they should be addressed before diving into a lesser problem.

This sounds intuitive, but sometimes people become irrational and just spend time on low priority issues. Like making things look pretty.

Pair programming is effective teamworking.

Initially we dividing up projects, and mostly worked separately. This was okay for well-defined problems, as it was the case for initial kernel implementation. But later on, the problems we needed to solve became so inter-dependent that it was no longer feasible to build something in the dark.

Many quick idea iterations were needed, and we needed each other to bounce ideas around. Having a comfy couch is important!

And towards the end, we were doing pair programming out of despair; we had to write working code, and we had to write it fast.

Pair programming produces quality code that is better thought out, and a rate that is comparable, if not faster, to separating out tasks and doing code reviews.

Summary

I think taking this class was very valuable, and was a very nice way to wrap up my Computer Science undergrad.

These lessons are ingrained in my memories, and helped shape my behavior.

For example, after pair programming, I subconsciously debate about solutions to problems and bounce ideas around. To an outsider, it may seem argumentative, but it’s really an effective way to solve problems.

Thank you for reading.

PS.

Feel free to reach out to me with any thoughts, and follow the discussion on reddit.

On planning for the future

Growing up, I looked up to a lot of heroes for motivation, and Steve Jobs is one such inspirational hero for me. He was influential to a lot of the values I hold true today. I had read his autobiography – multiple times – and I think it is one of the best books I’ve read. I wish I had been able to be join Apple while he was still around, to work with him, and experience the reality distortion field™ in person.

Most of the conversation I have with my friends and family would generally contain topics of what my ideas are, and how I plan to achieve them. They are interest in what my values are, how I make decisions. Usually I end up paraphrasing things that I’ve before, to others.

I want to summarize some of the principles I hold, as best as I could. Hopefully I don’t forget too much.

Principles

On What You Should Do

In the FB post, I talked about two principles (that help decide what you should do).

  1. Do the things that inspire you, that you love, and
  2. try to be really good at it, hopefully having commitment and courage to do it.

Let me elaborate on this, and then talk about some additional principles for how to get you to the goals you want.

Firstly, by doing the things that inspire you and that you love, this results in personal satisfaction. It’s very important, because it keeps you motivated for when the problems get tough – and there are going to be a lot of tough problems.

Anything worth doing is going to be difficult.

Of course, the assumption is that these things that you do are going to be creating value; whether it be for yourself or others. Just don’t use this as an excuse for binge playing video games, or binge watching Netflix.

Secondly, trying to be really good at it is important for you to create something of value. It’s important to have both breadth and depth – and being good at something gives you depth, a competitive edge over others.

Sure, there may be others that are smarter than you. But they have only 24 hours in a day, just as you do. So that places a limit on what others can possibly do, during their spare time. You don’t have to be the smartest to have a competitive edge – it’s sufficient to excel at skill, albeit seemingly small.

Commitment and courage are other necessary conditions to developing the skill necessary. You should already have the motivation and desire to pursuit something you like doing; whether it be solving a problem or becoming really good in a skill.

The second point complements the first.

These two principles are just about sufficient to be a guide on how to decide what to do, what your next target is, but not how to get there.

On How To Get There

Now that the objectives have been set, what determines the success of it is how to get there.

  1. Manage your free time. We all have 24 hours, how that time is spent that really matters.
    • Identify things that you should invest your time in, in order to reap the fruits of your labor.
    • But also balance life and work. Allocate your most valuable resource, your time, well – with significant others, working out, even video games. The important concept is moderation. For example, watching a season of Netflix is probably no use to getting to your goal.
  2. Read more. Non-fiction. On topics that immediately relevant to you.
    • The value of information depends on context. If I told you what the stock price of some company would be in the future, that would be very valuable; on the other hand, stock price in the past is less valuable.
    • Knowledge is key. Sharing knowledge is also key. Don’t forget about your peers.
    • Reading can give you a head start, often what your peers cannot obtain. Compared to others, you are making more informed decisions, better strategies and tactics. Against competition, even the smallest leverage or advantage makes a difference.
  3. Build projects. Develop your skills.
    • But don’t work in isolation. Get feedback to improve faster.
    • Success and failure doesn’t matter as much; there are things to be learnt even within failures.
  4. Network with others, build your connections.
    • The brain’s neurons work with others to achieve a common goal. A single neuron can’t achieve much on its own. As I said earlier, anything worth doing is going to be difficult. And difficult things need more resources to be tackled.
    • In machine learning, a neural network is inspired by the neuron architecture. When you learn, you are making new connections; and when you practice, you are strengthening the connections.
    • A strong network makes you better informed, helps you get relevant information quicker, creates more opportunities.
  5. Start today, rather than tomorrow.
    • Why is today such a good place to start? Starting today gives you a head start than starting tomorrow. And since you didn’t start yesterday, then today is the optimal day.
    • Take a small step, begin by just doing a little. Great accomplishments don’t happen overnight. Great Wall of China wasn’t built in a day.

That’s all for now folks. Thanks for reading!

PS:

I’m writing this while at the Starbucks on El Camino Real near my house, and coffee’s power is fading. I will try to contribute and share knowledge more often.

If you found this blog to be useful, let me know! My email is jason@sunapi386.ca and Facebook is https://www.facebook.com/sunapi386 – feel free to contact me.

Music: Driftmoon.