Design Article
Open-Source Robotics and Process Control: Sensor, Actuator and Control Circuit Examples - Part 1
Lewin Edwards
8/19/2008 2:42 PM EDT
In this chapter, I will present a few useful "cookbook" applications for real-time control circuits designed to perform some specific low-level task and interface with a master controller for instructions and overmonitoring. For the moment, we will deal principally
with the design and firmware of the peripherals themselves. In the next chapter, you will find more detailed detailed explanations of how to develop Linux code to access these peripherals from an embedded PC-compatible SBC or desktop PC.
The purpose of this chapter is to provide introductory-level information on how to interface with some common robotics-type sensors and actuators, and in particular to show how these can be tied into the type of system we have been discussing. Although the projects are standalone and don't directly develop on each other, you should read at least the description of the stepper motor controller in full, because that section describes how the SPI slave interface is implemented. This information isn't repeated in the descriptions of the other projects.
Note that in this book, we will discuss an overall system configuration where all devices are connected directly to the Linux SBC, as illustrated in Figure 3-1.

Figure 3-1: Simplified system layout.
This configuration is easy to develop and test, and is an excellent basis for many types of projects; in fact, this is how I prototyped all the E-2 hardware. [For more on the E-2 project see the author's E-2 Autonomous Submarine Project webpage.] For the sake of completeness, however, I should point out that in the actual E-2 system, all of the peripherals are connected to a single master controller (an Atmel ATmega128, in fact). This controller is connected to the SBC over an RS-232 link as illustrated in Figure 3-2.

Figure 3-2: Actual E-2 system layout.
The master controller is the real brains of the vehicle. In fact, in E-2 the Linux system can be considered just another peripheral of the master controller. The Linux board performs strictly high-level functions; it interfaces to two USB cameras and an 802.11b WLAN adapter, besides writing the vehicle log on a high-capacity storage medium and performing some computationally intensive tasks such as image analysis and digital spectrum analysis of audio coming in from the exterior microphones. This design is basically an engineering refinement of the system we'll be talking about in this book; discussing it in detail really wouldn't add much to the material you already have here. Pay no attention to that man behind the curtain!
For your convenience (and mine, too!), I have developed rough-and-ready PCB artwork for all the example circuits in this book. The PCB artwork is subject to revision, and as a result is not provided on the CD-ROM; you can download it freely from http://www.zws.com/. The schematics are, however, provided on the disk. In order to edit the PCB layouts or view the schematics from which they are generated, you will need to install the evaluation version of the Cadsoft Eagle PCB CAD package, which is included on the accompanying CD-ROM. Versions for both Windows and Linux are provided.
Please note that these layouts are designed with largely surface-mounted components. This reduces the manufacturing and assembly costs of the PCB (and it also makes routing easier in some circumstances). However, it does make hand-assembly slightly more challenging. The parts I have used can easily be hand-soldered with a little practice, but if you aren't sure of yourself, every part I've used is available in a through-hole version, with the exception of the Analog Devices accelerometer chips.
Ergonomics Tip: A scroll-wheel mouse is highly recommended if you're using Eagle. The wheel controls zoom level. Since the zoom in/out functions are centered on the current position of the mouse cursor, you can navigate all around a large schematic or PCB layout using only the scroll wheel and minimal mouse movements. It's rarely necessary to touch the scroll bars in the Eagle window; it's easier and much faster to zoom out, then zoom back in on the area of interest.
E2BUS PC-Host Interface
3.2 E2BUS PC-Host Interface
Internal control signals in E-2 are carried on a simple SPI-style ("three-wire") interface13 using a 10-conductor connector referred to as the "E2BUS" connector. The PCB layouts I have provided with this book use JST's PH series 2mm-pitch disconnectable crimp type connectors. These are commonly used for inter-board connections in applications such as VCRs, printers and CD-ROM drives; they provide fairly good vibration resistance and they hit an excellent price-performance point, as long as you don't mind investing in the appropriate crimp tool. If, however, you are building these circuits on breadboards, you will probably prefer to use standard 5.08 mm (100 mil) headers.
The E2BUS pinout used by the circuits in this book is:
| Pin | Name | Function |
| 1 | +12 V | +12 VDC regulated supply |
| 2 | GND | Ground |
| 3 | +5 V | +5 VDC regulated supply |
| 4 | GND | Ground |
| 5 | MOSI | SPI data input (to peripheral) |
| 6 | MISO | SPI data input (from peripheral) |
| 7 | SCK | SPI clock |
| 8 | _SSEL | Active low slave device select line |
| 9 | _RESET | Active low reset input |
| 10 | GND | Ground |
E2BUS is specified to carry up to 500 mA on each of the 12 V and 5 V lines. Peripherals that expect to draw more than 500 mA on either rail should have separate power input connectors (the main drive motor controller is one example that falls into this category).
There are two useful things to note about the E2BUS connector:
- It's possible to assemble a cable that will let you connect a PC's parallel port directly to an E2BUS peripheral (at a pinch, you can dispense with buffering and simply run wires direct from the parallel port signals to the E2BUS device). A fairly simple bit-banging piece of software on the PC will allow you to communicate with the peripheral.
- The E2BUS interface brings out all the signals necessary to perform in-system reprogramming of the flash and EEPROM memory of the AVR microcontrollers we are using, so in theory this port could be used to update the code and nonvolatile parameter data, if any, in an E2BUS module without needing to remove the microcontroller. For various reasons, however, it isn't always possible to achieve this with an AVR-based circuit; either because the ISP pins are being used for other functions by the circuit, or because the microcontroller lacks an external clock source (which may be required for in-system programming). However, the connector design is, at least, flexible enough to allow the possibility if you want to take advantage of it.
At this point, you might be wondering why I chose to use SPI rather than, say, I2C (which requires fewer I/O lines and would allow a true "bus" configuration with a single set of signals routed to all peripherals) or CAN, which is better suited for unfriendly environments such as automotive applications. The first reason is code simplicity. CAN and I2C are both, by comparison with SPI, relatively complex protocols. For example, I2C uses bidirectional I/O lines and it's a little complicated to isolate an I2C device from the rest of the bus, because your isolation component needs to understand the state of the bus. I2C is also best suited for applications where a master device is programming registers or memory locations in a slave device. SPI is a slightly better protocol—with virtually no overhead—for peripherals that deliver a constant stream of data.
For the purposes of this book, we'll primarily be talking about controlling E2BUS peripherals directly from the parallel (Centronics) printer port of a PC-compatible running Linux. This is the easiest scenario to describe, and it illustrates all of the required techniques nicely. Following is a schematic for a fairly simple parallel port interface that allows you to connect up to eight SPI-style peripherals to a PC. The schematic for this project is available in the projects/parbus directory on the CDROM. By means of LEDs, the interface shows you which device is currently selected, and activity on the data input and output pins.
Figure 3-3: Parallel port E2BUS interface.
This circuit might appear unnecessarily complicated, but it's really quite simple. The eight data lines from the parallel port are used as select lines for the eight peripherals. These signals are buffered through 74HC244s, the outputs of which are tristated by the parallel port's _STROBE signal. The reason for the tristate control is to reduce the chance of spurious bus transactions while the SBC is performing power-on initialization. Note that this system assumes that the device(s) in use in your peripherals have their own pullup resistors on the select lines. An additional HC244 buffers the same signals to a row of indicator LEDs that show you which device is currently selected. A third HC244 buffers the control signals used for MISO, MOSI and SCK, and additionally drives the _RESET line.
A side benefit of this circuit: If you use 5 V-tolerant, 3.3 V-capable devices where I have specified 74HC244s, you can use the design in Figure 3-3, virtually unmodified, to communicate between a standard 5V-level PC parallel port and external devices that use 3.3 V I/Os.
Footnote:
13. Note that 3-wire SPI is in no way related to "three-wire serial" RS-232 interfaces, which are simply a normal serial connection with only RxD, TxD and ground connected. SPI is a synchronous protocol.
E2BUS PC-Host Interface (cont.)
If you're looking at the schematic I provided on the CD-ROM, you'll observe that my accompanying PCB layout includes a standard right-angle DB25M connector to mate directly with the parallel port on a PC. If you are planning to build some kind of enclosure containing an SBC and connected E2BUS-style peripherals, you might instead consider using a 26-pin, 2 mm or 0.1"-spaced header. Most SBCs use one or other of these connectors for their parallel port.
In fact, you don't need to build this entire circuit to communicate with the projects in this book. If you only want to talk to one peripheral at a time, if you're exceedingly lazy, and if you're willing to take a bit of a risk on port compatibility, you can experiment with a quick-n-dirty cable wired as follows. The left-hand column indicates the E2BUS pin number, and the right-hand number indicates which corresponding signal should be wired on a DB25M connector.
| Pin | Name | Connect to |
| 1 | +12 V | External +12 VDC regulated supply |
| 2 | GND | +12 VDC ground return |
| 3 | +5 V | External +5 VDC regulated supply |
| 4 | GND | +5 VDC ground return |
| 5 | MOSI | Pin 15 of DB25M |
| 6 | MISO | Pins 17 and 13 of DB25M |
| 7 | SCK | Pin 16 of DB25M |
| 8 | _SSEL | Pin 2 of DB25M |
| 9 | _RESET | Pin 14 of DB25M |
| 10 | GND | Ground, pins 18"25 of DB25M |
Be warned - there is absolutely no protection for your computer's parallel port if you use this circuit. If you accidentally short, say, a 24 V motor supply onto one of the parallel lines, you will need a new motherboard. I strongly warn you not to use this quick and dirty hack with a laptop computer, unless it's a disposable $50 laptop you bought off eBay!
Also be warned that the simple cable is substantially less tolerant of variations in the motherboard's parallel port implementation than the full E2BUS interface board. If you find yourself missing transmit or receive bits, or getting garbage data, try adding a rather strong pullup, say 1K, to the SCLK and MOSI lines. If you still have problems, it may be possible to mitigate them by slowing down your data rates, but there will certainly be some trial and error waiting for you.
As I mentioned in the introduction to this chapter, the actual E-2 project isn't structured exactly as I have described in this section, and the principal reason is energy consumption. The PCM-5820 and its dependent peripherals are the greediest power hog in the entire submarine (these modules of the circuit pull considerably more current than both drive motors operating at full speed), and its brains aren't required most of the time on a typical E-2 voyage. For this reason, the master controller on the voyage is another AVR microcontroller - an ATmega128, to be exact.
The peripheral select signals are generated by three GPIOs fed to a 74HC138 1-of8 decoder. However, I originally started the project by connecting the peripherals directly to the SBC in the manner described in Figure 3-1, because it was the easiest way to debug the protocol and the peripherals themselves. For an early prototype, or for any laboratory fixture application that doesn't require battery power, you almost certainly want to do the same thing; it's much less challenging to debug the protocol and front-end interface issues in this configuration.
In the interest of completeness, I should point out one major weakness of the simplified E2BUS design in this book: It relies on the peripherals to perform bus arbitration. The ATtiny26L doesn't implement a full SPI interface in hardware, so the firmware in each peripheral needs to track the state of the select line and manually tristate its serial data output line when deselected. If any module happens to crash in an on-bus state, the entire bus could potentially be brought down. This design flaw could be mitigated to some degree by adding tristate buffers gated by the select line, or by migrating the peripherals to a different microcontroller that implements the full SPI interface in hardware. Also observe carefully that there is no reset generation circuitry on the individual peripheral modules; they rely on receiving an explicit software-generated reset from the attached SBC. A real-world design should implement an external reset generator with brownout detection, to ensure that all modules are reliably reset after a brownout or power-up event.
Host-to-Module Communications Protocol
3.3 Host-to-Module Communications Protocol
The SPI specification only defines the bare outline of the communications protocol, including little more than the physical interface. This is a good thing and a bad thing. It's good, because you can make your protocols as simple as you like - and bad, because it means you have to specify and develop your own high-level protocols!
The basic rules are as follows: Each slave device has an active-low slave select line (SS), a clock input (SCK), a data input (MOSI) and a data output (MISO). Note that the words "input" and "output" here are with reference to the slave device. It is fairly normal practice in schematics of SPI equipment to label the entire "output to slave(s)" net as MOSI and the "input from slave(s)" net as MISO, which can be slightly, and pulse SCK high. At this point we can sample the data stream out of the micro at MISO. Here's a sample waveform where the host is sending the code 0xFE to a peripheral. The top trace is MOSI and the bottom trace is SCK. Note how the pulses have rounded leading edges ("shark fins"). This trace was captured on a system connected using the quick and dirty cable as described previously.

Figure 3-4: Example SPI clock and data signals
The bit cell is approximately 9.6 µs, corresponding to a serial clock rate of 104.2 kHz. This is the fastest speed we can get out of the PCM-5820 using the code in e2bus.c with all timing delays commented out. Note that we're only using half the available bandwidth; it's entirely possible to implement a full-duplex protocol over the interface described in this section.
From a design perspective, you should observe also that for the projects described here, the Linux machine is always the bus master. This is a significant weak point in system reliability, because a crashed Linux box could potentially leave one or more peripheral modules in the "selected" state, listening to random noise coming down the bus. If you plan to implement a real system with this architecture, you should implement hardware and/or firmware interlocks to prevent such occurrences. For example, you could implement a timeout in the routine that monitors the SS line; if there is no SCK within a specified time period from SS going active, the peripheral should assume a crashed master, and go off-bus. Of course, this doesn't help you if the Linux box has pulled the master reset line low. You shouldn't use a configuration like this to control hardware that may need to be "safed" in event of a loss of control, unless you have some other external hardware that can overmonitor the control system and shut things down gracefully if the controller fails.
I have developed a simple piece of Linux code to do all the synchronous serial I/O you will need to talk to these projects. This code is provided in the projects/e2bus directory on the CD-ROM. The meat of this code resides in five simple C functions. Note that these functions assume that your E2BUS interface is connected on the first parallel port. Also note that the timing they exhibit is quite sloppy, since we're not attempting to make Linux appear real time. You should not run this code inside a low-priority thread, because other things will preempt it and may cause spurious timeout problems.
Following are the basic function prototypes:
| Prototype | Description |
| int E2B_Acquire(void) | You must call this function before calling any other E2BUS functions. It attempts to get exclusive access to the first parallel port. It returns 0 for success or "1 for any error. |
| void E2B_Release(void) | You can call this function as part of your at-exit cleanup routines. It ensures that all devices are deselected, and releases the parallel port. If you exit without calling this function, the port will still be released implicitly as your task ceases to exist, but devices may still be selected. |
| void E2B_Reset(void) | Deselects all devices, asserts the reset line on the SPI bus for 250 ms, then pauses for an additional 250 ms before returning. |
| void E2B_Tx_ Bytes(unsigned char *bytes, int count, int device, int deselect-after) | Asserts the select line for the specified device (valid device numbers are 0"7), then clocks out the specified number of bytes one bit at a time. If deselect-after is nonzero, the device is deselected after the transmit operation is complete. Setting this argument to 0 allows you to read back a command response without having to set up a new SPI transaction. |
| void E2B_Rx_ Bytes(unsigned char *bytes, int count, int device, int deselect-after) | Works exactly the same as E2B_Tx_Bytes(), but receives data instead of transmitting it. |
These functions, particularly E2B_Rx_Bytes and E2B_Tx_Bytes, are the low-level underpinnings of the E2BUS protocol. The workings of these functions are described in more detail, along with the complete sourcecode, in Section 4-6.
On the device end, all the example circuits here share pretty much exactly the same code for serial transfer operations, though command processing details are naturally specific to each project. Incoming SPI data is received by the ATtiny26L's USART and processed by a very simple and hence robust state machine. You'll find the states defined at the start of the sourcecode for each project, with constants named FSM_xxxx.
When a device's SEL line is inactive, the state machine is in a quiescent mode (FSM_SLEEP); the MISO pin is set to input mode (to prevent it from driving the bus); clock and data from the USI are ignored, and USI interrupts are disabled. Asserting SEL pushes the state machine into a "listen for command byte" mode, resets the USI, and enables data receive interrupts. The first complete byte received generates an interrupt which causes a state transition. The destination state is determined by the value of the command byte received. The machine may transit through further states depending on whether the command requires additional data bytes or not. If the received command requires additional data, the system proceeds through intermediate states to receive these additional byte(s), and then executes the command before returning to quiescent mode.
If the destination state involves transmitting data back to the host, the data required for transmission is assembled for return to the host, and subsequent USART overflow (or rather, underflow) interrupts clock the data out a byte at a time. After the last reply byte is clocked out, the final underflow interrupt causes a transition back to the quiescent state.
Deasserting SEL at any time immediately disables the USART and tristates MISO. This completely aborts any data transfer or command in progress; any partially received command will be discarded, and partially-transmitted data blocks will be forgotten.
Coming up in Part 2: The stepper motor controller.
Printed with permission from Newnes, a division of Elsevier. Copyright 2004. "Open-Source Robotics and Process Control Cookbook" by Lewin Edwards. For more information about this title and other similar books, please visit www.elsevierdirect.com.
Related links:
Choosing a microcontroller and other design decisions - Part 1 | Part 2 | Part 3
Building flexible architectures for configurable UAV systems
Rolling your own
The lowdown on Embedded Linux and its use in real-time applications: Part 1 | Part 2
How to roll your own Linux




