-

hey viewer, we're moving!

We are currently transitioning to a new web system, so we are not updating this wikisite anymore.

The public part of the new web system is available at http://www.ira.disco.unimib.it


INFIND2011/12 Laser Range finder

From Irawiki

Jump to: navigation, search

Students working on this project:

Contents

Introduction

text
Poomba during a scan task

The project aims to build a high level structure for controlling a laser range equipment mounted on a servo control to give us the chance to build a planimetry of the surroundings from the laser point of view. In order to let us operate in the best possible conditions, we have built from scratch the support for the servo on which we have mounted the Parallax Laser Range Finder. Last but not least, we added to the mounting structure two wheels and a pair of motors and we called it “Poomba” (it’s like "Roomba" but it doesn’t clean the room: it’s the Chinese version). In addition, the robot has been equipped with a digital compass in order to achieve a better scanning resolution and to provide an absolute reference system to the laser readings (magnetic north).

So the key features of what we have done are:

  • high level serial protocol (tested over the air with bluetooth connection)
  • integration of laser, digital compass and servo control in a single virtual device for high level data fusion
  • motor control to move the “robot” and make more measurements
  • remote data acquisition
  • interrupt based firmware

Tasks

Serial Communication: Giulio Bider, Alessio Vertemati

Communication Protocol: Marco Covelli, Alessio Vertemati

Hardware and software interrupts: Marco Covelli, Simone Bonetti

Real Time Clock: Alessio Vertemati

Magnetometer values with PWM input: Simone Bonetti, Marco Mobilio

Servo control with PWM: Marco Mobilio, Giulio Bider

Direct Memory Access: Marco Covelli, Marco Mobilio, Giulio Bider

Overall integration: Marco Covelli, Alessio Vertemati, Giulio Bider, Marco Mobilio, Simone Bonetti

Sensors and actuators

Parallax Range Finder

The Parallax Laser Range Finder (LRF) module is a distance-measuring instrument that uses laser technology to calculate the distance to a target object. The distance to a target object is calculated by optical triangulation using simple trigonometry between the centroid of laser light, CMOS camera, and the object itself.

The laser gives us an optimal measurement range between 150 and 1220 mm with an average error of the 4%. The laser takes about 1 second to complete a single measurement.

A single point optical triangulation system uses a laser light source, a lens and a linear light sensitive sensor. The geometry of an optical triangulation system is illustrated in Figure 1.

text
Parallax laser mounted on Poomba structure

A light source (typically a laser) illuminates a point on an object, an image of this light spot is then formed on the sensor surface, as the object is moved the image moves along the sensor, by measuring the location of the light spot image the distance of the object from the instrument can be determined provided the baseline length and the angles are known. The most important component in the optical triangulation system is the sensor. There are two types of sensor: the Position Sensitive Detector (PSD) and the Charged Coupled Device (CCD). The PSD is often chosen for devices measuring over a small range providing an analogue output which is ideal for use with pass-fail applications. The CCD sensor has the advantage of better geometric stability and produces a signal well suited to providing a digital output.

text
Figure 1

Magnetometer

text
Magnetometer

The CMPS10 module is a tilt compensated compass. Employing a 3-axis magnetometer and a 3-axis accelerometer. The CMPS10 produces results in the range of 0-3599, representing 0°-359.9°. The output of the three sensors measuring x, y and z components of the magnetic field, together with the pitch and roll are used to calculate the bearing. The CMPS10 module requires a power supply at 3.3 - 5V and draws a nominal 25mA current. There are three ways of getting the bearing from the module. A serial interface, an I2C interface or a PWM output. We opted for the PWM output.

We use the magnetometer in order to get an absolute reference over the servo rotation.

As the compass is rotated a high pulse will be generated that is proportional to the current angle. The pulse width varies from 1mS (0°) to 36.99mS (359.9°) – in other words 100uS/° with a +1mS offset. The signal goes low for 65mS between pulses, so the cycle time is 65mS + the pulse width (66ms-102ms).

text
PWM pulses of 20ms - 1ms offset = 19ms = 190°

Updates of the tilt compensated heading occur at 75Hz with the data is filtered by means of a 45 sample buffer, this means a complete refresh of the buffer is achieved every 640ms. Raw data from the magnetometer and accelerometer is available every 13.3ms.

