Why Arduino is not the right educational tool

Hack van de dam

I could have started with ‘why the Arduino sucks’ or ‘why the Arduino is bad’, which would have gotten me a tremendous load of page views. But I didn’t because it simply isnt’t true. The Arduino does not ‘suck’, and neither is it bad in its own right. It just isn’t the right tool to teach people programming, but it’s abused that way. Let me tell you why:

What is the Arduino?

“Arduino is an open-source electronics prototyping platform based on flexible, easy-to-use hardware and software. It’s intended for artists, designers, hobbyists, and anyone interested in creating interactive objects or environments.” There. I just copy-pasted that from [1]. And they’re right! The Arduino project is great for creating interactive objects or environments. You’ve got a gazillion of code examples to use, you can easily read out sensors that would take hours to days to get going (even with coding experience) and a large user base to ask questions. Above all, creating interactive objects or environments is about human interaction (fun!). Hook up a sensor to an actuator, create new combinations and play around… But it’s NOT a good standard to learn coding, or benefit from the power of embedded electronics.

And that’s where I’m bearing a grudge to the use of Arduino’s as a ‘getting started with programming’. Learning to work with microcontrollers is sometimes a steep pathway, but leverages the power of these little beasts. Using an Arduino to learn programming is like using MacDonalds to learn cooking; you get your meal, very fast, but you don’t get the skills to cook yourself. When you need a quick meal, the Mac can be OK (debatable, but just to make my point), but it’s not a cooking class.

5 reasons why, in no particular order:

1. No project space / code partioning / decent IDE

To me this is a great nuisance; I understand you don’t want to overwhelm novices with options, but the Arduino IDE ridicules decent code writing. Maybe you’re supposed to bend your knees that they’ve included color highlighting of variables, but come on, if you want to write decent code, at least give the option to look up variable definitions. See what that looks like below, in a screenshot from Code::Blocks [2]. Another, somewhat related point is that you’re supposed to write all your code in one ‘sketch’ (Figure 1). When you want to write any substantial program, with functions you’d like to be able to use later on, good practice (or even complimentary practice) is to create modular pieces of code. Writing everything in one long file is going straight against that objective, and stimulates writing ‘spaghetti code’, with definitions of variables everywhere and nowhere.

Why Arduino is not the right educational tool
Figure 1. Option to look up variable definitions in Code::Blocks.

The concept of why header files are important is described here [3]. Another good discussion and fast ‘howto’ is written in here (read the discussion!). Also, a great document describing why and how modularizing your code is great can be found on this post at embedded.com. To get a good understanding of ‘how it’s done right’, please take a look at this very clear document from MIT [4] regarding header files:

“A well organized C program has a good choice of modules, and properly constructed header files that make it easy to understand and access the functionality in a module. They also help ensure that the program is using the same declarations and definitions of all of the program components. This is important because compilers and linkers need help in enforcing the One Definition Rule.”

Being able to look up the definitions and implementations of files is a great help in writing modularized code. The Arduino IDE does not provide an easy way to create other c / h files, nor does it enable looking up the definitions of it’s own code (what does ‘digitalWrite’ actually do?). When learning to program C, PLEASE learn to use header files appropriately!

2. Bad abstractions / naming

The Arduino ‘programming language’ uses a lot of predefined functions to use peripherals of the Arduino. A lot of these functions use misguiding names or use bad abstractions, simply not describing what they’re doing. Good hardware abstraction saves the end user from fiddling a lot, bad hardware abstraction confuses. A few examples:

  1. analogWrite(int):
    “writes an analog value (PWM) to a pin”. You say what? PWM is analog? It’s as much analog as a CD contains analog information. Pulse width modulation is NOT analog; the rate is ‘approximately’ 490 Hz, and no clues are given to what RC combination you should use to make it analog. This is misguiding; good enough for a LED but it’s not the ‘Analog’ you’d like to use as a setpoint for an analog control system.
     
  2. OK, and if you generate PWM, at LEAST let me be able to set the PWM frequency.
     
  3. pinMode():
    I have to admit this is fixed now, but a while ago you had the options ‘INPUT’ and ‘OUTPUT’ only. When you wanted to have an input with pullup, you also had to do a digitalWrite() to the pin you just made an INPUT. When you know the AVR architecture, you know that you’re writing the DDRx and PORTx registers, but to a newbie it’s quite strange to ‘write’ to a pin you just made ‘input’ to get a pullup. It’s fixed now, but it took too long; the pinMode function was already available, and it just needed this extra option. This was not abstracting the hardware, but even creating code that will not be able to port nicely to other microcontrollers (which is probably why it was fixed around the time the Due came).
     
  4. Variables:
    why use all the chars, ints, longs, etcetera? Using stdint (uint8_t, uint16_t, int32, …) will give more insight, and more portable code. The int for AVR-GCC is 16-bit, while it is 32-bit for the GNU ARM compiler…
     
  5. Missing abstraction / feature:
    progmem. A lot of people use strings in memory for debugging. Fixed strings could be stored in flash memory and read from that memory, that feature is present in avr-libc. My guess is that 90% of people saying ‘my Arduino is full’ would benefit from adding some kind of keyword.

3. Horrible documentation

Again, this article / rant is based on using it for educational purposes. The documentation on the functions tells nothing about which peripherals are used, not even on a deeper level, hidden away from normal users. I’ve used openFrameworks before, and at least with their IDE you can look in the code how functions are implemented. When using the Arduino, you’re kept dumb. Could I be using a timer while running the servo() functions? Will sending a serial string block my program? Will using analogWrite interfere with other timed functions? You can’t read it in their reference manual.

