sábado, 11 de enero de 2014

Arduino - How to improve the realiability of sensors readings

Some days ago, as part of an obstacle avoiding robot project, I was trying to identify nearby objects using an ultrasonic distance sensor in order to turn right or left to avoid them.

In theory, this was a pretty straight forward task... but when I coded the described behavior, the robot started turning when it shouldnt. I looked at the code and everything looked fine, the only possible reason was that the robot thought that there was an object when the was no object.

I connected the arduino to the computer and started printing the distance sensor readings to the Arduino's IDE serial monitor. I was using 20cms as the distance where the robot should stop and turn in order avoid an object. So, I placed an object at 40cms and started watching the readings through the serial monitor, and I noticed that I was getting weird values. For example, I was getting:

39 40 41 3 39 4 42 42 3000 2800 40 41 38 2 40

I was aware that sensors are not accurate things because they are affected by multiple variables (quality of its construction, electrical noise, enviromental changes, etc), I was expecting values near the real value, for example if the real value was 40cm, I was expecting values between 35 and 45 maybe... but I never expected outliers that far from the real value.

Probably the better thing to do is to buy a sensor with the quality needed for the project, and also do everything you can to reduce the electrical noise, however no matter what you do, you wont get exact values on every reading. So, what can you do to improve the realiability of your sensors so they dont mess your program's logic?

I found that getting multiple samples and processing them sustantially improves the accuracy of the sensors readings.

So, every time that we want to measure the distance to an object, we are going to get multiple sample and get only one value from them.

Your first thought might be "lets average the numbers and we'll probably get near to the real value". Well, this is a BAD IDEA.

Lets say that for each measure we use 7 sensor readings and we get:

42 40 3000 41 3 38 43

The average is: 42 + 40 + 3000 + 41 + 3 + 38 + 43 = 3207 / 7 = 458cm (aprox)

A better way of processing the 7 samples is to use the median method. This is a very simple method, where you first sort all the values and then you use the value in the middle position, so half of the values are lower and half of the values are higher.

Lets apply the median method to this set of 7 samples:

First we sort it, getting : 3 38 30 41 42 43 3000

The result of the median method is 41, which is really close to the real value (which was 40).

I applied this method to the obstacle avoiding robot and I had really good results. Its important to notice that even with data filtering, you wont get the exact value, so you need to use "safe thresholds" in your program's logic. For example Im using 20 cms as the value where the robot should stop and turn in order to avoid an object. If there is an object at 19cms and the sensor returns a distance of 21cm, there is no problem, on the next iteration of the loop the robot will be closer to the object and I'll get a distance lower 20cms, so it will stop and turn before hitting the object.

There is an existing library for Arduino that allows us to easily get the median value of a set of samples. You can get it from here.

This is an example of how to use it:

#include 
#include 

//Define the pins for the ultrasonic sensor's echo and trigger pins 
#define DISTANCE_ECHO 4
#define DISTANCE_TRIGGER 7
#define MAX_ULTRASONIC_DISTANCE 200

NewPing sonar(DISTANCE_TRIGGER, DISTANCE_ECHO, MAX_ULTRASONIC_DISTANCE);

void setup()
{
    //Initialize serial communication to send the distance value  to the serial monitor
    Serial.begin(9600);
}

void loop()
{
  int distance_cm;
  distance_cm = getDistanceFromUltrasonicSensor();
  
  Serial.print(distance_cm);
  Serial.print("cm");
  Serial.println();
}

int getDistanceFromUltrasonicSensor(){
  //Create an instance of the RunningMedian class with the number of samples to use
  RunningMedian samples = RunningMedian(7);
  
  //Get the 7 samples
  for(int i= 0; i<5; i++){
      delay(50);
      int pingVal = sonar.ping();
      
      int distance = pingVal / US_ROUNDTRIP_CM;
      if(distance == 0){
        distance = 3000;
      }
     samples.add(distance);
   }   
   //Return the median value
   return samples.getMedian();  
}


Here I applied the median method for an ultrasonic distance sensor, but this applies to any other sensor, for example, temperature sensors, compass sensor, etc.

miércoles, 8 de enero de 2014

Arduino - Controlling DC motors with L298N motor controller

If you want to control a motor with the Arduino board, you'll need to power the motor with an external power source because the Arduino only provides up to 40 mA on its outputs, which is not enough to move DC motors. You will also need some circuit that allows you to move the motor forward and backwards (H-Bridge).

The L298N motor controller solves these 2 things for us, it allows us to power the motor from an external power source, while also allowing us to control the motor speed and directions with low current signals (which the arduino can handle).


 

Off topic: I bought mine from DealExtreme, which if you dont know I definitely recommend visiting. Its an online store that sells an enormous variety of things, at low prices and with free international shipping.


Lets see the input and outputs that this controller has:


Battery inputs
These are 2 of the blue connectors that you can see in the image above. This requires a battery which will power the 2 motors. The battery’s voltage should be compatible with the motors that you are going to use.  Check the specs of your controller to see the max allowed voltage .
Motor A outputs
These are 2 of the blue connectors that you can see in the image above. This will power the motor A
Motor B outputs
These are 2 of the blue connectors that you can see in the image above. This will power the motor B.
EN A
This signal should be connected to an Arduino’s PWM output pin. It will determine the speed of the motor A, a value of 0 means stopped and a value of 255 is max speed.
EN B
This signal should be connected to an Arduino’s PWM output pin. It will determine the speed of the motor B, a value of 0 means stopped and a value of 255 is max speed.
IN1 and IN2
These are 2 digital signals that will determine Motor’s A behavior (going forward, going backwards)
IN3 and IN4
These are 2 digital signals that will determine Motor’s B behavior (going forward, going backwards)