Compasses work by detecting the magnetic fields produced by the hot rotating iron core at the centre of the earth. The strength of the earth's magnetic field is about 0.5 to 0.6 gauss and has a component parallel to the earth's surface that always points toward the magnetic north pole. Traditional compasses work by using these fields to rotate a ferrous metal rod in a small container. The magnetic fields align the metal rod along this component to point to magnetic north. Using this information, along with a scale on the outside of the compass we can work out our heading (the direction we are facing).

Like other compasses, the CMPS10, is a magneto-resistive sensor on three axis (for a 3 axis magnetometer) which adjust current flow through the sensor. By applying a scale to this current, we can calculate the magnetic force (measured in Gauss) on the sensor.

An important thing to understand about magnetometers, called compasses for sake of simplicity is that they do not provide us with a direction. They provide us with a way to measure magnetism which we can use to calculate a direction. The compass is only created once we use the magnetometer in some calculations, as a whole system.

A simple calculation we can use to create a compass is below. When the device is level, (pitch Xb and roll Yb are at 0 degrees). The compass heading can be determined like so:

text
Compass calculation

The local earth magnetic field has a fixed component Hh on the horizontal plane pointing to the earths magnetic north. This is measured by the magnetic sensor axis XM and YM (here named as Xh and Yh). Using this we can calculate the heading angle using this simple equation:

Heading = arctan(\frac{Y_h}{X_h})

A problem that traditional compasses have is that they need to be held flat to function. If you hold a compass at right angles it will not work at all, and if you tilt it to 45 degrees the reading will be more inaccurate the further the compass is tilted. This problem occurs because the compass is only using the X and Y axis of the earths magnetic field (the compass needle is fixed onto a bearing that will only allow the needle to swivel on one axis). When the compass is not parallel to these axis the amount of magnetism felt by the needle will change based on how out of alignment the compass is to these axis.

Of course, one cannot simply add this value to the result to get an accurate heading. We first need to knowhow the device is tilted, so we know how to integrate the Z axis measurement properly, thus correct for our tilt. In other words, we need to know our orientation first. We will do this by incorporating a triple axis accelerometer into our compass system.

When the device is tilted, pitch and roll angles are not 0°. The diagram below the pitch and roll angles are measured by a 3 axis accelerometer. XM, YM and ZM (the measurement axis on the magnetometer) will be compensated to obtain Xh and Yh. Once have corrected the Xh and Yh measurements, we can use the first equation to calculate our heading.

text
Tilt compensated compass calculation

Xh = XM * cos(Pitch) + ZM * sin(Pitch)

Yh = XM * sin(Roll) * sin(Pitch) + YM * cos(Roll) − ZM * sin(Roll) * cos(Pitch)

Once we have tilt compensated Xh and Yh, we can now use the same equation as before to find our heading!

Heading = arctan(\frac{Y_h}{X_h})

Servo

Hitec HS-422 Standard Deluxe Servo.

This Servo is controlled by using the Pulse Width Modulation (PWM) technique as specified by this extract from the usage manual:

  • Pulse Width Control 1500usec Neutral
  • operating angle: 45° / one side pulse traveling 400usec
  • direction: clock wise/pulse traveling 1500 to 1900usec

Pulse Width Modulation is a really clever way to use electricity. Let’s say I wanna control the speed of a motor (or a servo in this case), well I could use a resistor but holding back all that power can make my resistor really hot and also I’m wasting power. Instead I can supply full power to the motor but in short pulses. The base fact is that a motor takes some time to respond to a broad changes sold by power ring. With the use of pulses our servo behaves as if it’s getting steady voltage somewhere between 4.8 and 6 Volts (or in a more general way between 0 and 12V). The voltage perceived by the servo can be determined by taking the amount of time our pulse wave is on versus off and we call this measure the duty cycle (expressed between 0 and 1, or in percentage if you prefer), then we multiply that amount by the high voltage level and we get the signals average voltage.

The chosen servo makes use of PWM to rotate at 180 degrees and accordingly to the duty cycle we could rotate it clockwise or counterclockwise. (detailed configuration in the Timers section)

Motors and drivers

MD25 - Dual 12Volt 2.8Amp H Bridge Motor Drive

text
Motor driver board

