Making robots with Ada
The Lego NXT Mindstorms kit has been extremely popular. Many schools and individuals have kits and third-party components. Even if the latest product is much more capable, the ubiquity and low cost of the NXT Mindstorms components make them an attractive basis for experimental upgrades. In particular, we can upgrade the on-board computer with a new, powerful, very low-cost microcontroller. We can replace the programming language with one used in the most demanding high-integrity applications, such as flight management and full-authority digital engine controllers (FADEC) used on commercial and military aircraft.
The NXT “brick” is the embedded computer system controlling the robots. It consists of an ARM micro-controller and an AVR co-processor. The brick enclosure provides an LCD screen, a speaker, Bluetooth, and four user-buttons, combined with the electronics required to interface to the external world. The result is a convenient, effective package (Figure 1):
Figure 1. NXT Brick (Source: Lego.com)
Bricks are programmed with a graphical language intended for children learning to program a computer, but the lack of expressive power quickly becomes limiting for more sophisticated programs. Multiple mainstream programming languages are available from third-party providers and are widely used.
The brick’s microcontrollers present another limitation. The ARM is a 48 MHz ARMv7, with 256 KB of FLASH and 64 KB of RAM. The 8MHz AVR has 4 KB of FLASH and 512 bytes of RAM. In contrast, very inexpensive ARM evaluation boards, available from many vendors, are considerably more powerful and have more memory. The STM32F4 Discovery Kit from STMicroelectronics, for example, provides an ARM Cortex-M4 running at up to 168 MHz, with a megabyte of FLASH and 192 KB of RAM, for approximately $15. There are several Discovery Kits available, with varying amounts of memory and devices on-board. Other ARM vendors offer evaluation boards with similar capabilities.
In addition to a modern processor, the STM Discovery Kits 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. For example, the STM32F4 Discovery Kit includes an accelerometer, an audio DAC and speaker driver, a digital microphone, four user LEDs, and a user pushbutton. The STM32F429I Discovery has a gyroscope and an LCD screen, as well as much more FLASH and RAM. All kits include extension headers to connect these devices to external hardware.
The Ada programming language is currently used in many safety-critical and high-integrity applications. If you have flown on a modern commercial airliner the chances are excellent that there was Ada in the critical software on-board. For that matter, Ada is used to develop the air traffic management systems controlling use of the airspace itself in both the United States and much of Europe.
Ada was available in the past as an alternative language for the Mindstorms brick, and at present GNAT implements Ada for newer ARM targets. This includes a freely available GPL version that supports some STM Discovery Kits out-of-the-box. Furthermore, the Mindstorms target was the Ada 2005 version, whereas Ada 2012 is available now. The free toolchain and IDE are available at http://libre.adacore.com/ for download.
Such attractive alternatives make a compelling case for replacing the NXT brick with a modern processor and programming language. This article is the first in a series exploring how to do just that. We will replace the brick with an STM Discovery Kit evaluation board and will use Ada 2012 to interact with the sensors and control the effectors.
We start the series by showing how to interface to the NXT touch sensor, including both the electronic circuit and the software device driver. Subsequent articles will show how to drive the NXT motors and the more complicated sensors, including third-party sensors and those requiring more advanced communication mechanisms. The source code and building instructions will be available on-line via a GitHub repository.
Replacing the Brick
With GNAT we can write application code for the target boards but we need drivers for the timers, UARTs, A/D and D/A converters, and other devices required to replace the NXT brick. The Ada Drivers Library (ADL) provided by AdaCore and the Ada community supplies many of these device drivers. The ADL supports a variety of development platforms from various vendors, although the initial – and currently most extensive – support is for the STM32 series boards. The ADL is available on GitHub for both non-proprietary and commercial use here: https://github.com/AdaCore/Ada_Drivers_Library.
Replacing the brick will also require drivers for the NXT sensors and motors – software that is not included in the ADL. We will illustrate development of these drivers in this article series.
NXT Sensor Support
The first sensor we will explore is the “NXT Touch Sensor” because it is the simplest to implement and highlights a number of issues. Other sensors will require A/D conversion or advanced communication that, although supported by the ADL, are more complex and therefore not ideal starting points. We will explore those in later articles.
External Circuit Required
The NXT Touch Sensor is simply an on-off momentary switch. A two-state input is handled by a “discrete” input to the processor, as opposed to an analog input to be quantized. The General Purpose IO (GPIO) hardware on the board provides these inputs and outputs (both discrete and analog). They are connected to the extension headers on the board.
An external electronic circuit is required to connect the sensor to the board. We can select one of the GPIO pins and connect the sensor to the corresponding header pin with a jumper wire. We will also require 3V power and a ground connection, both of which the headers supply.
The circuit will supply power to the sensor switch, with the MCU sensing the relative presence or absence of a voltage on the GPIO pin when the switch is pressed. When the sensed voltage is below a given threshold the signal is said to be “low” and the GPIO bit representing the discrete input is zero. A sensed voltage above the threshold is said to be “high” and in that case the representative bit is a one. The values “high” and “low” are known as “logic levels,” a term we will use in our software later.
Either level can be used to signal the discrete input being “on.” If the input is considered “on” when the signal is high, the input is said to be “active high.” On the other hand, if it is considered “on” when a low voltage is sensed, the input is said to be “active low.” Whether it is active high or active low depends on the circuit connecting the discrete input to the MCU, but the choice must be known to the software.
As you can see, the details of the circuit are important for the software in interpreting the state of the input pin. Merely detecting whether the pin is high or low is not sufficient to know if the input is active. The details are also important to proper function and safety. Done wrong, we will either have an unreliable input or we will potentially damage the power supply. Let’s examine some possible circuits.
We could simply connect the input pin to ground with the switch in between, as shown in figure 2:
Figure 2. Noisy Circuit (Source: Pat Rogers)
Here, the GPIO input pin is connected to the normally-open switch S1. When S1 is pressed the input will be connected to ground and will show a low voltage. If we have specified that this input pin is active low, it will be considered active. Unfortunately, there will be a problem when the switch is not pressed. In that case there is no voltage at all on the input pin, neither high nor low, and so electrical noise in the system may be sensed on the input pin. As a result, the input could fluctuate between high and low, hence between active and inactive. This is clearly an unacceptable result.
We might tie the input pin to the supply voltage instead of ground. This circuit is shown in figure 3:
Figure 3. Short Circuit (Source: Pat Rogers)
Now the problem occurs when the switch is pressed. When S1 closes, the power supply will be shorted directly to ground. “Bad Things” can happen in that case, including burning out the power supply.
To prevent either of the above situations we must alter the circuit to prevent noise from affecting the input readings and to avoid short-circuiting the power supply. A properly sized resistor will do this. The choice is then whether we want the input to be active high or active low.
If we want the input to be active high, we put the resistor next to ground, with the switch next to the power supply. This circuit is shown in figure 4. The input pin will always be connected between the switch and resistor in these figures.
Figure 4. Active High Circuit (Source: Pat Rogers)
Now when the switch is pressed, the input will sense the supply voltage and will be active when configured as an active high input. The resistor will limit the current flow so that the power supply is not potentially damaged. When the switch is not pressed, the pin will be tied to ground so no stray noise will be sensed.
If we want to configure the input to be active low, we swap the positions of the switch and resistor, as shown in figure 5:
Figure 5. Active Low Circuit (Source: Pat Rogers)
In this case, when the switch is pressed the input will sense low voltage, so an active low input would be active as far as the software is concerned. When the switch is not pressed the input will sense the supply voltage. As an active low input it will then be considered inactive.
When the resistor is tied to ground it is known as a “pull-down” resistor. It “pulls” the input’s sensed voltage low. In contrast, when the resistor is tied to the supply voltage it is known as a “pull-up” resistor. It “pulls” the sensed voltage high. The discrete input circuity within the MCU typically has internal pull-up and pull-down resistors for each pin, but these may not always suffice. The resistor selection is part of the software configuration of a GPIO pin.
The Lego NXT brick conveniently contains the required interfacing electronics within the brick itself. We are replacing the entire brick so we will have to provide the circuit, but for the touch sensor that means only that we must connect a resistor in a configuration that matches the logic level specified for the discrete input.
That covers the external circuit. Now let’s examine the software that implements the touch sensor.