The following values will allow you to set the motors directions from your arduino.


IN1
IN2

IN3
IN4
Motor A Forward
HIGH
LOW
Motor B Forward
HIGH
LOW
Motor A Backwards
LOW
HIGH
Motor B Backwards
LOW
HIGH


In the next example I'll show how to control 2 independant DC motor.

//Define the speed for the motors, Im just going to use 200 (almost top speed)
#define SPEED 200

//Define the signal pins for motor A
#define ENA 3
#define MAIN1  8
#define MAIN2  9

//Define the signal pins for motor B
#define ENB 5
#define MBIN1 10
#define MBIN2 11

void setup()
{
    pinMode(MAIN1, OUTPUT);  
    pinMode(MAIN2, OUTPUT);
    pinMode(MBIN1, OUTPUT);  
    pinMode(MBIN2, OUTPUT);
}

void loop(){
  forwardMotorA(SPEED);
  delay(2000); //let it running for 2 seconds
  backwardsMotorA(SPEED);
  delay(2000); 
  stopMotorA();

 
  forwardMotorB(SPEED);
  delay(2000); //let it running for 2 seconds
  backwardsMotorB(SPEED);
  delay(2000); 
  stopMotorB();
} 

void forwardMotorA(int speedVal){
  digitalWrite(MAIN1,HIGH);  
  digitalWrite(MAIN2,LOW); 

  analogWrite(ENA, speedVal);
}

void backwardsMotorA(int speedVal){
  digitalWrite(MAIN1,HIGH);  
  digitalWrite(MAIN2,LOW); 

  analogWrite(ENA, speedVal);
}

void stopMotorA(){
  analogWrite(ENA, 0);
}

void forwardMotorB(int speedVal){
  digitalWrite(MBIN1,HIGH);  
  digitalWrite(MBIN2,LOW); 

  analogWrite(ENB, speedVal);
}

void backwardsMotorB(int speedVal){
  digitalWrite(MBIN1,HIGH);  
  digitalWrite(MBIN2,LOW); 

  analogWrite(ENB, speedVal);
}

void stopMotorB(){
  analogWrite(ENB, 0);
}

martes, 7 de enero de 2014

Raspberry PI and Arduino - Great combination!

Raspberry PI

For those of you who dont know the Raspberry PI yet, it is a VERY cheap and VERY tiny computer. It costs around $35 - $40 and its of the size of a credit card. Of course its not a core i7 with 16GB of RAM, but has a quite decent ARM 700MHz CPU with 512MB of RAM, which allows you to do a lot of things. You can see the Raspberry PI's offical site to see all the crazy ideas that people come up with the Raspberry PI.



The Raspberry PI has some interesting benefits:
  • For the cost its pretty powerful (of course its useful for some applications, its not for everything, you wont be able to play GTA V on it, ha)
  • It runs linux
  • It works without a fan (yeah! no noise!)
  • Low power consumption (700-1000mA for Model B, which is the model with an ethernet port)
  • Its really small
The Raspberry PI has some limitations though and during its usage I found some issues. The one that struggled me most, is that the USB ports cannot power most of the devices, so you need a powered hub for them, and the Raspberry PI is not compatible with every USB hub... so its a bit complicated (you can get a list of compatible devices from here). For example some webcams, wifi dongles and external hdd need a powered USB hub.

Although the Raspberry PI its quite powerful, it has a major drawback for robotics or any electronic projects... it has no built-in analog inputs/outputs.

Arduino

Arduino is very popular electronics prototyping platform that makes everything easier for those of us that are amateurs on the electronics field. There are multiple Arduino boards, but I'll talk about the "Arduino Leonardo" which is the one that I bought. The Arduino Leonardo is a cheap board (you can get it for around $20) that includes a bunch of digital and analogs pins for input/output and a serial port which can be used to communicate the Arduino with a computer (this is also used to load the programs)



Arduino has its own IDE for coding and you code in an "arduino programming language" which is pretty similar to to C. One of the greatest things, is that it has an awesome community, so its really easy to find solutions to your problems and there are a lot of libraries to interact with sensors  and actuactors (ultrasonic for distance, infrared, servos, etc).

The arduino is awesome but it also has its limitations... it has a 16Mhz microprocessor and 32KB of memory. So, forget about doing heavy processing in the arduino.


Raspberry PI + Arduino = SUCCESS!

As you may have noticed, the Raspberry PI and the Arduino complement each other pretty well. The Raspberry PI is pretty powerful but it lacks of analog inputs/outputs which the arduino has. So, I think that the combination of both is a great success.

For my projects Im planning to communicate both boards through the serial interface (USB). The Arduino will just be an interface between the Raspberry PI and the hardware, exposing the sensors readings and getting commands for the actuator through a simple custom reusable serial protocol that Im going to code. And in the Raspberry PI I'll create a program for each project in the language that I want (for example python) and I can use all the power of the Raspberry PI to do the computation.