The two EMG30 motors mounted on the robot are driven by the MD25, an H Bridge Motor Drive that communicate through serial. It features the reading from the motors encoders and is able to provide counts for determining distance traveled and direction. It is possible to drive the two motors independently or with combined control. Only 12v is required to power the module and onboard 5v regulator can supply up to 1A peak, 300 mA continuously to external circuitry. Variable acceleration and power regulation are also included, plus the steering feature, available for combined control that allow to turn by sending a single instruction. In order to communicate with the board, the serial port configuration must be as follow:

  • baud rate 9600 bps
  • 1 start bit
  • 2 stop bits
  • no parity

Bluetooth

Bluetooth device is used to receive messages sent from controller and forward serial values through serial of port of STM32 to control Poomba via wireless connection.

The model chosen is the RN42-9273 from Roving Networks Bluetooth™.

We use as operation mode “Slave”, in this way others Bluetooth devices can discover and connect to this device. Outbound connections are also possible with this mode.

In order to communicate and transfer packet data, the serial port configuration must be the follow:

  • baud rate 115.200
  • 8 bits
  • no parity
  • 1 as stop bit
  • hardware control flow disabled
text
Bluetooth module on the rooftop breadboard

Internal board devices

USART

The onboard USART is used to drive serial communications towards and from the STM32 and the various sensors and actuators.

  • Bluetooth (input/output commands and data serial interface) - USART 1, pin PA9 e PA10
  • Motor - USART 2, pin PB10 e PB11
  • Laser - USART 3, pin PA2 e PA3

Timers

We use 3 STM32 internal timers: the first timer (TIM 2) is used to drive the servo in PWM mode; the second one (TIM 3) is used to create a known fixed time delay to provide the peripheral the needed amount of time for initialization. Lastly, the timer 4 (TIM 4) is used in PWM input mode to convert magnetometer PWM pulses to numeric values.

The general purpose Timer 2 (TIM2) has been used to control PWM duty cycle in order to make servo rotations.

Given the fact that the servo has a clear specification we configured the timer as reported in this code extract from the firmware:

//set timer period
TIM2->ARR = 20000;
//temporal OC disable
TIM2->CCER &= ~TIM_CCER_CC2E;
//set PWM mode 1
TIM2->CCMR1 |= 0x6 << 12;
//set duty cycle to 0
TIM2->CCR2 = 0;
//enable OC
TIM2->CCER |= TIM_CCER_CC2E;
//enable timer counter
TIM2->CR1 |= TIM_CR1_CEN;
//set pwm duty to SERVO_INIT_VALUE
TIM2->CCR2 = SERVO_INIT_VALUE;


The general purpose Timer 3 (TIM3) is used to create the delay function. The code extract below is from the init_delay_timer function in our main file.

// Activate TIM3 clock
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->CR1 = 0;
TIM3->CR2 = 0;
// prescaler 36000
// +1 every 0.5 millisecond
TIM3->PSC = 0x8CA0;
// continuos mode
TIM3->CR1 |= TIM_CR1_OPM;

We set the prescaler in order to get a counter increment every 0.5 milliseconds. The delay function (located in the utils.c file) uses the prescaled Timer 3 as exposed in the next code chunk:

TIM3->ARR = milliseconds*2;
//enable timer counter
TIM3->CR1 |= TIM_CR1_CEN;
// wait the timer
while(!(TIM3->SR & TIM_SR_UIF)) {};

As pointed out from the first line of this code portion, the delay functions takes a int parameter called milliseconds, as the fact the prescaler of the timer is configured to give a clock cycle at about 0.5 millisecond we simply multiply by 2 the requested delay. In order to get a blocking function we wait the counter to complete its counting cycle with a simple while.

And last but not least, the Timer 4. We use the Timer 4 to read PWM input pulses. In order to achieve this behaviour we first have to set the timer in capture mode (as pointed out by the code extract below); then we map two IC signals on the PWM input channel (TIM4_CH1) and we set them to be active on edges with opposite polarity. We choose the rising edge signal as the trigger input (counter resets on PWM rising edge).

//prescaler 720 (for discrimitating to 10us)
TIM4->PSC = 0x2D0;
//set TI on channel CH1
TIM4->CR2 &= ~TIM_CR2_TI1S;
/* Initialize capture/mode for PWM period */
TIM4->CCMR1 |= TIM_CCMR1_CC1S_0;
/* Polarity for TI1FP1 rising edge */
TIM4->CCER &= ~TIM_CCER_CC1P;
/* Initialize capture/mode for PWM duty cycle */
TIM4->CCMR1 |= TIM_CCMR1_CC2S_1;
/* Polarity for TI1FP2 falling edge */
TIM4->CCER |= TIM_CCER_CC2P;
/* Trigger input on TI1 */
TIM4->SMCR |= (TIM_SMCR_TS_2 | TIM_SMCR_TS_0);
/* Reset counter on PWM rising edge */
TIM4->SMCR |= TIM_SMCR_SMS_2;
/* Start capture mode */
TIM4->CCER |= (TIM_CCER_CC1E | TIM_CCER_CC2E);

