Table of Contents

Algorithms and flowchart

The algorithm is a step-by-step instruction, guideline or rule to performe some action or reach the solution for given problem. Flowchart is one of the way to represent algorithm graphically, where graphical elements like boxes, squares, circles, and arrows connecting them represent flow of control. Every element can represent on step in the instructions.

Simplified flowchart elements:

Start

Circle.

End

Filled circle inside bigger circle.

Action or expression

Rectangle. Inside rectangle a name of the action, name of the sub-routine or short description can be written. Similar actions can be included into one general action.

Sequence

Arrow, by pointing next activity.

Condition / Decision

Diamond (rhombus). Inside diamond is a logical expression and in most cases two arrows are drawn out from diamond. One is when logical expression results True (Yes/1) and other when expression result is False (No/0). Always both arrows have to be labeled. In special case only one arrow can be used as output from diamond. The case is when logical expression can clearly result only one solution, e.g. True. This is the case where for example endless cycle is used in program code (e.g. while (true)).

 

Data exchange

Trapezoid. Inside trapezoid a name or activity is described. In robotics it is usually used to communicate with sensors and user. For simplification also normal rectangle action can be used instead of trapezoid.

Examples

Drawing flowchart diagrams one can use common office suits like MS Word or MS Excel or OpenOffice/LibreOffice Writer or Calc but better results can be get by using special programs like MS Vision, OpenOffice/LibreOffice Draw, Google draw or some special diagram creating software.

Flowcharts describing microcontroller software usually do not have ends, instead whole main activity in an endless cycle. The exit condition of the endless cycle will never be true and therefore this is the case where condition block (diamond) can be represented only on exiting arrow. Condition it self can be notes simply True or 1. Creating diagrams it is important to keep in eye on the fact that if the program has forks, it can be done only through the diamond object. Junctions (two arrows are joining) can be described by special symbol, but in simple cases, one may simply have an arrow point to another arrow instead.

 
Following examples illustrate the use of flowchart elements for describing simple algorithm. First example is simple routine by describing one way flow without any cycle or decision points.

 
Following example describes a system which detects 1 m area and if an object entering into inspected area an alarm is triggered for a 10 seconds. Alarm is working until the object is left from the inspected area.

Sensors

Sensors

Sensors are devices converting any kind of physical attributes (temperature, luminance, force, acceleration etc.) to a understandable form for humans or machines. With the help from sensors the microcontroller receives information from the surrounding environment and makes decisions based on it. There are many types of sensors, approximately 195 different types are listed in Wikipedia. Only sensors with electrical output signal can be connected to microcontrollers. Based on electrical output signal, is possible to segment sensors as digital and analogue sensors.

In analogue sensor any change in physical attributes changes one of its electrical values, usually voltage, current or resistance. Since microcontrollers are digital devices, the signal have to be converted from analogue to digital before delivering it to controller. For this purpose analogue-digital converters are used witch usually are built-in to the microcontroller.

Analogue sensor which already includes digitizer of information, it is called digital sensor. Digital sensors can also standardize information, calibrate sensors and perform a great deal of other functions. There are many ways for transmitting info from digital sensor to microcontroller: the easiest is with logical signals, more complex way – through some data link interface. The following exercises though, are introducing simpler sensors and sensors known in robotics.

Photoresistor

Necessary knowledge: [HW] Sensors Module, [HW] User Interface Module, [ELC] Voltage Divider, [AVR] Analog-to-digital Converter, [LIB] Analog to Digital Converter, [LIB] Graphic LCD, [PRT] IDE Eclipse

Theory

A photoresistor
Electrical symbol for a photoresistor

A photoresistor is a sensor which electrical resistance is altered depending on the light intensity falling on it. The more intense is the light the more free carriers are formed and therefore the lower gets the resistance of the element. Two exterior metal contacts of the photoresistor are reaching through the ceramic base material to the light sensitive membrane, which determines the electrical resistance properties with its geometry and material properties. Since photo sensitive material itself has high resistance, with narrow, curvy track between the electrodes, low total resistance at average light intensity is gained. Similarly to the human eye, the photoresistor is sensitive at certain range of wavelengths and needs to be considered when selecting a photo element, otherwise it may not react to the light source used in the application. Following is simplified list of wavelengths of visible light segmented by colours:

Colour Range of wavelength (nm)
Purple 400 – 450
Blue 450 – 500
Green 500 – 570
Yellow 570 – 590
Orange 590 – 610
Red 610 – 700

A range of working temperature is set for photoresistor. Wishing the sensor to work at different temperatures, precising conversions must be executed, because the resisting properties of the sensors are depending on the temperature of the ambient.

For characterizing light intensiveness physical concept called light intensity (E) is used, this shows the quantity of light reaching any given surface. Measuring unit is lux (lx), where 1 lux represents, the even flow of light 1 lumen, falling on a surface of 1m2. Hardly ever in reality falls light (living area) on a surface evenly and therefore light intensity is reached generally as a average number. Below are few examples of light intensity:

 
Values of light intensity for comparison:

Environment Intensity of light (lx)
Full moon 0,1
Dusk 1
Auditorium 10
Class room 30
Sunset or sunrise 400
Operating room (hospital) 500 - 1000
Direct sun light 10000

Practice

The Sensor module in the HomeLab is equipped with VT935G photoresistor. One pin of the photoresistor is connected to +5 V power supply and second pin to the channel 1 (pin PF1) of the analogue-digital converter. Between this pin and the ground 10 kΩ resistor is also connected, which forms a voltage divider with the photoresistor. Since the electrical resistance of the photoresistor is decreasing as the light intensity falling on it grows, the measured voltage on the pin of the microcontroller grows as light intensity grows. It is worth to take into account that the photoresistor used in the HomeLab reacts most on orange and yellow light.

The sensor VT935G is not meant to be a specific measuring device. It is meant to be more a device to specify overall lighting conditions – is there a lighted lamp in the room or not. In this case one has to just measure the resistance of the sensor in the half dark room, note it in the program and compare measured values – is it lighter or darker.

The exercise here is a little bit more complex as the light intensity is measured also in lux. For doing this, exists an approximate formula and floating-point variables. In the C-language are floating-point variables float- and double-type variables, which can be used to present fractions. Their flaw is high demand of resources. Computers have special hardware to calculate floating-point variables, in the 8-bit AVR microcontroller calculations are executed in software which demands a lot of memory and time. If the flaws are not critical, the floating-point variables are worth using.

Relationship between resistance (R) of VT935G and intensity of light (E)

There is an approximate formula showing the relationship between the intensity of light and electrical resistance in the sensor datasheet. As seen on the graph (on the right), with using logarithm scale, the resistance and intensity of light are almost in linear relationship and form a in-line formula, because following conversion applies:

log(a/b) = log(a) - log(b)

The relation is characterised by the ascent of the factor γ (ascend of the line), which is 0,9 on VT935G sensor. We have also data on one of the points on that line: resistance 18.5 kΩ (RA) at 10 lx intensity of light (EA). Hence we have the coordinates of one point as well as the ascent of the line and for calculating any other point, we only need one coordinate. Meaning, if sensors' resistance (RB) is measured, it is possible to calculate from the equation of line, the intensity of light EB) that falls on the sensor. Finding EB from the equation of line:

log(EB) = log(RA/RB) / γ + log(EA)

EB = 10log(RA/RB) / γ + log(EA)

This gives the formula for calculating the intensity of light when the resistance is known. The resistance can not be measured directly with microcontroller. For this the photoresistor is in the voltage divider. The output voltage of this voltage divider is converted to a specific variable by the analogue-digital converter (ADC). To find the resistance, the output voltage (U2) of the voltage divider must be calculated first, using the ADC value, also comparison voltage (Uref) of the converter must be taken into account: The formula is following:

U2 = Uref * (ADC / 1024)

From the formula for voltage divider(check the chapter on voltage divider) the resistance of the upper photoresistor (R1) can be found:

R1 = (R2 * U1) / U2 - R2

