jeudi 28 mars 2013

Intro


Few months ago, I purchased an Arduino Uno module. For those who do not know, it is a prototyping platform based on a microcontroller, programmable via an open source language
For more information: http://www.arduino.cc/fr/

As I have some knowledge of electronics and programming (low skills), I started slowly with very small projects and simple codes, for isntance, make a LED flashing, then several LEDs, etc…
There are many tutorials on the internet explaining the different sides and possibilities of the Arduino.

After practicing a bit, I decided to start a new project, not very original but fun: Adding an Arduino to a radio controlled car, to be able in the first time, to control the car throught the serial port, then in the future, evolute to be able to control the car throught the WIFI or 3G network.

You will find, in this blog, the different steps of this project: material, source codes, problems, etc. ...

Your feedback, comments, and advises are of course welcome!

mercredi 27 mars 2013

Choosing a car:


I chose a simple electric car model. As I have not a huge budget, and as I wanted a real model brand, I choseo a 1/10th car brand Kyosho: The Kyosho Sandmaster.

I bought this one without the radio remote and the receiver. The receiver will be replaced, in my case, by the Arduino
Expect to pay about 90 euros for the car.
The advantage of taking a true model-making brand, and not a "noname", is that you can easily find any piece, in case of damage.

Here are 2 pictures of the car:







mardi 12 février 2013

HMC5883L Compass + Arduino + Processing


You will find below the Arduino and ProcessingCode. I used the arduino example code found into the library, and adaped it a bit.
The Processing code is from a code that I found on internet and adapted and changed some graphic details.
You will find also a link to download the library that I use.

Since the video, I have solved the angle issue, now performing 90 degrees angle with the compass will ouput correctly a +/- 90 degrees on the serial port.

HMC5883L Library:
http://dl.free.fr/q9O0J0cXe


Arduino code:


// Reference the I2C Library
#include <Wire.h>
// Reference the HMC5883L Compass Library
#include <HMC5883L.h>

// Store our compass as a variable.
HMC5883L compass;
// Record any errors that may occur in the compass.
int error = 0;

//rounding angle
int RoundDegreeInt;

int PreviousDegree = 0;

// Out setup routine, here we will configure the microcontroller and compass.
void setup()
{
  // Initialize the serial port.
  Serial.begin(9600);

  Wire.begin(); // Start the I2C interface.

  compass = HMC5883L(); // Construct a new HMC5883 compass.
 
  error = compass.SetScale(1.3); // Set the scale of the compass.
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));

  error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));
}

// Our main program loop.
void loop()
{
  // Retrive the raw values from the compass (not scaled).
  MagnetometerRaw raw = compass.ReadRawAxis();
  // Retrived the scaled values from the compass (scaled to the configured scale).
  MagnetometerScaled scaled = compass.ReadScaledAxis();

  // Values are accessed like so:
  int MilliGauss_OnThe_XAxis = scaled.XAxis;// (or YAxis, or ZAxis)

  // Calculate heading when the magnetometer is level, then correct for signs of axis.
  float heading = atan2(scaled.YAxis, scaled.XAxis);

  // Once you have your heading, you must then add your 'Declination Angle', which is the 'Error' of the magnetic field in your location.
  // Find yours here: http://www.magnetic-declination.com/
  // Mine is: 2� 37' W, which is 2.617 Degrees, or (which we need) 0.0456752665 radians, I will use 0.0457
  // If you cannot find your Declination, comment out these two lines, your compass will be slightly off.
  float declinationAngle = 0.009 ;
  heading += declinationAngle;

  // Correct for when signs are reversed.
  if(heading < 0)
    heading += 2*PI;
 
  // Check for wrap due to addition of declination.
  if(heading > 2*PI)
    heading -= 2*PI;
 
  // Convert radians to degrees for readability.
  float headingDegrees = heading * 180/M_PI;

  //correcting the angle issue
  if (headingDegrees >= 1 && headingDegrees < 240)
  {
    headingDegrees = map(headingDegrees,0,239,0,179);
  }
  else if (headingDegrees >= 240)
  {
    headingDegrees =  map(headingDegrees,240,360,180,360);
  }

  //rounding the angle
  RoundDegreeInt =round(headingDegrees);

  //smoothing value
  if( RoundDegreeInt < (PreviousDegree + 3) && RoundDegreeInt > (PreviousDegree - 3) ) {
    RoundDegreeInt = PreviousDegree;
  }

  Output(RoundDegreeInt);

  PreviousDegree = RoundDegreeInt;

  // Normally we would delay the application by 66ms to allow the loop
  // to run at 15Hz (default bandwidth for the HMC5883L).
  // However since we have a long serial out (104ms at 9600) we will let
  // it run at its natural speed.
  // delay(66);
}

// Output the data down the serial port.
void Output(int RoundDegreeInt)
{
   //Serial.println();
   Serial.println(RoundDegreeInt);
 
   delay(150);
}

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Processing Code:

import processing.serial.*;

Serial myPort;
PFont b;

int lf = 10;    // Linefeed in ASCII
String myString = null;
float angle;

void setup(){
  size(600,400);
  b = loadFont("Arial-BoldMT-48.vlw");
  myPort = new Serial(this, "COM3", 9600);
}