Because the PWM signal changes between 66ms and 102ms we decided to set the timer prescaler to 720 to get a tick every 10us and thus a resolution of a tenth of degree.

Direct Memory Access

While the Cortex CPU can be used to move data between peripherals and the internal SRAM, many of these operations can be automated with the internal DMA unit. The STM32 DMA unit has up to twelve independently configurable channels that can perform autonomous transfers from memory to memory, peripheral to memory, memory to peripheral and peripheral to peripheral. The memory to memory transfers will be performed as fast as the DMA channel can move the data. In the case of the peripheral transfers, the DMA unit is placed under the control of a selected peripheral and the data is transferred on demand to or from the controlling peripheral. As well as transferring blocks of data, each DMA unit can continually transfer data to a circular buffer. Since most communications peripherals do not contain any FIFO buffer, the DMA units are used to stream data to and from buffers in SRAM. The DMA unit has been specifically designed for the STM32 and as such it is optimised for the short but frequent data transfers that you typically find in microcontroller applications.

In our firmware the DMA has been used to handle the communication from the magnometer to the memory and from the bluetooth driver to enable async data transfer through the serial port.

To avoid any possible override on the buffer of the DMA we decide to implemente a FIFO queue; we choose to have a length of the queue of 8 buffers (which are 32 Byte each) but of course it's a parametric value that could be modified at any time.

We used the DMA1 channel 4 for the serial communication with the bluetooth interface (memory to peripheral) and the channel 1 on the same DMA for the magnetometer (peripheral to memory).

Scanner (virtual device)

text
Partial view of the scanner source code

Scanner is a virtual device created entirely in software. This device has 3 complementary functions: the main function, called scanning_routine, manages both retrieving data from sensors and sending commands to serial controller and to servo, to rotate the support structure of the Parallax Laser. The second function, called scanning_step, is used to send to servo new goal position and send to laser the message to do a new measurement; the third one, called pack_msg, is used to get the absolute angle values from the digital compass using DMA and assemble message. Collateral functions are: (1) stopping the scan and move the servo in our custom idle position (at 90°, viewing Poomba from behind, so to look straight forward) and (2) convert PWM value into degrees.

With this virtual device we automatically perform a scan from 0 to 180 degrees.

RTC

We use the STM32 internal Real Time Clock in order to get the timestamp to be attached to messages sent from the robot to the controller.

As RTC clock source we have chosen the LSI oscillator because the suggested LSE oscillator don't enter in the ready state (indicated by the RCC_BDCR_LSERDY bit on the BDCR register of the RCC) Since the LSI oscillator is at about 4000kHz we set the prescaler of the RTC to 39.999 accordingly to the next formula to get 1Hz period:

\frac {RTCCLK}{RTCPR} = \frac {40.000 kHz}{39999 + 1}

It's important to point out that we don't use the RTC as a complete calendar but only to get a temporal counting sequence to be attached before sending messages to the controller.

We expect in the next days to add a message to the serial protocol to give the possibility to configure the RTC counter in order to realize a sort of NTP synchronization.

As documented in the STM32 manual the LSI oscillator is not battery powered so the RTC clock will stop counting when the STM32 board doesn't receive external alimentation, but we save the counter on the backup domain in order to be restored when the power to the STM32 resumes.

Firmware

We have built a simple but highly “component separated” firmware to handle external messages (received as interrupt) on the default serial port (USART1, PA9 and PA10)

Every physical peripheral has it’s own device driver that abstracts the hardware operations that have to be done to control the device itself. We have defined a basic interface abstraction layer that every device needs in order to be correctly used (the word “device” is used as placeholder for motor, bluetooth, servo, laser):

void device_init(void);
this function will be called during the firmware init procedure (enlighted by the LED4 of the STM32 board)
void device_send(const char msg);
this function will be called from the message dispatcher. To simplify the message handling the message dispatcher will call a parsing function to get only the payload needed for the device. If a device has its parse_command function this will be called before the device_send