In the following calculation of voltage and resistance, the known factors are replaced with numbers and indexes have been removed:

U = 5 * (ADC / 1024)

R = (10 * 5) / U - 10

For finding the intensity of light, simplifying conversions can be done:

E = 10log(18.5/R) / 0.9 + 1 = 10log(18.5/R) * 10/9 * 101 =

= 10log18.5*10/9 - logR*10/9 * 10 = (10log18.5*10/9 / 10logR*10/9) * 10 =

= (18.510/9 / R10/9) * 10 = 18.510/9 * 10 * R-10/9

By calculating the constant in front of the variable of the field R, the expression remains follows:

E = 255,84 * R-10/9

These formulas help only if the photoresistor on the module of sensors of the HomeLab is used. If circuit is used equipped with different components, respective variables need to be changed. Next, source code of the example program is presented, which measures and calculates using ADC and displays the intensity of light on the LCD. But before compiling the program, the settings for using floating-point variables must be written in the project. How to do that is explained in the chapter of installing the software.

In the example program variables of voltage, resistance and intensity are defined using type double of floating-point variables. The variables which should be used as floating-point variables must always contain a decimal point (it can be also just 0, because then the compiler understands it correctly). When using sprintf for converting floating-point variable to text, “%f” format must be used, this may be enhanced using integers and decimal places. For example: “%3.2”, which displays always 3 integers and 2 decimal places.

 

#include <stdio.h>
#include <math.h>
#include <homelab/module/lcd_gfx.h>
#include <homelab/adc.h>
#include <homelab/delay.h>
 
// Main program
int main(void)
{
	char text[16];
	unsigned short adc_value;
	double voltage, resistance, illuminance;
 
	// Initializing the LCD
	lcd_gfx_init();
 
	// Clearing the LCD.
	lcd_gfx_clear();
 
	//Cursor on the position x=3, y=1
	lcd_gfx_goto_char_xy(3, 1);
 
	// Name of the program
	lcd_gfx_write_string("Luxmeter");
 
	// Setting the ADC
	adc_init(ADC_REF_AVCC, ADC_PRESCALE_8);
 
	// Endless loop.
	while (true)
	{
		// Reading the average value of the photoresistor
		adc_value = adc_get_average_value(1, 10);
 
		// Calculating the voltage in the input of the ADC
		voltage = 5.0 * ((double)adc_value / 1024.0);
 
		// Calculating the resistance of the photoresistor 
 
		// in the voltage divider
		resistance = (10.0 * 5.0) / voltage - 10.0;
 
		// Calculating the intensity of light in lux
		illuminance = 255.84 * pow(resistance, -10/9);
 
		// Converting the intensity of light to text
		sprintf(text, "%0.1f lux   ", illuminance);
 
		// Displaying it on the LCD
		lcd_gfx_goto_char_xy(3, 3);
		lcd_gfx_write_string(text);
 
		// Delay 500 ms
		sw_delay_ms(500);
	}
}

1-wire temperature sensor

The necessary knowledge: [HW] Sensors Module, [HW] User Interface Module, [HW] Controller module, [LIB] Pins, [LIB] Graphic LCD, [LIB] Sensors

Theory

Temperature sensor

Dallas Semiconductor Corp. worked out a communication bus system for simple sensors and other equipments called 1-wire protocol. This protocol provides low-speed data exchange, signaling and power over single signal wire. It is possible to connect up to 75 devices to one bus, forming MicroLan networks. MicroLan networks have one master unit, what controls network's traffic and ensures that one device at a time uses the bus. 1-wire protocol is similar to I2C protocol, but has lower data rates, longer distance range and only one wire for all communication.

1-wire communication is mostly used for communicating between different sensors and memory units. Bus data transfer rate is approximately 16.3 kbit/s. Communication is started by a master with the “reset” pulse, which pulls the wire to 0 volts for at least 480 µs. This signal resets all devices on the bus, simply taking the power out from the bus. After that, any device on the bus, shows that it exists with a “presence” pulse by holding the wire to ground at least 60 µs after the master releases the bus. With following 8-bit command and then data can be sent or received in groups of 8-bits. Each device on the bus has a unique 64-bit serial identification number.

1-wire sensors connection
Data transfer on a 1-wire bus

To find all devices, master send an enumeration command, and an address. For each bit master listens the answer. If slave device has all right address bits it returns a 0. Master uses this simple behavior to search for valid sequences of address bits. An enumeration of 10 or 15 devices finishes very quickly.

A read-time is initiated by master device pulling the 1-wire bus low for a minimum of 1 µs and then releasing the bus. Slave device transmits a 1 by leaving the bus high and transmits a 0 by pulling the bus low.

When transmitting a 0, slave device releases the bus by the end of the time, and the bus will be pulled back to its high idle state by pull-up resistor. Output data from the slave is valid for 15 µs after the falling edge which initiated read-time.

Practice

The DS18S20 digital thermometer provides 9–bit centigrade temperature measurements and has an alarm function with nonvolatile user-programmable upper and lower trigger points. A digital thermometer DS18S20 with a 1-wire communication protocol can be connected with Robotic HomeLab Sensor module external sensor connectors. Sensors's technical properties are following:

In the example below, 1-wire temperature sensor takes measurements and displays the results on HomeLab's User Interface board LCD display. With the present configuration and provided example code only 5 sensors can be connected to one bus. Sensors will be found automatically.

1-wire temperature sensor must be connected to sensor board ADC3 pin group. After loading the example program to the controller appears sensors queue number and temperature in Celsius on the User Interface board LCD display. If more than one sensor are connected on the bus, then sensor measurements are displayed in a row. Sensor and power supply type are also displayed. Homelab sensor's type is DS18S20 and power supply type is “externally”. It's possible to connect sensor only with 2 wires, in that case sensor receives it's power supply from data bus and on display “parasite” is displayed. “ERROR!” is shown in the display if error occurs, in this case the problem is most likely related with wiring.

Colors of the wires for connecting the sensor:

Example code enabling to read the temperature with 1-wire protocol is shown below. It is important to include “onewire.h” and “onewire.c” to the program. Sensor-specific code is located in “ds18x20.h” and “ds18x20.c” files.

 

#include <avr/io.h>
#include <string.h>
#include <stdio.h>
#include "onewire.h"
#include "ds18x20.h"
#include <homelab/module/lcd_gfx.h>
#include <homelab/delay.h>
#include <homelab/pin.h>
 
// Sensor queue number and sensor's specific code are stored here
extern uint8_t gSensorIDs[MAXSENSORS][OW_ROMCODE_SIZE];
 
