Making robots with Ada, Part 2 - Driving the motors

In part one of this series, we introduced the idea of replacing the Lego Mindstorms NXT® Brick with a low-cost ARM evaluation board so that we can reuse the NXT sensors and effectors with a much more powerful hardware and software platform.

Our replacement hardware is one of the very inexpensive “Discovery Kit” products from STMicroelectronics. (Similar boards are available from other vendors as well.) The Discovery Kits have ARM Cortex processors, with the specific processor and memory available depending on the kit. The MCUs on these boards include many on-package devices for interfacing to the external world, including A/D and D/A converters, timers, UARTs, DMA controllers, I2C and SPI communication, and others. Sophisticated external components are also included, depending upon the specific kit. For example, in the previous article’s demonstration we used the STM32F429I Discovery Kit which has a Cortex M4 MCU, a gyroscope, and an LCD screen (among others). In this article’s demonstration we don’t particularly need the LCD so we will use the STM32F4 Discovery Kit. It too has a Cortex M4 MCU, with an accelerometer instead of a gyroscope and no LCD. It is even less expensive than the F429I version – approximately $15.

Our industrial-strength programming language is Ada 2012, an object-oriented real-time / embedded-systems language widely used in commercial and military aircraft and high-speed trains, among many other high-integrity applications. If you have flown on a modern commercial airliner the chances are excellent that Ada code was in the critical software on-board. AdaCore’s GNAT technology implements Ada 2012 (the most recent version of the language standard) for newer ARM targets, including a freely available Community edition for students and hobbyists that supports some Discovery Kits out-of-the-box. (Other Discovery Kits are easily ported by users.) This free toolchain, including a full-strength IDE named GPS (GNAT Programming Studio), is available at http://libre.adacore.com/ for download.

In the previous article (part one) we demonstrated how to use a Discovery Kit and Ada to develop an object-oriented interface to the most basic NXT sensor: the touch sensor. Doing so required exploration of the simple external electronic circuit required and its effect on the software design of an API for discrete inputs. In this article we will add a basic interface for driving the NXT motors. Like the touch sensor, interfacing with the motors requires an external circuit so we discuss the requirements and options. Our new demonstration will use the touch sensor to control NXT motor speed, with on-board colored LEDs displaying the relative safety (slow, cruising, fast, red-lining).

Fundamental Language Concepts

The previous article introduced many of the important fundamentals of Ada. Most importantly, we covered “packages,” which are modules providing compile-time visibility control, and “private types,” which are types declared within packages in a specific way so that the types’ representations are hidden from clients. The combination of a package and a private type, along with associated operations, is used to implement abstract data types (ADTs), one of the most important and pervasive concepts in programming. ADTs are perhaps the key concept in Ada, much as using the notions of protected and private declarations for visibility control are central to class-oriented languages. We also introduced the notion of “generic units,” which are similar in concept to “templates” in C++ and other languages. We introduced object-oriented programming in Ada, and how to choose between, and implement, “interface inheritance” and “implementation inheritance.” We also introduced the significant concept of contract-based programming in the form of subprogram “preconditions” and “postconditions” that are verified at run-time. All of these concepts were used in the demonstrated program and much will be used in this one as well. That was a lot of material that we will not cover again, however, so please refer to the first article if you have any questions. Note too that free learning material is available on the AdaCore website, at http://university.adacore.com.

Having explained the construction of abstract data types in Ada, we then introduced the Ada Drivers Library (ADL). The ADL provides device drivers, typically in the form of abstract data types, for the timers, UARTs, A/D and D/A converters, GPIO points, and other devices required to replace the NXT brick. The ADL supports a variety of development platforms from various vendors, including STMicroelectronics boards and some Discovery Kits out-of-the-box. The library is available on GitHub for both non-proprietary and commercial use here: https://github.com/AdaCore/Ada_Drivers_Library. Please consider adding new devices and drivers to the library!

Controlling the Motors

NXT Motors

There are a number of Lego motors available, but we focus on those included with the Mindstorms kit. These are 9-volt DC motors with significant gear reduction, producing high torque, and a precise rotation sensor. The motors rotate at a rate relative to the power applied, and can rotate in either direction. The polarity of the power lines controls the direction: positive rotates one way, negative rotates the other way.

Figure 1: NXT motor internals. (Source: LEGO)

Figure 1 illustrates the partial internals of the NXT motor, including the gear train in light blue, and the rotation sensor at the far left, in dark blue, next to the motor itself in orange. Comprehensive information about these motors is available from this excellent web site: http://www.philohome.com/nxtmotor/nxtmotor.htm.

We mentioned that the polarity of the applied power determines the rotation direction. That polarity control requires an external circuit, specifically an ‘H-bridge” circuit that allows us to achieve that effect.

Figure 2 shows the functional layout of the H-bridge circuit, in particular the arrangement of the four switches S1 through S4 around the motor M. By selectively closing two switches and leaving the other two open we can control the direction of the current flow, and thereby control the direction of the motor rotation.

Figure 3 illustrates two of the three possible switch configurations. The red line shows the current flow. Another option is to close two switches on the same side and end, in which case the rotor will “lock” in place. Opening all the switches removes all power and thus does not cause rotation. The fourth possible combination, in which all switches are closed, is not used.