This interface defines only the need of an init, a message send function to receive commands from the message dispatcher or interrupt handlers. Every device must raise a software interrupt (we will discuss it later) to expose data to the message dispatcher and consequently to the controller.

We have also defined a protocol abstraction for each device that parses received commands (this is optional, the default behaviour is to use the bluetooth message parser to get only the payload of the received message)

As you might think some simplifications has been done to simplify the message management and its memory footprint. This simplifications are:

  • sender and receiver must be uniquely identifiable by a single char
  • the device_send (if practicable) can only accept one char

Serial Communication Protocol

The Serial Communication Protocol is a high level packet message protocol created to simplify the user interaction with a custom build robot. This protocol is based on the sender/receiver message communication concept, in other words every message has a sender and a receiver so the firmware loaded onto the STM32 (and in particular the message dispatcher) can forward the received message to the device driver handler in order to get interpreted and executed. As just said before the firmware is based on interrupts so it reacts only when someone calls it.

The message packet transmitted and received has variable length and has this structure:

sender$receiver$timestamp$payload#

While sender and receiver have got a 1 char fixed length, both timestamp and payload have variable lengths. The payload also depends on the device that receives the message. The implemented parser uses the $ as separator character to divide the message into its components and uses the # character to identify the end of the packet.

The sender/receiver paradigm will also be used internally in the firmware for inter-device communication.

The next table displays the implemented possibile receivers for a message. Of course the sender of the message could be any device (or device driver) configured.

Device (message receiver) Character ID Payload
Laser L U, R (details in the Laser Driver Protocol Section)
Motors M F, S, B, L, R, V (details in the Motor Driver Protocol Section)
Servo S PWM value corrisponding to the rotation (630 (= 0°) to 2490 (= 180°))
Scanner P S or F
Controller C scanning measurement, in the format: distance:angle

In order to get things done as soon as possible our Protocol and Communication leader has developed a java class to assemble the serial protocol packets used for testing purposes.

Laser Driver Protocol

Laser, whose id is the letter L, can receive these high level commands:

  • U : automatic detection of baud rate of the host
  • R : Single range measurement (returns a 4-digit decimal value in millimeters)

The laser output is a single 4-digit int value that represents the distance in millimeters from the target object, as Parallax specification the target object needs to be between 150 mm and 1220mm to get the maximum precision.

Motors Driver Protocol

Motors, whose id is the letter M, can receive these high level commands

  • F forward: go forward
  • B backward: go backward
  • L left: turn left
  • R right: turn right
  • S stop: brake and halt the execution of the previously received command
  • V speed: set the speed. Acceptable values are in the range 1 to 127. The motor speed complete payload is V:value
  • T disable timeout: disables the command security timeout. With the timeout disabled every command received will run indefinitely. When enabled all commands will be executed until the timeout automatically raises the stop command (this command is automatically configured by the motors init procedure)

Please take into account that steering while going forward or backward is not fully supported, you need to stop before stir to left or right.

Given the fact that the motor board has its own low level serial protocol we have connected the motor board to the USART3 (pin PB10, PB11).

The next table resumes the translation from high level command to motor understandable commands:

High level command Low level command
F 0x00 0x31 (0x80 + speed) 0x00 0x32 (0x80 + speed)
B 0x00 0x31 (0x80 - speed) 0x00 0x32 (0x80 - speed)
L 0x00 0x31 (0x80 - speed) 0x00 0x32 (0x80 + speed)
R 0x00 0x31 (0x80 + speed) 0x00 0x32 (0x80 - speed)
S 0x00 0x31 0x80 0x00 0x32 0x80
T 0x00 0x38

We have chosen to control each motor separately instead of using the preconfigured double motor control routines to get a much more control over the robot handling.

Servo Driver Protocol

The protocol involves sending a message to the servo (S) with a payload containing the PWM value to which the servo must be rotated. The value must be between 630 and 2490 degrees, where 630 (0° on the figure below) is the position in which the laser is rotated on the right, looking Poomba from behind.

text
Servo rotation positions

Scanner Driver Protocol