// Main program
int main( void )
{
  uint8_t nSensors, i;
  int16_t decicelsius;
  uint8_t error;
  char s[10];
  char sensor_nr[1];
 
  // Pin configuration of the Sensor board's multiplexer.
  pin multiplexer_pin = PIN(G, 0);
 
  // LCD display initialization 
  lcd_gfx_init();
 
  //  LCD display clear
  lcd_gfx_clear();
 
  // Switching back light on 
  lcd_gfx_backlight(true);	
 
  // Multiplexer's pin configuration as a output and then switchover it  
  // to connect external sensor with the controller.
  pin_setup_output(multiplexer_pin);
  pin_set(multiplexer_pin); 
 
  // 1-Wire bus configuration. In sensor board the ADC3 pin group is same as PF3.
  ow_set_bus(&PINF,&PORTF,&DDRF,PF3);
 
  // Searching for sensors. For variable nSensors is attributed the sum 
  // of all found sensors.
  nSensors = search_sensors();
 
  while(1) 
  {
    error = 0;
 
    // If no sensors found the error flag is set.
    if ( nSensors = 0 ) 
    {
      error++;
    }
 
    // All the sensor are displayed starting at the bottom.
    for ( i = nSensors; i > 0; i-- ) 
    {
	// Taking the measurements. In case of error, the error flag is set.
	if (DS18X20_start_meas(DS18X20_POWER_PARASITE,&gSensorIDs[i-1][0])=DS18X20_OK) 
	{
	  sw_delay_ms( 750 );
 
	  // Measurements are saved in decicelsius. In case of error,
	  // the error flag is set.
	  if (DS18X20_read_decicelsius(&gSensorIDs[i-1][0],&decicelsius)=DS18X20_OK) 
	  {
	    // Displaying the word "TEMP".
	    lcd_gfx_goto_char_xy(2, 1);
	    lcd_gfx_write_string("TEMP");
 
    	    // Displaying degree sign
	    lcd_gfx_goto_char_xy(13, 1);
	    lcd_gfx_write_string("C");
 
	    // Making the readings to strings and adding +/-.
	    DS18X20_format_from_decicelsius( decicelsius, s, 10 );
 
	    // Displaying the temprerature
	    lcd_gfx_goto_char_xy(7, 1);					
	    lcd_gfx_write_string(s);
 
	    // Displaying sensors queue number.
	    // Firstly it's converted to a string.
	    lcd_gfx_goto_char_xy(0, 1);
	    sprintf(sensor_nr, "%d", i);
	    lcd_gfx_write_string(sensor_nr);
	  } 
	  else 
	  {
	    // CRC error (Connection is down)
	    error++;
	  }
	}
	else 
	{
	  error++;
	}
    }		
    // Displaying the error messege.
    if ( error ) 
    {
	lcd_gfx_goto_char_xy(1, 3);
	lcd_gfx_write_string("ERROR!");
	error = 0;
    }
    else
    {
	lcd_gfx_goto_char_xy(1, 3);
	lcd_gfx_write_string("        ");
    }
    sw_delay_ms(500);
  }
}

Lidar

Necessary knowledge: [HW] Communication Module, [HW] User Interface Module, [LIB] Serial Interface, [LIB] Graphic LCD, [LIB] Sensors

Theory

SICK Laser Rangefinder (LIDAR)

LIDAR (Light Detection and Ranging) is an optical remote sensing system which can measure the distance of a target by illuminating it with light. LIDAR technology is being used in Robotics for the perception of the environment as well as object classification. The ability of LIDAR technology to provide 2D elevation maps of the terrain, high precision distance to the ground, and approach velocity can enable safe landing of robotic and manned vehicles with a high degree of precision.

Lidar consists of a transmitter which illuminates a target with a laser beam, and a receiver capable of detecting the component of light which is essentially coaxial with the transmitted beam. Receiver sensors calculate a distance, based on the time needed for the light to reach the target and return. A mechanical mechanism with a mirror sweeps the light beam to cover the required scene in a plane or even in three dimensions, using a rotating nodding mirror.

One way to measure the time of flight for the light beam is to use a pulsed laser and then measure the elapsed time directly. Electronics capable of resolving picoseconds are required in such devices and they are therefore very expensive. Another method is to measure the phase shift of the reflected light.

Working principle

Collimated infrared laser is used to the phase-shift measurement. For surfaces, having a roughness greater than the wavelength of the incident light, diffuse reflection will occur. The component of the infrared light will return almost parallel to the transmitted beam for objects.

Phase-shift measurement

The sensor measures the phase shift between the transmitted and reflected signals. The picture shows how this technique can be used to measure distance. The wavelength of the modulating signal obeys the equation:

c = f ∙ τ

where c is the speed of light and f the modulating frequency and τ the known modulating wavelength.

The total distance D' covered by the emitted light is:

D' = B + 2A = B + (θ * τ) / 2π

where A is the measured distance. B is the distance from the phase measurement unit. The required distance D, between the beam splitter and the target, is therefore given by

D = τ * θ / 4π

where θ is the electronically measured phase difference between the transmitted and reflected light beams.

It can be shown that the range is inversely proportional to the square of the received signal amplitude, directly affecting the sensor’s accuracy.

Practice

Map created by Lidar

In autonomous robotics as well as industrial robotics SICK laser rangers are very widely used. The SICK LMS 200 can easily be interfaced through RS-232 or RS-422, providing distance measurements over a 180 degree area up to 80 meters away. This lidar is based on a time-of-flight measurement principle. The example output of one scan measurement result is shown in the picture on the right.

Connection diagram

To make the SICK operational, it must be wired for power and communication. On the back of the SICK there are two connectors that looks like serial port connectors. The connector with the female end is for power and the connector with the male end is for communications. The power and the serial cable should be wired as shown in the picture. Lidar can be connected with Robotic HomeLab Communication module using one of the RS-232 connectors. Power must be taken from external power source and this is not included in Robotic HomLab kit. Required dc power voltage is 24 V.

The SICK receives commands as streams of bytes through the serial port. When transmitting data, it sends back streams of bytes corresponding to distance measurements at a given angle.

To grab data from the SICK, you must first send a start string to tell the sensor to start sending data. This string is:

Hexadecimal Form: 02 00 02 00 20 24 34 08

Decimal Form: 2 0 2 0 32 36 52 8

If the start string is successfully sent, Lidar will begin streaming data over RS232. Incoming data from a scan is sent sequentially as the sensor scans through 180°. For example if the sensor is set to scan 180° with resolution of 0.5° the first data point which was sent will correspond to 0°, the next will correspond to 0.5°, the following to 1°, and so on. This means there is total of 361 data points. Each distance measurement is sent in the form of two bytes. The least signifficant byte is sent first followed by the most signifficant byte. Operating in metric mode the unit for the measurements is in milimeters.

Finally to stop the sensor from sending data a stop string must be sent. This string is:

Hexadecimal Form: 02 00 02 00 20 25 35 08

Decimal Form: 2 0 2 0 32 37 53 8

Following example shows how to initiate Lidar and get the count of package.

#include <stdio.h>
#include <homelab/delay.h>
#include <homelab/pin.h>
#include <homelab/module/lcd_gfx.h>
#include <homelab/usart.h>
 
// Defining USART interface.
usart port = USART(0);
 
// Defining button pins.
pin button1 = PIN(C, 0);
pin button2 = PIN(C, 1);
 
// Initialize
static inline void init()
{
	// Setting buttons pins as inputs.
	pin_setup_input_with_pullup(button1);
	pin_setup_input_with_pullup(button2);
 
	// Set-up of the LCD.
	lcd_gfx_init();
 	// Cleaning the screen.
	lcd_gfx_clear();
 	// Switching on the background light.
	lcd_gfx_backlight(true);	
 	// Displaying the name of the program.
	lcd_gfx_goto_char_xy(3, 1);
	lcd_gfx_write_string("Lidar");
 
	// The set-up of the USART interface.
	usart_init_async
	(
		port,
		USART_DATABITS_8,
		USART_STOPBITS_ONE,
		USART_PARITY_NONE,
		USART_BAUDRATE_ASYNC(9600)
	);		
}
 
// Main program
int main(void)
{	
	unsigned char new_value1, new_value2, old_value1 = 0, old_value2 = 0;
 
	char c;
	int i = 0;
	int count = 0;
	char text[16];
 
	// Initialize
	init();	
 
	// Endless cycle
	while (1)
	{	 
		// Reads buttons states
		new_value1 = pin_get_debounced_value(button1);
		new_value2 = pin_get_debounced_value(button2);
 
		// Button S1 is pressed.
		if((!new_value1) && (old_value1))
		{	
			//Send "02 00 02 00 20 24 34 08" to start scanning.
 
			usart_send_char(port, 0x02);
			usart_send_char(port, 0x00);
			usart_send_char(port, 0x02);
			usart_send_char(port, 0x00);
			usart_send_char(port, 0x20);
			usart_send_char(port, 0x24);
			usart_send_char(port, 0x34);
			usart_send_char(port, 0x08);
		}
 
		// Button S2 is pressed.
		if((!new_value2) && (old_value2))
		{
			//Send "0x 02 00 02 00	20 25 35 08" to stop scanning.
			usart_send_char(port, 0x02);
			usart_send_char(port, 0x00);
			usart_send_char(port, 0x02);
			usart_send_char(port, 0x00);
			usart_send_char(port, 0x20);
			usart_send_char(port, 0x25);
			usart_send_char(port, 0x35);
			usart_send_char(port, 0x08);				
		}
 
		// Remembers the last keys values.
		old_value1 = new_value1;
		old_value2 = new_value2;
 
		// Try to read serial port
		if (usart_try_read_char(port, &c))
		{
			// Find a header "0x 02 81 D6 02 B0 69 41"
			// Very basic package start search.	
			if(c = 0x02) i++;
			if(c = 0x81) i++;			
			if(c = 0xD6) i++;			
			if(c = 0x02) i++;			
			if(c = 0xB0) i++;			
			if(c = 0x69) i++;			
			if(c = 0x41) i++;
 
			//If there is an header
			if(i >= 7)
			{
				//Increse packet counter
				count++;
 
				//Displaying packet count on the LCD.
				lcd_gfx_goto_char_xy(0, 3);
 
				sprintf(text, "Pakette: %i", count);
 
				lcd_gfx_write_string(text);
 
				i=0;
			}
		}					
	}
}