The Arduino reference also describes its ‘language’. The underlying framework uses some C and some C++ features, both not clearly described. If you want to learn programming, ‘Arduino’ is not the language you’d like to have on your resume, you want to be able to program in C! The difference / equality is not clear, and leads to confusement when going to other microcontrollers or ANSI-C environments. Where are classes used? Where are structs used? I understand that Arduino doesn’t want to scare off new users, but there is no roadmap to ‘advanced’ use.

4. No access to peripherals / wasting resources

I know, you do have access to the peripherals of the Arduino / Atmel chip when you mingle your Arduino code with ‘real’ C and use the Atmel registers. But when you’re that far, please do yourself a pleasure and write your own code, where you know which peripherals are used in which way. When I started programming microcontrollers I was amazed at the speed at which they worked (8 MHz PIC); writing code optimized for the peripherals, using interrupts to do as much parallel as possible showed me what power lies in embedded devices and computers. To me, using the Arduino to learn programming embedded systems takes away that golden edge of creating ‘lean and mean’ applications.

At my current job, people are trying to write control loops using the Arduino; by using the micros() funciton they take the start time of the loop() function, do their tasks, and then poll the micros() function to wait until their loop time has passed. This wastes so much potential for future tasks that should be added, or for processes that are not running at the same timebase. This alone is what makes the mbed better; it’s implementation of ‘Ticker’ functions has its drawbacks, but at least uses interrupt-based timing, leaving the main loop for ‘slow processing’ tasks.

5. No ‘real’ debugging

When the Atmega328 was used no debugging port was available; now the Due is released and the Atmel devices have debug ports from tiny series (DebugWire) to the XMEGA series (PDI and JTAG), this powerfull toolset is kept from the Arduino users. I think development time of applications drops by 30% for me when being able to use a proper debugger setup. At least the ARM could use the OpenOCD implementation, and give power to the programmers. A few breakpoints give a very fast indication of what code is executed, and what error conditions happen. This is where I get very enthusiastic about all new ARM development kits with debugger hardware included. Add arm-gdb and OpenOCD, and you’re up! Setting up those toolchains can be a bit fiddly, but completely worth it when trying to make a decent embedded application.

What’s your alternative?

I think that’s enough for complaining. Your next question should be: how do we educate programming with a good environment? I have several options, all of whom might be worse or more difficult to start with. To get back to my comparison between the Mac and learning to cook yourselves: learning to cook takes someone to teach you. I’ve helped quite a few people to show how to start using other tools, and in general they’re a bit grumpy at the start (why is this so laborious?), and happy in the end (now I understand what’s happening!).

Scratch [5]. To get youngsters to start programming, this is fun, and shows what programs are. It’s fun and easy, and it even enables code partitioning! It’s not embedded though, but if you start out young, this is a good way to learn programming.

Mbed [6]. Now open sourced, this lets you use NXP boards and the inexpensive Freescale Freedom board. Here I’m getting quite enthousiastic. The compiler is online, which is great for novices, as you don’t have to install toolchains. Also a humongous archive of code examples is available that you can easily import into your project. Yes, projects! You can organize and partition your code, and use version control online. The code provided by mbed is C++, using classes and operator overloading, which was a bit confusing for me as ANSI-C-er at first, but the documentation is SO clear, and easily available (again found in your project) that it was more encouraging me to also use those features. Peripherals cannot be used simply, but you can use timers indirectly to generate timing interrupts, and again this is well documented. You don’t like online services? You can also use it offline. The only downside to the mbed for me is that you can’t debug using breakpoints or watchpoints.

AVR-GCC /WinAVR [7], with Xmega series. The AVR-GCC toolchain (with avr-libc) has a respectable reputation and a very good userbase [8]. The reason I recommend the Xmega series is the *fantastic* documentation, the fact that the peripherals each have their own application note, that Atmel Studio is bloated, but gives you the real tools in hands for code partitioning (Goto definition of…), debugging (breakpoints!) and simulation (view bits in peripherals!). When using the (overpriced) Dragon debugger you can debug devices up to 32k code size. Starting with this setup without any coding knowledge might be a bit too steep though, try to get help online, or ask a knowledgeable friend to help out. Reading the application notes just gives me that fizzling feeling that you can make a system that does SO much on its own once you set it up; DMA’s to get ADC values into memory, event system to trigger timers to trigger DACs, etcetera. Quite a bit of work, but than you’re doing embedded-fu. Like making Sushi instead of going to the Mac….

Use Launchpad/STM32/ [9]… Other ARM board. Yes and no here… Yes, ARM is the future, but it’s quite complicated to start with, I think. Also, when using free toolchains you have to put a lot of work into setting up the toolchain. It’s rewarding though; boards with debuggers for takeaway prices (EUR 8 for an STM32F0 Discovery [10] -> Atmel, are you reading this?!), and something to put on your resume: I’ve worked with ARM. The documentation however is mostly poor and frightingly large…. Also, the option set for compilers and IDE’s is so large, that it’s hard to find out why your program is not compiling when it isn’t…

Conclusion

The Arduino is great ‘programming fastfood’: easily available, quick result and sometimes quite tasty. But it isn’t suitable for educating ‘how to program’ or ‘getting performance out of microcontrollers’, or use it as a first step that has an advanced level for enthousiasts. To do that learn real cooking; start with boiling water with scratch, cook potatoes with mbed and make sushi with Atmel to end up going freestyle on the ARM development boards. Now you’re playing with power!

References

coderkick.com