As we previously mentioned the scanner is a virtual device. Its aim is to drive the servo to rotate the laser structure, send the measure command to the laser to get measurements and obtain the digital compass values. Of course the scanner driver returns to the controller every received message from the laser and the magnetometer in order to plot distance data. Technically this device listens for commands whose receiver id is set to P than send to the servo a message to rotate to 0° in order to begin the scanning procedure. After that the driver sends a message to the laser to take a distance measure. The scanning procedure will be initiated by setting the message payload to S and will be interrupted if set to F. Every time a distance measure is returned (this will be intercepted using message dispatcher and interrupts), the scanner driver polls the magnetometer for the angle value and sends a command to the servo to move to the next step (approximately 2 degrees/step) until a range of 180 degrees has been completed. Of course every message returned from the laser is then submitted to the controller that needs data to be plotted. The scanner driver can also stop the scanning procedure if intercepts one or more messages to other peripherals. We think that if we move the robot, the data captured by the scanner are subject to errors and position translation so we have decided to stop the data capturing if the robot is moved out of it’s start position when the scanning procedure has been called. The scanner core cycle implementation (move servo and take laser measure) is done in the main cycle of the firmware in order to prevent blocking procedures in interrupt handling functions. To do this we use global status variables, like the scanning variable.

Magnetometer driver protocol

The magnetometer cannot be controlled from the controller, it's a system reserved peripheral used in order to get compass value during the scanner procedure. We use Direct Memory Access so we have a buffer with the last avaiable value.

...
/* Configure DMA1 channel 1 peripheral address register. */
DMA1_Channel1->CPAR = (uint32_t) &(TIM4->CCR2);
/* Configure DMA1 channel 1 memory address register. */
DMA1_Channel1->CMAR = (uint32_t) &ccr2;
/* Enable RX DMA requests. */
TIM4->DIER |= TIM_DIER_CC1DE;
...

Firmware Source Organization

As just said before the internal architecture of the firmware is based on message passing and interrupt handling. Hardware interrupts are used to receive bytes sent from peripherals like laser or bluetooth. During the handling of the hardware interrupt we build up a buffer to capture the entire message, this is possible due to known serial character terminators. Software interrupts, on the other hand, are used to notify the message dispatcher that something is ready to be done. Of course after the serial buffer is full a software interrupt will be raised to handle the message that has been received.

So let’s dig-in a little deeper into the firmware. We have different modules for all physically connected devices and virtual devices. Every module has an init procedure to do the correct initialization for the registers used to communicate with the device. Also we have developed a little protocol utility helper to parse and compose messages.

The core part of the firmware is based on events. Practically it reacts on external events, like messages sent from the controller or internal events, like a device that signals a read value or the end of the requested procedure. The internal state of the robot is given by the aggregation of all the states of the connected devices (with devices we intend real peripherals or virtual devices).

The whole firmware is divided in three macro-areas:

  1. The message dispatcher
  2. Peripherals driver
  3. Protocol composer and parser

'The message dispatcher' is the core component that handles all the messages to and from connected devices. It verifies that message sender and receiver are correct. At the time of writing this document no error handling has been done, we simply ignores malformed messages and/or non existing receivers.

'Peripherals driver' realises a sort of hardware abstraction layer that converts high level commands to low level instructions or PWM signals or whatever the device requires and abstracts the communication throught primitive functions and interrupt handling.

'The protocol composer and parser' are abstractions of the message protocol used to create the message from its components (sender, receiver, timestamp, payload) and it's used to parse the received message to extract the information needed at every level of the firmware abstraction (e.g. receiver and payload)

The firmware is composed by several files and, for logic organization, different folders and subfolders. The next table summarizes files and folders involved in the firmware structure:

Source file Description
main.c do the main initializations like the global clock, GPIOs, software interrupts and the delay timer and setup a while cycle that keeps everything alive
message_dispatcher.{c, h} handles software and hardware interrupts, contains the handle_message functions to extract components from the received message string and the global send_message function that realizes the message passing part of the firmware
utils.{c, h} contains global utility functions like delay, itoa (int to char) and our own string copy
global.h contains global constants for the servo and the serial protocol
Protocols folder
bluetooth/bt_protocol.{c, h} exposes the functions for parsing and composing the serial protocol message
motors/mt_protocol.{c, h} exposes the conversion function from high level command to the low level command in order to drive the motor board
Drivers folder
bluetooth/bt_driver.{c, h} has the init and the send methods in order to initialized the USART1 to receive and send messages. In this file we also save the message buffer for input and output
bluetooth/dma/dma_handler.{c, h} handles the DMA transfer of a message queue over the USART1
laser/ls_driver.{c, h} as all drivers in this file we implemented the init and send functions. Also contains a buffer to store the laser entire response, when we waits for the distance measure
leds/led_driver.{c, h} macro for turning on, off and toggle leds