Color sensor

Necessary knowledge: [HW] Sensors Module, [HW] User Interface Module, [AVR] Analog-to-digital Converter, [LIB] Analog to Digital Converter, [LIB] Graphic LCD, [LIB] Sensors

Theory

ColorPAL sensor

The color sensor detects the color of the surface, usually in the RGB scale. Color is the result of interaction between a light source, an object and an observer. In case of reflected light, light falling on an object will be reflected or absorbed depending on surface characteristics, such as reflectance and transmittance. For example, green paper will absorb most of the reddish and bluish part of the spectrum while reflecting the greenish part of the spectrum, making it appear greenish to the observer.

Measuring colors of the ingredients are basically two ways. The easiest way is to use a color-changing light source and a sensor that measures the intensity of the light. Most industrial color sensors contain a white light emitter and three separate receivers. There are usually three sets of color source or color filter with peak sensitivities at wavelengths that we identify as red (580nm), green (540nm) and blue (450nm). All colors can be derived by their components.

Color sensing techniques

Color sensors have a variety of applications including detection of environment, choosing the right product and sorting. The detection of color compared to the vision sensor is much faster and cheaper.

Practice

The ColorPAL from Parallax (Datasheet) is a miniature color and light sensor. The ColorPAL uses an RGB LED to illuminate a sample, one color at a time, along with a broad-spectrum light-to-voltage converter to measure the light reflected back. The amount of light reflected from the sample under illumination from each red, green and blue LED can be used to determine the samples color. The subject must be reflective and non-fluorescent. The color of objects that emit light (e.g. LEDs) cannot be detected.

The light sensor used in the ColorPAL is a TSL13T, which has the spectral sensitivity curve (taken from the TSL13T datasheet) as seen on the figure and superimposed with the LED wavelengths.

ColorPAL spectral sensitivity curve

Sensor outputs a voltage, proportional to all the light that it sees weighted by the curve on the figure. Therefore, when a subject is illuminated with a red LED only it will respond with a voltage proportional to the red component of the subjects color and similarly with blue and green. When there is ambient light mixed in with the LEDs illumination, its effect can be eliminated by sampling first without any LEDs turned on and then subtracting this reading, in turn, from each of the red, green, and blue components. This reference measurement should be taken before each color measurement to eliminate any effects from varying ambient conditions.

ColorPAL sensor requires only three connections: +5 V supply, ground and serial data. It can be plugged into Robotic Homelab communication board EXT_UART connector. Separate TxD and RxD pins needs to be connected together using diode. Communication with the ColorPAL takes place using serial I/O transmitting and receiving at between 2400 and 7200 baud using a non-inverted open-drain protocol.

ColorPAL wiring schematic

Example code enabling to read the RGB values which is printed on the screen using hex format. Measurements with ColorPAL sensor will be made automatically.

#include <stdio.h>
#include <homelab/delay.h>
#include <homelab/module/lcd_gfx.h>
#include <homelab/usart.h>
 
// Determining USART interface.
usart port = USART(0);
 
// Main program
int main(void)
{	
	// Variable, which is stored in the read characters.
	char c;
 
	// Variables for each color text which is printed on the screen.
	char red[7];
	char green[7];
	char blue[7];
 
	// Variable for all color data.
	char data[9];
 
	// The set-up of the USART interface.
	usart_init_async
	(
		port,
		USART_DATABITS_8,
		USART_STOPBITS_ONE,
		USART_PARITY_NONE,
		USART_BAUDRATE_ASYNC(2400)
	);	
 
	// LCD init
	lcd_gfx_init();
 
	// Clear screen
	lcd_gfx_clear();
 
	// Turn on backlight.
	lcd_gfx_backlight(true);	
 
	// Print program name
	lcd_gfx_goto_char_xy(3, 1);
	lcd_gfx_write_string("ColorPAL");
 
	while (1)
	{	 
		// Send a command to the sensor.
		usart_send_string(port, "=m!");
 
		// There are 12 character to read (3 command and 9 data character).
		for(int i = 0; i < 12; i++)
		{
			// Waiting for incoming data.
			while (!usart_has_data(port)){}				 
 
			// Read out the received character.
			c = usart_read_char(port);
 
			// The first three characters (=m!),
			// which we have sent, it is not necessary.
			if(i>3)
			{	
				// Store the received data character. 
				data[i-3] = c;
			}			
		}		
 
		// Converting the data to the suitable form 
		// and print it on the screen.	
		sprintf(red, "Red:   %c%c%c", data[0], data[1], data[2]);
		lcd_gfx_goto_char_xy(0, 3);
		lcd_gfx_write_string(red);
 
		sprintf(green, "Green: %c%c%c", data[3], data[4], data[5]);
		lcd_gfx_goto_char_xy(0, 4);
		lcd_gfx_write_string(green);	
 
		sprintf(blue, "Blue:  %c%c%c", data[6], data[7], data[8]);
		lcd_gfx_goto_char_xy(0, 5);
		lcd_gfx_write_string(blue);					
 
		// Delay
		sw_delay_ms(500);
	}
}

Force sensor

Necessary knowledge: [HW] Sensors Module, [HW] User Interface Module, [AVR] Analog-to-digital Converter, [LIB] Analog to Digital Converter, [LIB] Graphic LCD, [LIB] Sensors

Theory

Force-sensing resistor
Force-sensing resistor layers

FSR (force-sensing resistor) sensor allow you to detect physical pressure, squeezing and weight. FSR is basically a resistor that changes its resistive value (in ohms Ω) depending on how much it’s pressed. These sensors are fairly low cost and easy to use but they're rarely accurate. They also vary some from sensor to sensor perhaps 10%. It means when you use FSR's you should only expect to get ranges of response. As with all resistive based sensors force-sensing resistors require a relatively simple interface and can operate satisfactorily in moderately hostile environments. Compared to other force sensors, the advantages of FSR are their size and good shock resistance. However FSR will be damaged if pressure is applied for a longer time period (hours).

FSR consists of a conductive polymer, which changes resistance in a predictable manner following application of force to its surface. They are normally supplied as a polymer sheet or ink that can be applied by screen printing. The sensing film consists of both electrically conducting and non-conducting particles suspended in matrix. The particles are sub-micrometre sizes, and are formulated to reduce the temperature dependence, improve mechanical properties and increase surface durability. Applying a force to the surface of a sensing film causes particles to touch the conducting electrodes changing the resistance of the film.

Force-sensing resistors are commonly used to create pressure-sensing “buttons” and have applications in many fields, including musical instruments, car occupancy sensors, and robotics.

Practice

Force conductance graph
Voltage divider schematics for the sensor

Pololu FSR with 12.7 mm diameter circular active area are exhibits a decrease in resistance with an increase in the force applied to the active surface. Its force sensitivity is optimized for use in human touch control of electronic devices. The force vs. resistance characteristic provides an overview of FSR typical response behavior. For interpretational convenience the force vs. resistance data is plotted on a log/log format. In general, FSR response approximately follows an inverse power-law characteristic (roughly 1/R).