void draw(){

background(255);

while (myPort.available() > 0) {
    myString = myPort.readStringUntil(lf);
    if (myString != null) {
  //print(myString);  // Prints String
    angle=float(myString);  // Converts and prints float
    println(angle);
    }
  }
  translate(160, 50);

  // draw the compass background
  ellipseMode(CENTER);
  fill(50);
  stroke(10);
  strokeWeight(2);
  ellipse(150,150,300,300);

  // draw the lines and dots
  translate(150,150);  // translate the lines and dots to the middle of the compass
  float CompassX = -angle;
  rotate(radians(CompassX));
  noStroke();
  fill(51, 255, 51);

  int radius = 120;

  for( int degC = 5; degC < 360; degC += 10) //Compass dots
  {
    float angleC = radians(degC);
    float xC = 0 + (cos(angleC)* radius);
    float yC = 0 + (sin(angleC)* radius);
    ellipse(xC,yC, 3, 3);
  }

  for( int degL = 10; degL < 370; degL += 10) //Compass lines
  {
    float angleL = radians(degL);
    float x = 0 + (cos(angleL)* 145);
    float y = 0 + (sin(angleL)* 145);
 
    if( degL==90 || degL==180 || degL==270 || degL==360) {
     stroke(51, 255, 51);
     strokeWeight(4);
    }
    else {
      stroke(234,144,7);
      strokeWeight(2);
    }
    line(0,0, x,y);
  }

  fill(102, 102, 102);
  noStroke();
  ellipseMode(CENTER);
  ellipse(0,0, 228,228); //draw a filled circle to hide the lines in the middle

  b = loadFont("Arial-BoldMT-48.vlw");
  textAlign(CENTER);

  // Draw the letters
  fill(250);
  textFont(b, 32);
  text("N", 1, -90);
  rotate(radians(90));
  text("E", 0, -90);
  rotate(radians(90));
  text("S", 0, -90);
  rotate(radians(90));
  text("W", 0, -90);
  rotate(radians(90));
 
  textFont(b,40);
  textAlign(CENTER);
  //text((angle), 20, 20);
  println(angle);

  //draw the needle

  rotate(radians(-CompassX)); //make it stationary
  stroke(234,144,7);
  strokeWeight(3);

  triangle(-10, 0, 10, 0, 0, -85);
  fill(234,144,7);
  triangle(-10, 0, 10, 0, 0, 60);

}











lundi 11 février 2013

Inside


Inside, we can find:

  • The ESC (Electronic Speed Control):

This is a KA-18 ESC Kyosho.
This one provides power (5V) to the radio receiver (which is missing in my case), and also control and vary the speed of the main motor according to the commands received and transmitted by the radio receiver.

This one consists of:
- The plug (which will connect to the battery, a 7.2V battery 2200 mha in my case)
- The output to power the main motor
- A pin with 3 wires, black, white, and red. Black and red normally allow powering the radio receiver (5V). The white wire is needed to send the data received by the receiver, which will be transmitted to the ESC.
- A switch, to turn on and off the car.

The steering servo (front wheels).
To control a servo, this one has 3 wires: The red and black wires will power the servo (5v). The white wire is the one used to control the servo, indicating the angle of the position.
The steering servo is directly connected to the receiver (which is itself powered by the ESC).


dimanche 10 février 2013

First step: Controling the steering servo

It is very simple to control a servo motor using an Arduino.
The servo position can vary from an angle of 0 to 180 degrees. It is interesting for me to know the maximum angle to turn on the right and on the left.

For this, I will use:
- An arduino
- A potentiometer
- Some simple wires
- A USB cable, to power the Arduino, and to get the value sends by the Arduino to the computer (with the serial port).

I will make an assembly, to change the angle of the servo, depending on the value of the potentiometer.

Here is the page that I used and which perfectly matched my case:

http://arduino.cc/en/Tutorial/Knob

And here's a picture of the assembly:


We will use:
- An analog input of the Arduino (to measure the value of the potentiometer)
- An output of the Arduino (to communicate to the servo the value of the angle to reach)
- The ground and the 5V output, to apply a voltage across the potentiometer, and also to power the servo.

Good to know:
Values which are ​​read from the analog input of the Arduino are always between 0 and 1023 (10 bits resolution).
Therefore, it is important, when making the code, to adapt this value to match the value expected by a servo, so between 0 and 179 (180 degrees).

To know this value, this one is then sent via the serial port (here USB) to the computer.

Controlling the steering servo with a Potentiometer: Code and video


To make the control of the servo motor easier, there is a special library made for: servo.h (http://www.arduino.cc/en/Reference/Servo)
I will use it here.

Here is the code:

#include <Servo.h>
Servo frontservo; // declare servo name as "frontservo"
int potpin = A0; // analog pin used to connect the potentiometer
int val; // variable to read the value from the analog pin
void setup()
{
frontservo.attach(9); // attach the servo on pin 9 to the servo object
Serial.begin(9600); // set the serial port rate to 9600 bauds
}
void loop()
{
val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023)
val = map(val, 0, 1023, 0, 179); // scale it to use it with the servo (value between 0 and 179 degres)
frontservo.write(val); // sets the servo position according to the scaled value
Serial.println(val); // send the value via the serial port
delay(15); // waits for the servo to get there
}

On the computer side, I will use the serial monitor of the Arduino programm (Ctrl Shift M).

The video:



So you can see thanks to this , that the wheels are centered when the value is around 100 ( between 90 and 100). The maximum movement on the is right about 130, on the left about 60.