Note: This web page contains an introductory technical description of the Robot Controller. The full details can be found in the downloadable .pdf version avaliable on the Downloads page.
The main idea in this project is to develop a stand-alone circuit board and code that controls several (up to 32) RC servo motors. The board is intended to be used for robots or other electromechanical devices requiring a relatively large number of RC servos. The board is stand-alone, meaning that it can be programmed directly using standard tools for Atmel AVR development, and does not require commands from an external board, such as an Arduino or a Raspberry pi.
It is assumed that the reader has basic knowledge about embedded development in general, and specifically about Atmel AVR development, both in C and assembly (gnu toolchain). Furthermore, it is assumed that the reader is familiar with servo motors and their control pulses and power connections.
This circuit's main functionality consists of two main parts, each controlled by an Atmel ATmega168 (or alternatively ATmega328). They communicate via SPI serial interface, and is each responsible for the following tasks:
The software consists of two separate Atmel Studio projects, one for each of the microcontrollers. See User Manual for further details.
Robot Controller AVR and programming interface
This chapter aims at giving the sufficient background needed to program the Robot Controller. Programming the robot controller is ultimately about writing functions that generate timer values that correspond to the durations of the servo control pulses to each servo. The pulses must be generated in a synchronized manner, to obtain the desired movements.
The process of updating timer values in the Robot Controller AVR is highly interrupt driven in order to ease synchronization with the generation of the physical servo control pulses in the Pulse controller AVR. Most of the work in the Robot Controller AVR is done in the ISR(SPI_STC_vect) ISR (Interrupt Service Routine). The cycle of interrupts is repeated every 20ms, which corresponds to the period of the servo control pulses. This means that all robot functions must be called directly from the ISR(SPI_STC_vect) ISR in order to update the timer values with correct timing.
The generated timer values must be given in microseconds, which corresponds directly to the duration of the servo control pulse. The programmer must know exactly how the pulse duration corresponds to the angular position for each type of servo that is used. This can be specified as #define’s in the Robots.h header file.
Main ISR (Interrupt Service Routine)
As described in the introduction, all the timer values are generated in the Robot Controller AVR and transmitted over SPI interface to the Pulse Controller AVR, every 20ms. The transmission is initiated by the Pulse Controller AVR, which is the SPI master device, by sending a dummy byte. This in turn triggers an STC (SPI Transmission Complete) interrupt on the Robot Controller AVR. The ISR(SPI_STC_vect) ISR then performs the following main tasks, every 20ms:
Calling robot functions
The user-programmed robot functions, generating timer values for the servo control pulses, are generally called from within the ISR(SPI_STC_vect) ISR, as illustrated in Figur 2.
There is also a main() loop, as is mandatory in any C program.
In this loop tasks that are not timing critical, or tasks that takes too long to be placed in the 20ms ISR loop can be handled. An example is the reading of potentiometers or other analog sensors read by the ADC (Analog to Digital Converter) can be place.
Currently, all functions handling the ADC inputs are placed in the main loop.
Data array transmitted over SPI
As described above, the Robot Controller AVR contains the robot control functionality. Ultimately, these functions generate the servo pulse lengths for each of the 32 servo motors, in microseconds. These 16-bit values are stored in the array input_register, where each of the two columns contain the high and low bytes for each timer value. In addition, the last four elements in this array contains the values in the array servo_mask. This array contains bytes where the individual bits are used to disable (bit=0) or enable (bit=1) individual servos in each shift register. The Robot Controller MCU is an SPI slave, and on the periodic (every 20ms) request from the SPI master, it transmits the array input_register over SPI.
Pulse Controller AVR, is responsible initiating and controlling the transmission of the timer values from the Robot Controller MCU, as described above. It continuously sends dummy bytes over ISP, and receives the timer value bytes in return. It writes the values to an array input_register, which is identical to the array in Robot Controller AVR. Subsequently, these values are transferred to other arrays and used in the further processing and generation of the physical servo control pulses.
Servo motor parameters
For each servo, a set of parameters must be defined. These parameters are stored in the array servo, with one element for each of the 32 servos. The array consists of elements of the type struct servo_data. Currently, the parameters for each servo are:
The following initialization takes place before the main() loop and the ISR(SPI_STC_vect) ISR starts running:
In addition, the physical position of each servo is initiated in sequence, to avoid the large current surge that would appear if all motors were enabled simultaneously. This is done as soon as interrupts are enabled, by the ISR(SPI_STC_vect) ISR checking if servo initialization is in progress, and if so calls the init_servo_position() function.
Detailed description and design
A detailed description of the technical design can be found in the .pdf version available on the Downloads page
Click to enlarge images below