The easiest way to measure a resistance of FSR is to connect one terminal to power and the other to a pull-down resistor to ground. Then the point between the fixed pull-down resistor and the variable FSR resistor is connected to the analogue input of a Controller board. In this configuration the analogue voltage reading ranges from 0V (ground) to about 5V (or about the same as the power supply voltage). As the resistance of the FSR decreases the total resistance of the FSR and the pull-down resistor decreases from about 100Kohm to 10Kohm. That means the current flowing through both resistors increases which in turn causes the voltage across the fixed 10K resistor to increase.

Measuring the Newton force by the FSR it is good idea to map analogue voltage reading ranges to 0 V to supply voltage. After that you can calculate the FSR resistance using following formula:

RFSR = ((Vcc - U) * R1) / U

Where: RFSR - FSR Resistance Vcc – supply voltage. Usually 5 V U – The measured voltage. The ADC reading must be converted to 0 V - Vcc R1 – resistor. 10 k

Then you can calculate the conductivity CFSR in S/m [Siemens per meter]. The conductance is plotted vs. force (the inverse of resistance: 1/r). This format allows interpretation on a linear scale.

CFSR = 1 / RFSR

Use the FSR guide graphs on the datasheet to approximate the force. It depends on the measurable range. For example (0-1 Kg) low force range can be use formula:

FFSR = CFSR / 80

The example program of the force sensor shows the measured force (Newtons) and weight (kg) on the LCD.

 

#include <stdio.h>
#include <homelab/adc.h>
#include <homelab/delay.h>
#include <homelab/pin.h>
#include <homelab/module/lcd_gfx.h>
 
// Map a value from one range to another.
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
 
// Main program
int main(void)
{
	signed short value; // The analog reading.
	char text[16];
	int voltage; // The analog reading converted to voltage.
	unsigned long resistance; // The voltage converted to resistance.
	unsigned long conductance; 
	long force; // The resistance converted to force. 
	long weight; // The force converted to weight. 
 
	// Set the external sensors pins.
	pin ex_sensors = PIN(G, 0);
	pin_setup_output(ex_sensors);
	pin_set(ex_sensors);
 
	// LCD initialization.
	lcd_gfx_init();
 
	// Display clearing.
	lcd_gfx_clear();
 
	// Move the cursor to the right of the screen.
	lcd_gfx_goto_char_xy(1,1);
 
	// Print the name of the program.
	lcd_gfx_write_string("Force sensor");
 
	// Set the ADC.
	adc_init(ADC_REF_AVCC, ADC_PRESCALE_8);
 
	// An endless loop.
	while (true)
	{
		// Converting and averaging channel 0 value.
		value = adc_get_average_value(0, 4);
 
		// Analog voltage reading ranges from about 0 to 1023 
		// which maps to 0V to 5V   (= 5000mV)
	        voltage = map(value, 0, 1023, 0, 5000);
 
		// The voltage = Vcc * R / (R + FSR) where R = 10K and Vcc = 5V
		// so FSR = ((Vcc - V) * R) / V
		// fsrVoltage is in millivolts so 5V = 5000mV
		resistance = 5000 - voltage;     
	        resistance *= 10000; // 10K resistor
	        resistance /= voltage; // FSR resistance in ohms.
 
		conductance = 1000000; //We measure in micromhos.
	        conductance /= resistance; //Conductance in microMhos.
 
 		// Move the cursor to the right of the screen.
		lcd_gfx_goto_char_xy(1,3);
 
		// Calculate the force.	    
                force = conductance / 80;
                sprintf(text, "%lu Newtons   ", force);
 
		// Printing of the force.
		lcd_gfx_goto_char_xy(1,3);
		lcd_gfx_write_string(text);
 
		// Printing and calculating of the weight.
		lcd_gfx_goto_char_xy(1,4);
		weight = force / 9,8;
		sprintf(text, "%lu kg   ", weight);
		lcd_gfx_write_string(text);
 
		// Delay.
		sw_delay_ms(500);
	}
}

Motors

Motors are actuator devices, actually some of them are and those can also be very different, beginning with operating principles and ending with power and size. In robotics mainly electric motors are used. Electrical motor is a device which converts electrical energy to mechanical energy (work). It works on principles of electromagnetism.

There are several ways to classify electrical motors. Most important is to divide them as alternate current (AC) and direct current (DC) motors. In addition, there are electrical motors with brushes and brush-less motors, linear motors and rotary motors, nano-motors and large motors and so on. On the other hand, some of the segmentations are provisional. For example, linear motion is achieved usually using rotary electrical motor, which is integrated into unitary body with screw mechanism and treated so as linear actuator. In this chapter are covered three most common types of electrical motors in robotics: DC motor with permanent magnets, RC servos and stepper-motor.

DC motor

Necessary knowledge: [HW] Motor Module, [AVR] Digital Inputs/Outputs, [LIB] Motors, [LIB] Delay

Theory

DC motor

Permanent magnet DC motors are very common in different applications, where small dimensions, high power and low price are essential. Due to their fairly high speed, they are used together with transmission (to output lower speed and higher torque).

The perfect graph of relationship between speed (V), current (I), power (P), efficiency (η)and torque (T)of a DC motor.

Permanent magnet DC motors have quite simple construction and their controlling is quite elementary. Although controlling is easy, their speed is not precisely determined by the control signal because it depends on several factors, primarily of the torque applied on the shaft and feeding current. The relationship between torque and speed of a ideal DC motor is linear, which means: the higher is the load on the shaft the lower is the speed of the shaft and the higher is the current through the coil.

Brushed DC motors are using DC voltage and basically do not need special control electronics because all necessary communication is done inside the motor. When the motor is operating, two static brushes are sliding on the revolving commutator and holding the voltage on the coils. The direction of revolving of the motor is determined by the polarity of the current. If the motor must revolve in only one direction, then the current may come through relay or some other simple connection. If the motor has to revolve in both directions, then an electronic circuit called H-bridge is used.

In the H-bridge are four transistors (or four groups) directing the current for driving the motor. The electrical scheme of the H-bridge is similar to the letter H and that is where it gets its name. The peculiarity of the H-bridge is the possibility to apply both directional polarities to the motor. Picture on the side shows the principal scheme of the H-bridge based on the example of the switches. If two diagonal switches are closed, the engine starts operating. The direction of the revolving of the motor depends on in which diagonal the switches are closed. In the real H-bridge the switches are replaced with transistors which are selected according to the current of the motor and voltage.

The working principle of H-bridge used on switches.

There exist also integrated H-bridges, for conducting smaller currents. For higher currents special power MOSFET-s are used. The H-bridge with other electronics is called motor controller or driver. The driver of DC motor in the HomeLab L293D includes 2 integrated H-bridges and circuit breaking diodes. The motor is controlled with three digital signals,one of them is operation enabling signal enable and the other two are determining the state of the transistors in the H-bridge. Never can occur that two vertical transistors are opened, because this would short-circuit the power source. This means that the driver is designed as foolproof and only option that can be chosen is which transistor (upper or bottom) of one side of the H-bridge (of “semi-bridge”) is opened. In other words the polarity is selected using two driving signals which is applied to the two ends of the coil of the motor.

Practice

The board of the motors of the HomeLab allows connecting up to four DC motors. The schemes and instructions for connection are found in the chapter “Motors module”. Basically, for every motor there is a H-bridge which is controlled with two digital output pins of the microcontroller, because the enable pin is constantly high. If both controlling pins have same value, then the motor is stopped if different then it revolves in the corresponding direction. The state of the H-bridge is described in the following table:

Input A Input B Output A Output B Result
0 0 - - The motor is stopped
1 1 + + The motor is stopped
1 0 + - The motor revolves in direction 1
0 1 - + The motor revolves in direction 2

DC motors can be controlled by manipulating directly corresponding driver pins with microcontroller. Though, special functions for driving the motor are in the library of the HomeLab.

