This shows you the differences between two versions of the page.
en:mecfuture_book [2012/04/26 13:51] – created raivo.sell | en:mecfuture_book [2020/07/20 09:00] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | <> | + | ====== Algorithms and flowchart====== |
+ | |||
+ | The algorithm is a step-by-step instruction, | ||
+ | |||
+ | 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)//). | ||
+ | |||
+ | {{: | ||
+ | |||
+ | <pagebreak> | ||
+ | ==== 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/ | ||
+ | |||
+ | 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 are devices converting any kind of physical attributes (temperature, | ||
+ | |||
+ | 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, | ||
+ | |||
+ | ===== Photoresistor ===== | ||
+ | |||
+ | //Necessary knowledge: [HW] [[en: | ||
+ | |||
+ | ==== Theory ==== | ||
+ | |||
+ | [{{ : | ||
+ | [{{ : | ||
+ | |||
+ | 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 | ||
+ | | Purple | ||
+ | | Blue | 450 – 500 | | ||
+ | | Green | 500 – 570 | | ||
+ | | Yellow | ||
+ | | Orange | ||
+ | | Red | 610 – 700 | | ||
+ | |||
+ | A range of working temperature is set for photoresistor. Wishing the sensor to work at different temperatures, | ||
+ | |||
+ | 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 | ||
+ | | Full moon | 0,1 | | ||
+ | | Dusk | 1 | | ||
+ | | Auditorium | ||
+ | | Class room | 30 | | ||
+ | | Sunset or sunrise | ||
+ | | Operating room (hospital) | 500 - 1000 | | ||
+ | | Direct sun light | ||
+ | |||
+ | ==== 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 // | ||
+ | |||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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Ω (R< | ||
+ | |||
+ | log(E< | ||
+ | E< | ||
+ | |||
+ | 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 (U< | ||
+ | The formula is following: | ||
+ | |||
+ | U< | ||
+ | |||
+ | From the formula for voltage divider(check the chapter on voltage divider) the resistance of the upper photoresistor (R< | ||
+ | |||
+ | R< | ||
+ | |||
+ | 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 = 10< | ||
+ | = 10< | ||
+ | = (18.5< | ||
+ | |||
+ | |||
+ | By calculating the constant in front of the variable of the field R, the expression remains follows: | ||
+ | |||
+ | E = 255,84 * R< | ||
+ | |||
+ | 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. | ||
+ | < | ||
+ | <code c> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | // 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, | ||
+ | |||
+ | // Name of the program | ||
+ | lcd_gfx_write_string(" | ||
+ | |||
+ | // Setting the ADC | ||
+ | adc_init(ADC_REF_AVCC, | ||
+ | |||
+ | // Endless loop. | ||
+ | while (true) | ||
+ | { | ||
+ | // Reading the average value of the photoresistor | ||
+ | adc_value = adc_get_average_value(1, | ||
+ | |||
+ | // 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, | ||
+ | |||
+ | // Converting the intensity of light to text | ||
+ | sprintf(text, | ||
+ | |||
+ | // Displaying it on the LCD | ||
+ | lcd_gfx_goto_char_xy(3, | ||
+ | lcd_gfx_write_string(text); | ||
+ | |||
+ | // Delay 500 ms | ||
+ | sw_delay_ms(500); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== 1-wire temperature sensor ===== | ||
+ | |||
+ | //The necessary knowledge: [HW] [[en: | ||
+ | [HW] [[en: | ||
+ | |||
+ | ==== Theory ==== | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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' | ||
+ | |||
+ | 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 " | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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' | ||
+ | |||
+ | * Power supply: +3...+5 VDC | ||
+ | * Temperature measurement range: -55...+100 °C | ||
+ | * Wire length: 2 m | ||
+ | * Datasheet [[http:// | ||
+ | |||
+ | In the example below, 1-wire temperature sensor takes measurements and displays the results on HomeLab' | ||
+ | |||
+ | 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' | ||
+ | |||
+ | Colors of the wires for connecting the sensor: | ||
+ | * Green - Optional VDD pin. VDD must be grounded for operation in parasite power mode | ||
+ | * White - Data Input/ | ||
+ | * Brown - Ground. | ||
+ | |||
+ | Example code enabling to read the temperature with 1-wire protocol is shown below. It is important to include | ||
+ | |||
+ | < | ||
+ | |||
+ | <code c> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include " | ||
+ | #include " | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | // Sensor queue number and sensor' | ||
+ | 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' | ||
+ | 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' | ||
+ | // 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(& | ||
+ | |||
+ | // 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,& | ||
+ | { | ||
+ | sw_delay_ms( 750 ); | ||
+ | |||
+ | // Measurements are saved in decicelsius. In case of error, | ||
+ | // the error flag is set. | ||
+ | if (DS18X20_read_decicelsius(& | ||
+ | { | ||
+ | // Displaying the word " | ||
+ | lcd_gfx_goto_char_xy(2, | ||
+ | lcd_gfx_write_string(" | ||
+ | |||
+ | // Displaying degree sign | ||
+ | lcd_gfx_goto_char_xy(13, | ||
+ | lcd_gfx_write_string(" | ||
+ | |||
+ | // Making the readings to strings and adding +/-. | ||
+ | DS18X20_format_from_decicelsius( decicelsius, | ||
+ | |||
+ | // Displaying the temprerature | ||
+ | lcd_gfx_goto_char_xy(7, | ||
+ | lcd_gfx_write_string(s); | ||
+ | |||
+ | // Displaying sensors queue number. | ||
+ | // Firstly it's converted to a string. | ||
+ | lcd_gfx_goto_char_xy(0, | ||
+ | sprintf(sensor_nr, | ||
+ | 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, | ||
+ | lcd_gfx_write_string(" | ||
+ | error = 0; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | lcd_gfx_goto_char_xy(1, | ||
+ | lcd_gfx_write_string(" | ||
+ | } | ||
+ | sw_delay_ms(500); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== Lidar ===== | ||
+ | |||
+ | |||
+ | //Necessary knowledge: [HW] [[en: | ||
+ | |||
+ | ==== Theory ==== | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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. | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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. | ||
+ | |||
+ | |||
+ | [{{: | ||
+ | |||
+ | |||
+ | 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 ==== | ||
+ | [{{ : | ||
+ | |||
+ | |||
+ | 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. | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | To make the SICK operational, | ||
+ | |||
+ | 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: | ||
+ | |||
+ | Decimal Form: | ||
+ | |||
+ | 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: | ||
+ | |||
+ | Decimal Form: | ||
+ | |||
+ | Following example shows how to initiate Lidar and get the count of package. | ||
+ | |||
+ | <code c> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | // 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, | ||
+ | lcd_gfx_write_string(" | ||
+ | |||
+ | // 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, | ||
+ | usart_send_char(port, | ||
+ | usart_send_char(port, | ||
+ | usart_send_char(port, | ||
+ | usart_send_char(port, | ||
+ | usart_send_char(port, | ||
+ | usart_send_char(port, | ||
+ | usart_send_char(port, | ||
+ | } | ||
+ | |||
+ | // 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, | ||
+ | usart_send_char(port, | ||
+ | usart_send_char(port, | ||
+ | usart_send_char(port, | ||
+ | usart_send_char(port, | ||
+ | usart_send_char(port, | ||
+ | usart_send_char(port, | ||
+ | usart_send_char(port, | ||
+ | } | ||
+ | |||
+ | // Remembers the last keys values. | ||
+ | old_value1 = new_value1; | ||
+ | old_value2 = new_value2; | ||
+ | |||
+ | // Try to read serial port | ||
+ | if (usart_try_read_char(port, | ||
+ | { | ||
+ | // 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) | ||
+ | { | ||
+ | // | ||
+ | count++; | ||
+ | |||
+ | // | ||
+ | lcd_gfx_goto_char_xy(0, | ||
+ | |||
+ | sprintf(text, | ||
+ | |||
+ | lcd_gfx_write_string(text); | ||
+ | |||
+ | i=0; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== Color sensor ===== | ||
+ | |||
+ | //Necessary knowledge: [HW] [[en: | ||
+ | |||
+ | ==== Theory ==== | ||
+ | |||
+ | [{{ : | ||
+ | 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, | ||
+ | |||
+ | 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 sensors have a variety of applications including detection of environment, | ||
+ | |||
+ | |||
+ | |||
+ | ==== Practice ==== | ||
+ | |||
+ | The ColorPAL from Parallax ([[http:// | ||
+ | |||
+ | 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. | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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, | ||
+ | |||
+ | ColorPAL sensor requires only three connections: | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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. | ||
+ | |||
+ | <code c> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | // 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, | ||
+ | lcd_gfx_write_string(" | ||
+ | |||
+ | while (1) | ||
+ | { | ||
+ | // Send a command to the sensor. | ||
+ | usart_send_string(port, | ||
+ | |||
+ | // 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> | ||
+ | { | ||
+ | // Store the received data character. | ||
+ | data[i-3] = c; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Converting the data to the suitable form | ||
+ | // and print it on the screen. | ||
+ | sprintf(red, | ||
+ | lcd_gfx_goto_char_xy(0, | ||
+ | lcd_gfx_write_string(red); | ||
+ | |||
+ | sprintf(green, | ||
+ | lcd_gfx_goto_char_xy(0, | ||
+ | lcd_gfx_write_string(green); | ||
+ | |||
+ | sprintf(blue, | ||
+ | lcd_gfx_goto_char_xy(0, | ||
+ | lcd_gfx_write_string(blue); | ||
+ | |||
+ | // Delay | ||
+ | sw_delay_ms(500); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== Force sensor ===== | ||
+ | |||
+ | //Necessary knowledge: [HW] [[en: | ||
+ | |||
+ | ==== Theory ==== | ||
+ | |||
+ | [{{ : | ||
+ | [{{ : | ||
+ | |||
+ | 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' | ||
+ | |||
+ | FSR consists of a conductive polymer, which changes resistance in a predictable manner following application of force to its surface. | ||
+ | |||
+ | Force-sensing resistors are commonly used to create pressure-sensing " | ||
+ | |||
+ | |||
+ | ==== Practice ==== | ||
+ | |||
+ | [{{ : | ||
+ | [{{ : | ||
+ | |||
+ | 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. | ||
+ | |||
+ | 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: | ||
+ | |||
+ | R< | ||
+ | |||
+ | Where: | ||
+ | R< | ||
+ | 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 C< | ||
+ | |||
+ | C< | ||
+ | |||
+ | 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: | ||
+ | |||
+ | F< | ||
+ | |||
+ | The example program of the force sensor shows the measured force (Newtons) and weight (kg) on the LCD. | ||
+ | |||
+ | < | ||
+ | |||
+ | <code c> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | // 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, | ||
+ | |||
+ | // Print the name of the program. | ||
+ | lcd_gfx_write_string(" | ||
+ | |||
+ | // Set the ADC. | ||
+ | adc_init(ADC_REF_AVCC, | ||
+ | |||
+ | // An endless loop. | ||
+ | while (true) | ||
+ | { | ||
+ | // Converting and averaging channel 0 value. | ||
+ | value = adc_get_average_value(0, | ||
+ | |||
+ | // 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; // | ||
+ | |||
+ | // Move the cursor to the right of the screen. | ||
+ | lcd_gfx_goto_char_xy(1, | ||
+ | |||
+ | // Calculate the force. | ||
+ | force = conductance / 80; | ||
+ | sprintf(text, | ||
+ | |||
+ | // Printing of the force. | ||
+ | lcd_gfx_goto_char_xy(1, | ||
+ | lcd_gfx_write_string(text); | ||
+ | |||
+ | // Printing and calculating of the weight. | ||
+ | lcd_gfx_goto_char_xy(1, | ||
+ | weight = force / 9,8; | ||
+ | sprintf(text, | ||
+ | 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] [[en: | ||
+ | |||
+ | ==== Theory ==== | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | Permanent magnet DC motors are very common in different applications, | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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. | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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, | ||
+ | |||
+ | ^ Input A ^ Input B ^ Output A ^ Output B ^ Result | ||
+ | | 0 | ||
+ | | 1 | ||
+ | | 1 | ||
+ | | 0 | ||
+ | |||
+ | 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. | ||
+ | |||
+ | <code c> | ||
+ | // 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], | ||
+ | pin_set_to(dcmotor_pins[index][1], | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | With the array // | ||
+ | |||
+ | 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. | ||
+ | |||
+ | <code c> | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | // 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, | ||
+ | |||
+ | // Endless loop | ||
+ | while (true) | ||
+ | { | ||
+ | // One motor revolves in one direction and the other | ||
+ | // one to other direction. | ||
+ | dcmotor_drive(0, | ||
+ | dcmotor_drive_pwm(1, | ||
+ | |||
+ | // 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] [[en: | ||
+ | |||
+ | |||
+ | ==== Theory ==== | ||
+ | [{{ : | ||
+ | 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. | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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). | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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), | ||
+ | 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 | ||
+ | |||
+ | |||
+ | 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. | ||
+ | |||
+ | <code c> | ||
+ | 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 - // | ||
+ | |||
+ | 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. | ||
+ | |||
+ | <code c> | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | int main(void) | ||
+ | { | ||
+ | // DC motor 0 init with no prescaler | ||
+ | dcmotor_drive_pwm_init(0, | ||
+ | |||
+ | while(1) | ||
+ | { | ||
+ | // DC motor drive with half of the nominal speed | ||
+ | dcmotor_drive_pwm(0, | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Another example program which controls first DC motor (DC motor connector 0) with potentiometer from Sensor module. | ||
+ | |||
+ | <code c> | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | int main(void) | ||
+ | { | ||
+ | int speed; | ||
+ | |||
+ | // Adjusting ADC | ||
+ | adc_init(ADC_REF_AVCC, | ||
+ | |||
+ | // DC motor 0 init with no prescaler | ||
+ | dcmotor_drive_pwm_init(0, | ||
+ | |||
+ | while(1) | ||
+ | { | ||
+ | // Potentiometer is connected to channel 3 | ||
+ | // Average of 4 samples are acquired | ||
+ | speed = adc_get_average_value(3, | ||
+ | |||
+ | // 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, | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== Servomotor ===== | ||
+ | |||
+ | //Necessary knowledge: [HW] [[en: | ||
+ | |||
+ | ==== Theory ==== | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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), | ||
+ | an external pulse-width modulation (PWM) signal. If a signal meets RC servo timing | ||
+ | requirements, | ||
+ | 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 (// | ||
+ | |||
+ | 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. | ||
+ | |||
+ | ~~CL~~ | ||
+ | |||
+ | ==== 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, | ||
+ | |||
+ | |||
+ | 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, | ||
+ | |||
+ | |||
+ | <code c> | ||
+ | // | ||
+ | // 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 | ||
+ | |||
+ | // | ||
+ | // Middle position of PWM servo (5 ms / 20 ms) | ||
+ | // Middle position is 15/200 of full period. | ||
+ | // | ||
+ | #define PWM_MIDDLE_POS | ||
+ | |||
+ | // | ||
+ | // 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 | ||
+ | |||
+ | // | ||
+ | // 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 // | ||
+ | |||
+ | <code c> | ||
+ | // | ||
+ | // Testing program of the motors module of the HomeLab kit. | ||
+ | // | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | // Main program | ||
+ | int main(void) | ||
+ | { | ||
+ | short position; | ||
+ | |||
+ | // Set-up of the ADC. | ||
+ | adc_init(ADC_REF_AVCC, | ||
+ | |||
+ | // 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, | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | ===== Stepper motor ===== | ||
+ | |||
+ | //Necessary knowledge: [HW] [[en: | ||
+ | |||
+ | ==== Theory ==== | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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, | ||
+ | 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, | ||
+ | * Variable Reluctance Stepper (high accuracy, low torque, low price) | ||
+ | * Permanent Magnet Stepper (low accuracy, high torque, low price) | ||
+ | * Hybrid Synchronous Stepper (high accuracy, high torque, high price) | ||
+ | |||
+ | 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. | ||
+ | |||
+ | |||
+ | < | ||
+ | |||
+ | **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** | ||
+ | |||
+ | [{{ : | ||
+ | |||
+ | 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: | ||
+ | |||
+ | |||
+ | ^ ^ | ||
+ | ^ 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. | ||
+ | |||
+ | There is function // | ||
+ | |||
+ | |||
+ | <code c> | ||
+ | // | ||
+ | // 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. | ||
+ | |||
+ | <code c> | ||
+ | // | ||
+ | // The test program for the bipolar stepper motor of the motor' | ||
+ | //module of the HomeLab. | ||
+ | // | ||
+ | #include < | ||
+ | |||
+ | // 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, | ||
+ | |||
+ | // Turning 200 half steps to the other direction | ||
+ | // at speed 30 ms/step. | ||
+ | bipolar_halfstep(-1, | ||
+ | } | ||
+ | } | ||
+ | </ |