Note: leds are not exposed as controllable devices via serial protocol

magnetometer/mg_driver.{c, h} initialize Timer 4 and its DMA configuration and so maintain a buffer of the last magnetometer value
motors/mt_driver.{c, h} motors initialization and send functions to control motor behaviour
rtc/rtc_driver.{c, h} exposes initialization and time related functions
scanner/sc_driver.{c, h} implements the logic to do a full 180 degrees scanning
servo/sv_driver.{c, h} initialization and rotation commands for the PWM servo

Experimental Tests

Since videos cannot be uploaded to the wiki we link them:

Results and Problems

Results

text
Scanning result on controller

Problems

  1. Serial Communication could be tricky if BaudRate is not configured properly
  2. Major pains were caused by the development toolbox, in particular during the deployments phase of the firmware. In a totally non deterministic way the new firmware won’t be executed but the debugger shows the new source with breakpoints. This caused a lot of trouble when testing correct register configuration on the STM32
  3. Along with the IDE we have encountered problems using standard C functions that has been declared as supported on the ST forums, like the strcpy and the strcat. In unpredicatable way this functions causes segmentation fault (or something similar) across different firmware redeploy. Maybe this unpredicatable aspects are caused by the arm gcc compiler, maybe not, so we decided to implement our own strcpy (that we call scpy) and the other standard library functions we used.
  4. The LSE oscillator doesn't enter in ready state so we opted to use the LSI oscillator as RTC clock source accepting that the counter will not be incremented when the STM32 is inactive

User Manual

Hardware Wiring

DC input 3.3V:

3V3 and GND

laser:

USART 3, pin PA2 and PA3

magnetometer:

TIM4 channel 1 PB6

bluetooth:

USART 1, pin PA9 and PA10

motors:

USART 2, pin PB10 and PB11

servo:

TIM2_CH2, pin PA1
text
Hardware wiring

Startup Procedure

In order to make the final user happy we have simplified the startup procedure. The STM32 is shipped with the firmware on-board. To get started:

  1. Turn on the global switch on the Poomba rooftop
  2. Check the battery state using the indicator and the beeper
  3. Watch at the STM32 LED number 4. When this led is on the firmware is doing some initialization. When the led turns off the robot is in ready state
  4. Pair your bluetooth device with the device called RN42-9273
  5. Send commands or use our custom application
  6. Have fun

In order to get visual feedback from the robot every received message is interpreted and than echoed to the controller and on the STM32 board the LED 2 will flash for little time to signal that a message has been received on the main control serial (aka USART1 or the bluetooth serial).

Usage example

In this section we have decided to put a simple script of commands to be sent to the Poomba brain in order to do some movements and a scanning procedure. 1.  C$M$1340960014095$F# //motor forward
2.  5 seconds delay
3.  C$M$1340960014095$S# //motor stop
4.  C$M$1340960014095$R# //motor right
5.  1 seconds delay
6.  C$M$1340960014095$S# //motor stop
7.  C$M$1340960014095$V:80# //set motor Speed (default value = 20)
8.  C$M$1340960014095$F# //motor forward
9.  5 seconds delay
10. C$M$1340960014095$S# //motor stop
11. C$P$1340960014095$S# //scanning procedure start
12. wait for scanning procedure to complete or send C$P$1340960014095$F# to stop

Attachments

Firmware source code: http://cl.ly/HpNi

Controller source code: http://cl.ly/HpUE

References

  1. Parallax Range Finder, http://www.parallax.com/Store/Sensors/AllSensors/tabid/760/ProductID/774/List/0/Default.aspx?SortField=ProductName,ProductName
  2. Optical Triangulation, http://www.optical-metrology-centre.com/Downloads/Tech_Briefs/TechBrief_SinglePtOpticalTriangulation.pdf
  3. Motors, http://www.robot-electronics.co.uk/htm/md25tech.htm
  4. Magnetometer, http://www.robot-electronics.co.uk/htm/cmps10doc.htm
  5. Make:Magazine “Circuit Skills: PWM - Pulse Width Modulation”, http://blog.makezine.com/2011/06/01/circuit-skills-pwm-pulse-width-modulation-sponsored-by-jameco-electronics/
  6. Tilt Compensated Compass Explanation https://www.loveelectronics.co.uk/Tutorials/13/tilt-compensated-compass-arduino-tutorial
Personal tools