// The setup of the pins driving pins.
static pin dcmotor_pins[4][2] =
{
	{ PIN(B, 7), PIN(B, 4) },
	{ PIN(D, 1), PIN(D, 0) },
	{ PIN(D, 7), PIN(D, 6) },
	{ PIN(D, 5), PIN(D, 4) }
};
 
// Allowing the control of the chosen DC motor.
void dcmotor_init(unsigned char index)
{	
	pin_setup_output(dcmotor_pins[index][0]);
	pin_setup_output(dcmotor_pins[index][1]);
}
 
// Determining the operation and the direction of the chosen DC motor.
void dcmotor_drive(unsigned char index, signed char direction)
{	
	pin_set_to(dcmotor_pins[index][0], direction < 0);			
	pin_set_to(dcmotor_pins[index][1], direction > 0);
}

With the array dcmotor_pins in the library, the controlling pins of four motor-controllers are determined. Before controlling the motors, function dcmotor_init with the number of the motor-controller (0 – 3) must be called out. It sets the pins as output. For controlling is the function dcmotor_drive, with it the negative direction parameter is used to give to the motor one revolving direction and other direction with positive parameter, and 0 if the motor is stopped.

The following is an example program which controls first and second DC motor so that they alter their revolving direction after every second. The speed could be controlled if one controlling pin were modulated with PWM signal.

#include <homelab/module/motors.h>
#include <homelab/delay.h>
 
// Main program
int main(void)
{
	// Variable of direction and speed.
	signed char direction = 1, speed = 1;
 
	// Setup of motors no 0.
	dcmotor_init(0);
 
        // Setup of motors no 1. pwm mode
	dcmotor_drive_pwm_init(1, TIMER2_NO_PRESCALE);
 
	// Endless loop
	while (true)
	{
		// One motor revolves in one direction and the other 
		// one to other direction.
		dcmotor_drive(0, direction);
		dcmotor_drive_pwm(1, direction, speed);
 
		// Break for 1 second.
		sw_delay_ms(1000);
 
		// Reversing the direction.
		direction = -direction;
 
		// The speed increase of +10.
		speed+=10;
	}
}

DC motor speed

Necessary knowledge: [HW] Motor Module, [AVR] Digital Inputs/Outputs, [LIB] Motors, [LIB] Delay

Theory

DC motor with wheel

Permanent magnet DC motors are very common in robotics and mechatronics. DC motors are relatively easy to control, both direction and speed. Motor rotation direction is determined by power supply polarity and H-bridge driver is often used when DC motor is controlled by microcontroller.

Even DC motor speed is easy to control there is no guarantee that required speed is also actually obtained. The reason is that the actual speed depends on several factors, primarily of the torque applied on the shaft, feeding current and other motor characteristics. The relationship between torque and speed of a ideal DC motor is linear, which means: the higher is the load on the shaft the lower is the speed of the shaft and the higher is the current through the coil. In reality it is not linear and can vary depending on the motor quite a lot.

Controlling the speed of DC motor can be realized either by analogous or digital signaling.

PWM signal examples for one period

In general, motor speed is dependent of the applied voltage. When powering motor with its nominal voltage, motor runs at its nominal speed at no load condition. When reducing the voltage motor speed and torque also decreases. This kind of speed control can be called as analogous motor speed control. This can be realized for example with one transistor.

In robotics DC motors are in most cases controlled by microcontrollers and as microcontrollers are digital devices it is much easier to control motor speed also digitally. To do that, instead of keeping transistor open partly, transistors need to be closed and opened constantly using pulse width modulation (PWM), so the total energy supplied to the motor is somewhere between motor switched off and motor running on full power. Opened time in the whole PWM period is called duty cycle, which is marked as percents. 0% means the transistor is closed constantly – it is not conducting current. 100% means the transistor is constantly open and is conducting current all the time. The frequency of the PWM has to be high enough to avoid vibrations in the shaft of the motor. At low frequencies the motor produces noise and due to that, modulation frequencies over 20 kHz are used quite often. On the other hand the efficiency of the transistors might not be so good at higher frequencies. Vibrating of the shaft of the motor is reduced by inertia of the rotor and the inductivity of the coils. Instead of using single transistor, H-bridge can be feed with the same PWM signal by controlling so motor speed and direction.

By using digital contorol, i.e. PWM signal to control the transistor and by this motor speed, there are several advantages over the analogous control. Most important ones for microcontroller driven systems are that speed can be controlled only by one single digital output (no need for complicated digital-analogous converter) and control is more effective (power dissipation are minimized).

Controlling motor speed with PWM

Simplified control schematics is shown on the figure. Control voltage Vc from microcontroller output pin turns on and off the transistor Q in approx. 20 kHz frequency. When Q is turned on (saturation), full current I flows freely through the motor M. In this state transistor acts as a closed switch and voltage on the transistor Vq is nearly 0 by leaving almost full Vdd across the motor. We can calculate the power dissipated by the transistor by using formula P = I × V. Applying this to Q:

P = I × Vq, and if Vq = 0 also P = 0 W

This means that almost no power is consumed by transistor when it is ON state. Similar situation is also when transistor is closed (OFF state). In this situation nearly no current flows through the motor and transistor. Calculating the power consumed by transistor once again:

P = I × Vq, and if I = 0 also P = 0 W

As a conclusion, when transistor operates only on and off states the efficiency can be very high as nearly no power is consumed by transistor itself. Compared with linear (analogous) control of the transistor when half of the power can be consumed by transistor in case motor is operated at half speed. However in practice, digital control (PWM) is also not totally lossless as transistors cannot be turned on and off instantaneously. Therefore little dissipation occurs in every transistor and every switching, by cousing bigger dissipation when frequency is higher.

Note: do not mix up RC Servo PWM signal with ordinary PWM signals.

Practice

The Motor module of the HomeLab includes motor board and DC motor equipped with integrated gearbox and encoder. Motor board allows connecting up to four DC motors. The schemes and instructions for connection are found in the chapter “Motors module”. Every motor is connected to H-bridge which is controlled with two digital output pins of the microcontroller. Motor speed is controlled by timers which are generating software PWM signal for H-bridge. Motor speed can be controlled by relative value between 0 to 255, where 0 means that motor is stopped and 255 that motor runs at maximum speed.

static pin dcmotor_pins[4][2] =
{
	{ PIN(B, 7), PIN(B, 4) },
	{ PIN(D, 1), PIN(D, 0) },
	{ PIN(D, 7), PIN(D, 6) },
	{ PIN(D, 5), PIN(D, 4) }
};
 
static int motorindex[4][2] =
{
	{ 0, 1 },
	{ 2, 3 },
	{ 4, 5 },
	{ 6, 7 }
};
 
// Initialize PWM for specified DC motor. 
void dcmotor_drive_pwm_init(unsigned char index, timer2_prescale prescaler)
{
  	unsigned char i, pwm;
 
	pin_setup_output(dcmotor_pins[index][0]);
	pin_setup_output(dcmotor_pins[index][1]);
 
	motor[index] = 1;
 
  	pwm = PWMDEFAULT;
 
  	for(i=0 ; i<CHMAX ; i++)      // initialize all channels
  	{
    	  compare[i] = pwm;           // set default PWM values
    	  compbuff[i] = pwm;          // set default PWM values
  	}
 
	// Timer 2 normal regime, set prescaler
	timer2_init_normal(prescaler);
  	// Timer 2 interrupts set enabled
	timer2_overflow_interrupt_enable(true);
 
  	// Enable global interrupts
	sei();
}
 
void dcmotor_drive_pwm(unsigned char index, signed char direction, unsigned char speed) 
{
	if(direction = -1)
	{
		compbuff[motorindex[index][0]] = 0x00;
		compbuff[motorindex[index][1]] = speed;
	}
	if(direction = 1)
	{
		compbuff[motorindex[index][0]] = speed;
		compbuff[motorindex[index][1]] = 0x00;
	} 
}

