Hola,
Os adjunto una entrada en que empiezo mis pinitos de la integración de Arduino con el software Processing y me gustaría que ayudárais en el tema de pulir la recepción de muestras del acelerómetro (todo esto en arduino), así como la aplicación de un filtro Kalman que he visto que se suele utilizar, pero no se como.
Código fuente de arduino
/*
Proyecto : Horizonte Artificial
Autor....: Ricard Forner (RFKsolutions)
Version..: 0.0.1
Fecha....: 10/07/2011
Código fuente: Arduino
Circuito
Pin 8: Lectura Pulsador Resistencia: 8.2 k
Pin 9: LED RGB (Azul) Resistencia: 100 ohm
Pin 10: LED RGB (Verde) Resistencia: 100 ohm
Pin 11: LED RGB (Rojo) Resistencia: 180 ohm
*/
class Accelerometer {
int p[3]; // pins ejes XYZ analog
int a[3]; // aceleracion (zero-based)
int b[3]; // aceleracion bias/calibracion
int g, t, r; // copia cache de calculos
int scale; // factor escala entre ADC y gravedad
int ledPin; // pin del led de calibracion
public:
Accelerometer(int pinX, int pinY, int pinZ, int pScale, int pLedPin) {
pinMode((p[0] = pinX), INPUT);
pinMode((p[1] = pinY), INPUT);
pinMode((p[2] = pinZ), INPUT);
for (int i = 0; i < 3; i++) {
b[i] = 512;
}
g = t = r = 0;
scale = pScale;
pinMode((ledPin = pLedPin), OUTPUT);
}
void update() {
for (int i = 0; i < 3; i++) {
a[i] = analogRead(p[i]) - b[i];
}
g = t = r = 0;
}
void calibrate() {
digitalWrite(ledPin, HIGH);
for (int i = 0; i < 3; i++) {
b[i] = analogRead(p[i]);
}
b[2] -= scale;
update();
digitalWrite(ledPin, LOW);
}
int milligee() {
if (g != 0) return g;
long squared = 0.0;
for (int i = 0; i < 3; i++) {
squared += (long)a[i] * (long)a[i];
}
g = squared * 1000 / (scale*scale);
return g;
}
int accel(int axis) {
if (axis < 0 || axis > 3) return 0;
return a[axis];
}
int roll() {
if (r != 0) return r;
r = (int)(atan2(a[0], a[2]) * 180. / M_PI);
return r;
}
int pitch() {
if (t != 0) return t;
t = (int)(acos(a[1] / (float)scale) * 180. / M_PI);
return t;
}
void toConsole() {
Serial.print("xV="); Serial.print(b[0]);
Serial.print("\tyV="); Serial.print(b[1]);
Serial.print("\tzV="); Serial.print(b[2]);
Serial.print("\tx="); Serial.print(a[0]);
Serial.print("\ty="); Serial.print(a[1]);
Serial.print("\tz="); Serial.print(a[2]);
Serial.print("\tmg="); Serial.print(milligee());
Serial.print("\tpitch="); Serial.print(pitch());
Serial.print("\troll="); Serial.print(roll());
Serial.println();
}
void toProcessing() {
Serial.print(0);
// XYX mV
Serial.print(";"); Serial.print(b[0]);
Serial.print(";"); Serial.print(b[1]);
Serial.print(";"); Serial.print(b[2]);
// XYX valores
Serial.print(";"); Serial.print(a[0]);
Serial.print(";"); Serial.print(a[1]);
Serial.print(";"); Serial.print(a[2]);
// mGe (1 gee = 9.8ms2)
Serial.print(";"); Serial.print(milligee());
// pitch
Serial.print(";"); Serial.print(pitch());
// roll
Serial.print(";"); Serial.print(roll());
Serial.println();
}
void loop() {
update();
}
};
const int sensorEjeX = 0;
const int sensorEjeY = 1;
const int sensorEjeZ = 2;
const int buttonPin = 8;
const int ledPinRed =11;
const int ledPinGreen =10;
const int ledPinBlue = 9;
int bucle = 0;
Accelerometer accel = Accelerometer(sensorEjeX, sensorEjeY, sensorEjeZ, 64, ledPinRed);
void establishContact() {
Serial.begin(38400);
Serial.println("Arduino conectado.");
}
void initButtons() {
pinMode(buttonPin, INPUT);
digitalWrite(buttonPin, LOW); // pulldown
}
void initLEDs() {
pinMode(ledPinRed, OUTPUT);
pinMode(ledPinGreen, OUTPUT);
pinMode(ledPinBlue, OUTPUT);
}
void setup(){
establishContact();
initButtons();
initLEDs();
}
void loop() {
delay(20);
accel.loop();
// Calibracion bajo peticion
if (HIGH == digitalRead(buttonPin)) { accel.calibrate(); }
// Enviamos solo 1 de cada 8 muestras
if (--bucle <= 0) { bucle = 8; accel.toProcessing(); }
}
Código fuente de processing
/**
Proyecto : Horizonte Artificial
Autor....: Ricard Forner (RFKsolutions)
Version..: 0.0.1
Fecha....: 10/07/2011
Código fuente: Processing
*/
import processing.serial.*;
//
int appWidth = 400;
int appHeight = 480;
int appCenterX = appWidth/2;
int appCenterY = appHeight/2;
int diametro = 200;
// Puerto serie de comunicacion arduino
Serial port;
// valores procedentes de arduino
int sensorXmV;
int sensorYmV;
int sensorZmV;
int sensorX;
int sensorY;
int sensorZ;
int sensormg;
int sensorPitch;
int sensorRoll;
void setup() {
size(appWidth, appHeight);
smooth();
noStroke();
background(0);
PantallaTexto();
AbrirPuertoSerie();
}
void PantallaTexto() {
textMode(SCREEN);
text("Proyecto Horizonte Artificial", 30, 40);
text("by RFKsolutions", 30, 60);
text("v 0.0.1 - 10 julio de 2011", 30, 80);
text("Prueba: Visualización ROLL", appCenterX, appHeight-40);
text("Hardware: Arduino + ADXL335", appCenterX, appHeight-20);
}
void AbrirPuertoSerie() {
// Pintamos la lista de puertos disponibles
println(Serial.list());
// Puerto del arduino
port = new Serial(this, "COM17", 38400);
// no se leera la función serialEvent() hasta que aparezca un salto de linea
port.bufferUntil('\n');
}
void arduinoPuertoDisponible() {
while (port.available() > 0) {
serialEvent(port.read());
}
}
void serialEvent(int Serial) {
String inStr = port.readStringUntil('\n');
if (inStr!=null) {
inStr = trim(inStr);
// Se dividen los valores por el separador ";"
int[] sensores = int(split(inStr,";"));
if (sensores.length>=10) {
sensorXmV = sensores[1];
sensorYmV = sensores[2];
sensorZmV = sensores[3];
sensorX = sensores[4];
sensorY = sensores[5];
sensorZ = sensores[6];
sensormg = sensores[7];
sensorPitch = sensores[8];
sensorRoll = sensores[9];
}
print(sensorXmV); print("; ");
print(sensorYmV); print("; ");
print(sensorZmV); print("; ");
print(sensorX); print("; ");
print(sensorY); print("; ");
print(sensorZ); print("; ");
print(sensormg); print("; ");
print(sensorPitch); print("; ");
println(sensorRoll);
}
}
void draw() {
arduinoPuertoDisponible();
translate(appCenterX, appCenterY);
float lastAng = radians(sensorRoll);
int[] angs = {180, 180};
for (int i=0; i<angs.length; i++) {
// Horizonte: Zona
if (i==0) {
// Tierra
fill(208, 119, 0);
} else {
// Cielo
fill(108, 156, 255);
}
arc(0, 0, diametro, diametro, lastAng, lastAng+radians(angs[i]));
// Horizonte: Lineas
if (i==0) {
// Tierra lineas
fill(198, 198, 198);
for (int j=0; j<3; j++) {
rotate(lastAng);
rect(-((j%2==0)?40:20), +15+(j*30), (j%2==0)?80:40, 2);
rotate(-lastAng);
}
} else {
// Cielo lineas
fill(198, 198, 198);
for (int j=0; j<3; j++) {
rotate(PI+lastAng);
rect(-((j%2==0)?40:20), -15-(j*30), (j%2==0)?80:40, 2);
rotate(PI-lastAng);
}
}
lastAng += radians(angs[i]);
}
// Parrilla
fill(210,10,10);
rect((diametro/4), -2, (diametro/4), 4);
rect(-(diametro/2), -2, (diametro/4), 4);
}
La idea es crear un Horizonte Artificial mediante un acelerómetro de la familia ADXL3xx, en este caso es un ADXL335 que de Sparkfun y que funciona a 3.3V.
Si quereis ver la entrada entera id a http://bit.ly/nS8l0H, pero mejor seguir la línea en éste foro.