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.
samedi 9 février 2013
Controlling the ESC: Arduino and potentiometer
Regarding
the main motor control, I have to control the ESC. This one can be
controlled as a servo, this the servo.h library.
Note
that the ESC needs to be initialized. The boot sequence depends of
the ESC brand and model. In my case, I need to send the value 100
during 1 second.
Also,
as the ESC is already powered by the battery, I wont use the 5v pin
of the Arduino.
Therefore
we can use the same code.
Assembly:
Video:
vendredi 8 février 2013
Controlling the steering servo with a mouse
Instead
of using a potentiometer to control a servo, i will use in this case
a mouse.
In
order to send a value to the Arduino, depending of the mouse
movements, I have to make a short program which will run on the
computer side.
To
create this program, I will use a development platform called
Processing. It is Open Source, easy to use, and specially made for
interaction and animation. Actually, the programm Arduino is based on
Processing.
For more
info: http://processing.org/
So,
I will have on code, running on Processing, sending the value to the
Arduino, depending of the mouse position, and another code, running
on the Arduino, to control the servo depending of the value received
through the serial port.
I
wil use:
-
My computer (and the mouse)
-
The Arduino
-
The USB cable and some simple wires
-
The steering servo of the Kyosho car
As
we do not use any potentiometer anymore, the servo will be directly
connecter to the Arduino. +5v pin to the red wire, GND to the black
wire (here brown), and the pin to the white wire (here orange).
jeudi 7 février 2013
Controlling the steering servo with a mouse: the Processing code
As
the Arduino program is based on Processing, the syntaxe used to write
the code will be very similar.
To
write the code, I used the examples below, which are matching
perfertly what I intented to do.
and
After
some changes, here the code that I will use:
import
processing.serial.*;
int
xpos=90; // set x servo's value to mid point (0-180);
Serial
myport; // The serial port we will be using
void
setup()
{
size(720, 360); //
size of the main windows
myport
= new Serial(this, "COM3", 9600); // declare the serial
port on COM3 with a speed of 9600 bds)
}
void
draw()
//Note
that MouseX is referring to the X axis position of the mouse, from 0
on the left to 720 on the right
{
fill(175);
rect(0,0,720,360);
fill(255,0,0);
// set the color RED for the next shapes
rect(360, 175,
mouseX-360, 50); // draw a rectangle from the middle position to the
x axis of the mouse position
update(mouseX);
}
void
update(int x)
{
//Calculate servo
postion from mouseX
xpos=
x/4; // the middle will be 360/4=90
myport.write(xpos+"x");
//sends the position throught the serial port followed by the letter
x, by that way we can if we want, control more servos with different
letters
println(xpos);
// display the value of the position into the processing monitor
delay(25);
}
mercredi 6 février 2013
Controlling the steering servo with a mouse: the Arduino code
On
the Arduino side, I also adapted the sketch to fits with my purpose:
#include
<Servo.h>
Servo
xservo; // xservo is the direction servo
int
xpos= 0;
void
setup(){
xservo.attach(9);
//attach the servo to pin 9
Serial.begin(9600);
// 9600 is the rate of communication
}
void
loop() {
static
int v = 0; // value to be sent to the servo (0-180)
if
( Serial.available()) {
char
ch = Serial.read(); // read in a character from the serial port and
assign to ch
switch(ch) { //
switch based on the value of ch, it will be only x in this case
case
'0'...'9': // if it's numeric
v
= v * 10 + ch - '0';
/*
so if the chars sent
are 45x (turn x servo to 45 degs)..
v is the value we
want to send to the servo and it is currently 0
The first char (ch)
is 4 so
0*10 = 0 + 4 - 0 =
4;
Second char is 4;
4*10 = 40 + 5 = 45 -
0 = 45;
Third char is not a
number(0-9) so we drop through...
*/
break;
case
'x': // if it's x
/*
....and land here
where we send the
value of v which is now 45 to the x servo
and
then reset v to 0
*/
v
= constrain(v, 60, 130); // constrain the value to be between 60 and
130
xservo.write(v); //
send the value to the servo
delay(25);
v
= 0; // reset this value to 0
break;
}
}
}
mardi 5 février 2013
lundi 4 février 2013
Pan tilt control with an Xbox controller: Intro
As
we have seen, we can use Processing to send different values to the
Arduino, depending in the previous case of the mouse, but we can also
use many kind of devices.
As
I have a Xbox 360, I decided to use the controller through Processing
and the Arduino, to control a pan tilt.
The
Pan tilt:
I
have chose a very simple and cheap pan tilt that I have purchase on
SparkFun.com
This
one is made of 2 pieces of metal assembled with screws, and
controlled with 2 servos.
A
picture:
As
demonstrated earlier, it is very easy to drive a servo with the
Arduino, so driving 2 servos should be easy too.
dimanche 3 février 2013
Pan tilt control with an Xbox controller: the Processing code
To
be able to use the buttons, joysticks and triggers of the xbox
controler into processing easily, we need to use a librairy. There is
a special librairy dedicated to jospads and controllers, it is called
ProControll.
More
info about Procontroll library:
http://creativecomputing.cc/p5libs/procontroll/
With
a controller like the Xbox 360 controller, acquiring a button change
is quite easy. However, acquiring and using the value, for one or
several axis, of the joystick, is a bit more difficult.
Actually,
for the josticks, the value returned by the controller is a large
floating decimal value.
This
one needs to be converted into a value that we can directly use and
send to the Arduino.
Also,
as the joytick is not a perfect circle, and as it can be very
sensitive, a function to control the tolerance needs to be used.
I
have looked over internet, and I found this video on youtube:
The
person described how to control a motor with a Xbox controller. There
is below the video the description and also the code that the person
used. I thank a lot Mr Mspinksosu because his video and code helped
me a lot.
I
adapted the code to fit in my project. The main changes are that I
simplified the code a lot, I adapted the Processing side to get the
value of the X and Y axis of the right joystick, and on the Arduino
side, I removed the interuptions and I changed a bit the code in
order to drive the servo with the servo.h library.
Inscription à :
Articles (Atom)