With the array dcmotor_pins in the library, the controlling pins of four motor-controllers are determined. Before controlling the motors and their speed, function dcmotor_drive_pwm_init with the number of the motor-controller (0 – 3) must be called out. It sets the pins as output. In addition prescaler - timer2_prescale prescaler have to be set as a second parameter. Prescaler sets PWM frequency and is important when using other timer based functions on the same time. If only motors are used TIMER2_NO_PRESCALE value is most suitable. If other timer based functions are used on the same time e.g. ultrasonic sensor TIMER2_PRESCALE_8 is recommended value. Bigger prescaler values are not suitable for DC motor speed control as vibration will be too high. However the same function can be used for example flashing the LED and in this case bigger prescaler values are important to consider.

For controlling motor speed the function dcmotor_drive_pwm is included into library. With this function three parameters are needed. First is motor index (0-3), second is direction -negative direction parameter is used to give to the motor one revolving direction and other direction with positive parameter, and 0 if the motor is stopped. Third parameter is speed where the value can be from 0 to 255. The speed value is not any specific rpm, but is relative value and the actual speed is depending on the motor and power supply. The precision of motor speed control is 8-bit, meaning that smallest controlling value is 1/255 of full speed.

The following is an example program which controls first DC motor (DC motor connector 0) so that motor speed is half of the full speed. The speed is modulated with PWM signal of controlling pin.

#include <homelab/delay.h>
#include <homelab/module/motors.h>
 
int main(void)
{
	// DC motor 0 init with no prescaler
  	dcmotor_drive_pwm_init(0, TIMER2_NO_PRESCALE);
 
  	while(1)
  	{   	
 		// DC motor drive with half of the nominal speed
		dcmotor_drive_pwm(0, 1, 128);			      
  	}
}

Another example program which controls first DC motor (DC motor connector 0) with potentiometer from Sensor module.

#include <homelab/delay.h>
#include <homelab/module/motors.h>
#include <homelab/adc.h>
 
int main(void)
{
	int speed;
 
	// Adjusting ADC
	adc_init(ADC_REF_AVCC, ADC_PRESCALE_8);
 
	// DC motor 0 init with no prescaler
  	dcmotor_drive_pwm_init(0, TIMER2_NO_PRESCALE);
 
  	while(1)
  	{
		// Potentiometer is connected to channel 3
		// Average of 4 samples are acquired
		speed = adc_get_average_value(3, 4);
 
		// DC motor drive with speed from potentiometer
		// As potentiometer has 10-bit output but DC motor drive 
		// function 8-bit input the adc output have to be converted 
		// to 8-bit e.g dividing the output with 4, or shifting bit 
		// 2 position >>2
		dcmotor_drive_pwm(0, 1, speed/4);
  	}
}

Servomotor

Necessary knowledge: [HW] Motor Module, [HW] Sensors Module, [AVR] Digital Inputs/Outputs, [LIB] Motors, [LIB] Analog to Digital Converter

Theory

RC servo motor
The relationship between width of the signal and position of Servo PWM.

Servo motors are often used in radio-controlled (RC) models, and are very useful in different kinds of small robotics applications because they are compact and inexpensive. An RC servo motor includes a built-in DC motor, gearbox, position feedback sensor (usually potentiometer), and drive electronics. RC servo motors can be controlled by an external pulse-width modulation (PWM) signal. If a signal meets RC servo timing requirements, it usually “describes” a (target) position input for the servo drive electronics. Servo motor electronics compare the shaft position with the inputted position, trying to find a shaft position where they match. The position control signal is a continuous square-wave signal, as depicted in figure.

RC (radio-controlled) servo-motors are very common actuator devices in robotics and model building. RC servo motors are consisting of small DC motor, reduction gear and control logic device. Usually the rotor of the servo motor moves to a certain position and tries to maintain that position. The position of the rotor depends of the control signal received by the servo motor. Depending on the type of the motor, the maximum revolving angle of the motor may differ. Servo motors that revolve constantly are rare. In this case, the control signal determines not the revolving angle but the speed of revolving. Servo motor “hack” is also quite common. This makes the position determining servo motor to constantly revolving servo. In this case the feedback potentiometer is replaced by two fixed resistors and the mechanical resistor that prevents full rotations is removed from the gear. A very important characteristic of servo motors is its power-weight ratio.

The controlling signal of servo motor is specific pulse with modulated signal (PWM), where width of the pulse determines the position of the rotor. The period of the signal is 20 ms (50 Hz) and the width of the high period is 1 ms – 2 ms. 1 ms marks one extreme position and 2 ms marks the second one. 1,5 ms marks the middle position of the servo motor’s rotor.

Traditional RC servo motor is also known as analogue-servo motor. It is because in the last decade so called digital servo motors were becoming common. The difference between those two is that in analogue servo motor the motor is controlled by the same 50 Hz PWM input signal. In digital servo motor the motor is controlled by a microcontroller with much higher frequency signal. The input signal is the same in the digital servo motor but higher modulation frequency of the motor enables much more precise and faster position determining.

Practice

On the board of module of motors of the HomeLab are two plugs for connecting RC servo motors. The PWM ends of the plugs are connected to the PB5 and PB6 pins of the microcontroller, which alternative functions are outputs of comparing units A and B of the timer 1. Timer 1 is capable of producing PWM signal and due to that the control of motors is very simple in the program. Only difficulty is set-up of the timer.

The timer 1 must be set up in PWM production mode, where the maximum value of the timer is determined with ICR register. With the maximum value changed in the program and in the pace divider of the timer, the precise PWM frequency for controlling the servo motor can be determined. With the comparison register of the timer, lengths of both high semi periods of PWM signal can be determined. The timers have special comparing units which are monitoring the value of the counter and in case it remains equal with the value of the comparison register they change the output value of comparing units. The following is the program code of the servo motor control library of the HomeLab. For the purpose of functionality, it uses parameters for timers which are determined with macro functions. For example, the period is found using F_CPU constant, which marks the clock rate of the microcontroller. When using macros, there is no need to calculate the parameters of timer for different clock rates and the compiler converts the operations with macros to constants anyway, so the program memory is not growing and does not demand more time.

//
// The value of the timer (20 ms)for achieving the full period of PWM.
// F_CPU is the clock rate of the microcontroller which is divided with 
// 50 Hz and 8.
//
//
#define PWM_PERIOD      (F_CPU / 8 / 50)
 
//
// Middle position of PWM servo (5 ms / 20 ms)
// Middle position is 15/200 of full period.
//
#define PWM_MIDDLE_POS  (PWM_PERIOD * 15 / 200)
 
//
// Factor for converting the percents (-100% to 100%)to periods.
// +1 is added to ensure that semi periods would reach to the boundaries 
// of 1 ms and 2 ms or // a little over.
//
#define PWM_RATIO       (PWM_PERIOD / 20 / 2 / 100 + 1)
 
//
// Set-up of the pins.
//
static pin servo_pins[2] =
{
	PIN(B, 5), PIN(B, 6)
};
 
//
// Preparing the servo motor for working.
//
void servomotor_init(unsigned char index)
{
	// The pin of PWM signal for output.
	pin_setup_output(servo_pins[index]); 
 
	// Setup of timer 1.
	// Prescaler = 8
	// Fast PWM mode, where TOP = ICR
	// OUTA and OUTB to low in comparisson.
	timer1_init_fast_pwm(
		TIMER1_PRESCALE_8,
		TIMER1_FAST_PWM_TOP_ICR,
		TIMER1_FAST_PWM_OUTPUT_CLEAR_ON_MATCH,
		TIMER1_FAST_PWM_OUTPUT_CLEAR_ON_MATCH,
		TIMER1_FAST_PWM_OUTPUT_DISABLE);
 
	// Determining the period by maximum value.
	timer1_set_input_capture_value(PWM_PERIOD);	
}
 
//
// Determining the position of the servo motor.
// The parameter of the position is from -100% to +100%.
//
void servomotor_position(unsigned char index, signed short position)
{	
	switch (index)
	{
		case 0:			
			timer1_set_compare_match_unitA_value(
				PWM_MIDDLE_POS + position * PWM_RATIO);
			break;
 
		case 1:
			timer1_set_compare_match_unitB_value(
				PWM_MIDDLE_POS + position * PWM_RATIO);
			break;
	}
}

The example program uses described functions of the library of the HomeLab. In the beginning of the program the first servo motor’s PWM signal generator is started with the servomotor_init function. The value of the position of the servo motor is obtained from the channel number 3 of the analogue-digital converter, where a potentiometer on the board of sensors is connected. To get the range -100 % - +100 % necessary for controlling the servo motor, half of the maximum (512) is subtracted of the ADC value and the result is divided with 5. The result is +/- 102, but small inaccuracy does not count because servo motors also differ by the relation of the PWM signal and revolving angle. Final PWM‘s semi period’s width in applications has to be determined using test-and-error method. Also the remote controls of RC models have corresponding opportunities for precise setup. When the program is started the rotors position of the servomotor is changed according to the position of the potentiometer.

//
// Testing program of the motors module of the HomeLab kit.
//
#include <homelab/adc.h>
#include <homelab/module/motors.h>
 
// Main program
int main(void)
{
	short position;
 
	// Set-up of the ADC.
	adc_init(ADC_REF_AVCC, ADC_PRESCALE_8);
 
	// Set-up of the motor.
	servomotor_init(0);
 
	// Endless loop.
	while (true)
	{
		// Reading the position of the potentiometer and 
		// converting the range of
		// the servo motor.
		position = ((short)adc_get_value(3) - (short)512) / (short)5;
 
		// Determining the position of the servo motor.
		servomotor_position(0, position);
	}
}

Stepper motor

Necessary knowledge: [HW] Motor Module, [AVR] Digital Inputs/Outputs, [LIB] Motors

Theory

Stepper-motor

Stepper motors can generally be divided into unipolar and bipolar steppers. Unipolar stepper motors are characterized by their centre-tapped windings, which divide two coils into four. Stepper motors have neither built-in brushes nor internal electronics, meaning all commutation must be performed externally. The most common commutation type is the open-loop mode: the motor driver energizes the coils following a certain pattern, but uses no feedback. Steps can be missed in case of motor shaft torque overload. Missed steps cause inaccurate positioning. Bipolar stepper motors usually have four wires and two separate coils inside; they have many features similar to those of unipolar steppers. Unipolar stepper motors can be run as bipolar stepper motors, but not vice versa.

Stepper-motors are widely used in applications which demand accuracy. Unlike DC motors, stepper motors do not have brushes nor commutator – they have several independent coils, which are commutated with exterior electronics (drivers). Rotating the rotor is done by commutating coils step by step, without feedback. This is one of the faults in stepper motors – in case of mechanical overloading, when the rotor is not rotating, the steps will be mixed up and movement becomes inaccurate. Two types of stepper motors are distinguished by coils: unipolar and bipolar stepper motors. By construction three additional segments are considered:

Variable reluctance stepper motors have toothed windings and toothed iron rotor. The largest pulling force is when the teeth of both sides are covering each other. In Permanent magnet stepper motor,just like the name hints, are permanent magnets which orientate according to the polarity of the windings. In hybrid synchronous steppers both technologies are used.

Depending on the model of stepper motor, performing one full rotation (360 degrees) of the rotor, demands hundredths of steps of commutations. For stable and smooth movement, appropriate control electronics are used which control the motor according to its parameters (inertia of the rotor, torque, resonance etc.). In addition to control electronics different commutating methods may be applied. Commutating one winding in a row is called Full Step Drive and if the drive is alternated between one and two windings it is called Half Stepping. Cosine micro stepping is also used, allowing specially accurate and smooth controlling.

 

Unipolar stepper-motor

The windings of an unipolar-stepper motor

Unipolar-stepper motor has 5 or 6 leads. According to the scheme of the motor only ¼ of the windings is activated. Vcc lines are usually connected to the positive power supply. During commutation the ends of windings 1a, 1b, 2a and 2b are connected through transistors (transistor array of the motor board ULN2803) only to the ground and that makes their control electronics fairly simple.

Bipolar stepper-motor

The windings of a bipolar stepper-motor.

Bipolar stepper motor differs from unipolar stepper motor by having the polarity of the windings altered during the commutation. Half of the windings are activated together, this allows to gain higher efficiency than unipolar stepper motors. Bipolar stepper motors have four leads, each connected to a different half-bridge (driver L293 on the board of motors). During commutation half-bridges are applying either positive or negative voltage to the ends of the windings. Unipolar motors can be started using bipolar driver: just connect lines 1a, 1b, 2a and 2b of the windings (Vcc will be not connected).

The commutation necessary for controlling stepper-motors with windings at full step mode and half step mode is displayed in the table below. Since in drivers for uni-polar stepper motors only opening of the transistors takes place, the steps are marked by 0 and 1. Controlling of bipolar stepper motors may need more signals and therefore the steps are marked using the polarity of the driver outputs:

Unipolar Bipolar
Step 1A 2A 1B 2B 1A 2A 1B 2B
Full step
1 1 0 0 0 + - - -
2 0 1 0 0 - + - -
3 0 0 1 0 - - + -
4 0 0 0 1 - - - +
Half step
1 1 0 0 0 + - - -
2 1 1 0 0 + + - -
3 0 1 0 0 - + - -
4 0 1 1 0 - + + -
5 0 0 1 0 - - + -
6 0 0 1 1 - - + +
7 0 0 0 1 - - - +
8 1 0 0 1 + - - +

Practice

The goal of this exercise is to start a bipolar stepper motor, which can be replaced by unipolar stepper motor using the above described method. There are drivers, on the board of motors, which must be controlled via four input pins by the microcontroller. Each pin represents the polarity of one end of a winding. The voltage of the end of the winding is positive if the pin is high and negative if the pin is low. To the ends 1A, 1B, 2A and 2B correspond the pins of the microcontroller PB0, PB1, PB2 and PB3.

There is function bipolar_init in the library of the HomeLab for controlling the bipolar stepper motors setting the pins as output and function bipolar_halfstep executes revolving by determined half steps. The commutation is done by the table of half steps, but more complex bit operations are used.

//
// Preparing for controlling the bipolar stepper motor.
//
void bipolar_init(void)
{
	DDRB |= 0x0F;
	PORTB &= 0xF0;
}
 
//
// Moving the bipolar stepper motor by half steps.
//
void bipolar_halfstep(signed char dir,
	unsigned short num_steps, unsigned char speed)
{
	unsigned short i;
	unsigned char pattern, state1 = 0, state2 = 1;
 
	// Insuring the direction +- 1
	dir = ((dir < 0) ? -1 : +1);
 
	// Execution of half-steps.
	for (i = 0; i < num_steps; i++)
	{		
		state1 += dir;
		state2 += dir;
 
		// Creating the pattern.
		pattern = (1 << ( (state1 % 8) >> 1) ) |
		          (1 << ( (state2 % 8) >> 1) );
 
		// Setting the output.
		PORTB = (PORTB & 0xF0) | (pattern & 0x0F);
 
		// Taking a break to wait for executing the step.
		sw_delay_ms(speed);
	}
 
	// Stopping the motor.
	PORTB &= 0xF0;
}

Usage of the functions is demonstrated by the example program which rotates the motor alternately to one direction and then to the other direction 200 half steps. The speed of rotating the motor is determined by the length of the brakes made between the steps. If the break is set to be too short, the motor can not accomplish the turn due to the inertia of the rotor and the shaft does not move.

//
// The test program for the bipolar stepper motor of the motor's
//module of the HomeLab.
//
#include <homelab/module/motors.h>
 
// Main program
int main(void)
{
	// Set up of the motor.
	bipolar_init();
 
	// Endless loop.
	while (true)
	{
		// Turning the rotor 200 half steps to one direction 
		// at speed of 30 ms/step.
		bipolar_halfstep(+1, 200, 30);
 
		// Turning 200 half steps to the other direction 
		// at speed 30 ms/step.
		bipolar_halfstep(-1, 200, 30);
	}
}