sábado, 3 de diciembre de 2011

Ambilight de 2 canales en Arduino

El último proyecto en que me embarcadado en el mundo del Hardware OpenSource es una solución multimedia para crear un sistema Ambilight utilizando como no, la plataforma Arduino.


Para realizar este proyecto he decidido crear una placa personalizada desde cero (llamada MiAmbilight de 2 canales) realizando su diseño en Fritzing, prototiparla por IxDS de manera profesional, y adquirir todos los productos necesarios, siendo estos:
  • Tira de LEDs RGB de 12V
  • Adaptador 220V-12V
  • Conectores Futaba (de aeromodelismo)
  • Conectores y cable plano bus
  • Placa serigrafiada MiAmbiligth
  • Plataforma Arduino UNO o BoArduino
El diseño ha estado preparado para que sea compatible con el conexionado de Arduino UNO o bien con la BoArduino. En ambos casos, el número de señales PWM esta limitado por lo que máximo que podemos realizar son 2 canales de colores RGB.


TIRA DE LEDS

Puede ser adquirida en eBay o DealExtreme a un precio irrisorio, y nos sirve para montar cada uno de los canales de luz para nuestro Ambilight.






CONEXION AC-DC 12V

Y el resultado es:

PLACA SERIGRAFIADA

Tras soldar los componentes la placa tiene el siguiente aspecto (para cada canal se puede decidir el tipo de conector que se quiera para hacerlo compatible con el conexionado de los leds)

MONTAJE RESULTANTE



Proximamente el código empleado en Arduino y su funcionamiento en real...

domingo, 9 de octubre de 2011

PAROCA I - Información del proyecto en un nuevo feed vía RSS

Se ha añadido una nueva manera de acceder a las evoluciones del proyecto PAROCA I - Plataforma Robótica de Carga mediante RSS en la siguiente dirección:

Fuente RSS: http://feeds.feedburner.com/ParocaRobotics

La información es proporcionada directamente desde un nuevo blog como fuente oficial del proyecto, no obstante y a título personal, las pruebas de ingeniería, desarrollo y montaje se seguirán mostrando en este blog que estás leyendo.


domingo, 18 de septiembre de 2011

Acceso a carpetas compartidas Windows desde FreeNAS usando CIFS/SMB

De todos es sabido que FreeNAS tiene como objetivo principal ser un servidor de ficheros en red, pero podemos darle un punto más de centralización de servicios en servidor, permitiendo acceder desde el propio FreeNAS a carpetas compartidas CIFS/samba, como por ejemplo carpetas compatidas de un PC con sistema operativo Windows.

Por ejemplo, queremos disponer en FreeNAS un directorio /mnt/mount/documentos/ que acceda al PC //192.168.1.2/DocumentosCompartidos, el cual es un PC normal de sobremesa.

PASOS

1. Crear un fichero de configuración (p. ej. en /mnt/mount/scripts/nsmb.conf)
 [default]
workgroup=HOMEWGRP
[COMPUTERNAME]
addr=192.168.1.2
[COMPUTERNAME:USER123]
password=1234
2. Activar el servicio CIFS/SMB

3. Ejecución en Avanzado / Comando de:
mkdir /mnt/mount/documentos
cp /mnt/mount/scripts/nsmb.conf /etc/nsmb.conf
mount_smbfs -N //user123@COMPUTERNAME/DocumentosCompartidos /mnt/mount/documentos

De esta manera ya tendremos montado en el FreeNAS el acceso externo a un recurso compartido.

NOTA: Para desmontar la unidad, tan sencillo como:
 umount /mnt/mount/documentos

sábado, 27 de agosto de 2011

PAROCA I - Plataforma Robótica de Carga: Señalización

Tras realizar las pruebas oportunas en una placa de prototipado del Sistema de Señalización de la Plataforma Robótica de Carga, se ha procedido a crear una placa PCB específica compatible con Arduino a fin de poder ponerla en la pila escalable de placas que ofrece la distribución de pines de Arduino Uno.


Visto en una entrada anterior el uso del Shift Register mediante un 74HC595, la presente placa usa solamente 3 pines, el A0, A1 y A2 para disponer de 8 salidas LEDs, 3 para un LED Tricolor de estado, y 5 más de señalización propiamente. Estos 5 LEDs de señalización pueden tener diferentes operativas tan sólo cambiando el software almacenado en Arduino, tal como luces estroboscópicas, de posicionamiento o para simular un intermitente como los de los automóviles.

Placa de señalización

Esquema realizado con la herramienta Open Source Fritzing.
Esquema realizado con el rellenado de cobre.
Placa PCB fabricada por IxDS según la exportación Gerber realizada con mi diseño en Fritzing.
Placa PCB vista inferior.
Placa PCB con los componentes ya soldados. Destacar que el switch (jumper) que se ve en la parte superior izquierda sirven para cerrar o abrir el circuito GND para los 4 LEDs, tal que que si en vez de un jumper ponemos un interruptor, podremos activar el sistema de luces/LEDs manualmente.

Placa de señalización aplicada en el proyecto PAROCA I

Vista individual de las placas que, de momento, forman el robot PAROCA I, siendo estas la de Arduino o cerebro, la de driver motor y la de señalización.
Vista de las placas en su posicion final.

Seguimos trabajando, seguimos innovando !!!!




martes, 9 de agosto de 2011

Uso del chip Shift Register (74HC595) en Arduino

El chip 74HC595 nos permite utilizar una entrada de datos serie, y convertir un byte a 8 salidas en paralelo. Mediante el uso de una entrada de DATA, una de CLOCK y un LATCH, conseguimos con sólo 3 pines de Arduino procesar 8 salidas paralelas digitales.

Destacar que pueden encadenarse varios chips, por lo que si añadimos un segundo chip podemos tener 16 salidas paralelas simultáneas con 2 bytes, y así sucesivamente.


CIRCUITO
Nuestro prototipo para probar la conversión de serie a digital que nos facilita el 595 se basa en el esquema siguiente:

PROTOTIPO
El prototipo implementado en una protoboard tiene éste aspecto.


CÓDIGO FUENTE DE ARDUINO
La prueba se basa en el sistema de señalización del Proyecto PAROCA I, en que se muestran 5 LEDs en frecuencia estroboscópica (10ms / 64 ms) y un LED tricolor en que se mostrará el estado de la batería.

 /*  

Proyecto.....: PAROCA I
Descripcion..: Plataforma Robotica de Carga
Autor........: Ricard Forner (RFKSolutions.es)
Version......: 0.0.1
Fecha........: 03/08/2011
Código fuente: Arduino
*/
//Pin conectado a latch pin (ST_CP) del 74HC595
const int latchPin = A1;
//Pin conectado a clock pin (SH_CP) del 74HC595
const int clockPin = A0;
//Pin conectado a Data in (DS) del 74HC595
const int dataPin = A2;
//// Luces intermitentes / strobe
int seqLED[5] = {8+16, 8+16, 32+64, 32+64, 128};
//// Luces estado bateria
const int batteryOk = 2; // verde
const int batteryLow = 1; // rojo
int batteryStatus;
void setup() {
initLuces();
batteryStatus = batteryOk;
}
void loop() {
doLuces(batteryStatus);
}
void initLuces() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
void doLuces(int status) {
for (int n=0; n<5; n++) {
digitalWrite(latchPin, LOW);
delay(10);
shiftOut(dataPin, clockPin, MSBFIRST, status+seqLED[n]);
digitalWrite(latchPin, HIGH);
delay(12);
}
}



VÍDEOS
Como resultado de lo publicado en el presente artículo, un par de vídeos de su funcionamiento.


Video de una rotación secuencial de los LEDs.



domingo, 31 de julio de 2011

PAROCA I - Plataforma Robótica de Carga: Chasis

El chasis para la Plataforma Robótica de Carga será integramente en aluminio y realizada 100% personalizada mediante elementos individuales. Estos deberán ser perforados, atornillados o machambrados para su uso, no obstante, nos aseguramos de la unicidad e individualidad del proyecto y de la Plataforma Robótica.


A tal efecto, se utilizarán los siguientes componentes:
  • 2x Ángulo de aluminio de 40mm x 40mm x 3mm x 500mm de largo (6 EUR/ud)
  • 4x Ángulo de aluminio de 40mm x 40mm x 3mm x 250mm de largo (4 EUR/ud)
  • 1x Plataforma antideslizante de aluminio de 500mm x 250mm x 3mm (9 EUR/ud)
  • 1x Placa aluminio de 100mm x 3mm x 250mm (4 EUR/ud)
Coste de los productos: 43 EUR, adquirido en Forward Metals.

En el siguiente conjunto de imágenes podemos ver la plataforma en sus elementos básicos (sin montar) y visto en comparativa a uno de los motores que utilizaré.


Visión inferior de como estará la distribución (los ángulos internos evidentemente no estarán así, sino formando una C para atornillar la base intermedia en donde se alojará la electrónica).


Visión inferior (sólo indicativa de una posible distribución).



Próximamente ...

En una nueva entrada en el blog, se describirá la distribución electrónica básica del PAROCA I, (señalización y motorización) que como adelanto mostraremos un boceto de estos en la imágen siguiente:



domingo, 24 de julio de 2011

PAROCA I - Plataforma Robótica de Carga: Driver + Motores

El primer elemento que necesitamos para la Plataforma Robótica de Carga (PAROCA I) es un driver para los motores DC que se van a utilizar en el prototipo, en este caso 4 motores DC brushes de 6V.

Motor Shield

Lo primero de todo para el driver de los motores es seleccionar el H-Bridge y que mejor que el conocidísimo L293D capaz de proporcionar 600mA (pico de 1.2 A) con protección térmica y operativo en un rango de tensión de 4.5V a 36V. Utilizaremos ya una solución de 4 H-Bridges existente en el mercado realizado por Adafruit.com, el MShield o Motor Shield.


Motor Gear
El motor escogido es el 75:1 Metal GearMotor 25Dx54L mm adquiridos en Pololu, capaz de proporcionar:

Gear ratio 75:1
Free-run speed @ 6V 75 rpm
Free-run current @ 6V 80 mA
Stall current @ 6V 2200 mA
Stall torque @ 6V 6.1Kg·cm


Montaje de los componentes
En la secuencia de imágenes siguiente se pueden ver los elementos que formarán parte del PAROCA I, en este caso:

1x Driver MShield
4x GearMotor 75:1
4x Ruedas 90x10mm
4x Mounting hubs
4x Soportes motor (brackets)
4x Cables JST para fácil conexión/desconexión


Componentes necesarios para montar el shield del motor compatible para Arduino.
Detalles del prototipo, alimentación por pila 9V recargable, Arduino UNO, Motor Shield y 1 Gearmotor.

Detalle de la soldadura de cable al motor protegida por envoltura tubo termoretráctil.
El conjunto de los componentes ya integrados.

Ejemplo del código fuente en Arduino
 #include <AFMotor.h>

// Motor DC en M1
AF_DCMotor motor(1);

void setup() {
Serial.begin(57600);
Serial.println("Iniciando motores...!");
// Configurando velocidad motor #1 (de 0 a 255)
motor.setSpeed(200);
motor.run(RELEASE); // PARAR
}

int i;

void loop() {
motor.run(FORWARD); // Motor: Avance
// motor.run(BACKWARD); // Motor: Retroceso
}

sábado, 16 de julio de 2011

PAROCA I - Plataforma Robótica de Carga: Kick off

Para mi nuevo proyecto de Plataforma Robótica de Carga (llamado desde ahora como proyecto PAROCA) empieza el desarrollo de los elementos que formarán parte del primer prototipo.

Así que: Kick off del proyecto !!

Anteriormente se ha escrito alguna entrada en el blog del uso del Horizonte Artificial para la detección del plano horizontal y su inclinación mediante un acelerometro ADXL335. El objetivo es emplearlo en lo que se llama Parallel manipulators (o Parallel robot) para el presente proyecto, de tal manera que se mantenga siempre la plataforma horizontal independientemente de la inclinación del suelo.

A tal efecto, y tras un estudio de las técnicas empleadas se describen dos vertientes ampliamente estudiadas:
  • Plataforma Stewart (basada en actuators lineales)
  • Delta robot (basado en actuators rotatorios)
Empezamos a mirar la mejor alternativa...

domingo, 10 de julio de 2011

Horizonte Artificial realizado en Processing vía Arduino

La presente entrada en el blog describe el prototipo creado para visualizar y gestionar los llamados "Ángulos de Euler" de aeronáutica/náutica -a fin de ser correctos deberían llamarse ángulos de Cardano. El objetivo, determinar la orientación de un objeto que puede rotar (cabeceo, guiñada y alabeo/balanceo) sobre los ejes intrínsecos.

La siguiente imagen muestra la interficie gráfica creada en Processing para visualizar en tiempo real la información que nos proviene de nuestra plataforma hardware (en este caso vía un acelerómetro de 3 ejes montada sobre una plataforma Arduino)


La primera prueba de horizonte artificial será en este caso sólo tratar y visualizar el ROLL (balanceo/alabeo)


Hardware
- Arduino UNO
- Acelerómetro ADXL335
- LED Tricolor
- Resistencias (1x8.2K, 2x100, 1x180)
- MiniPulsador
- Cables + miniplaca de prototipado


La siguiente imagen muestra el circuito completo de nuestro prototipo. El pulsador se utiliza para calibrar el acelerómetro de 3 ejes, es decir, cuando consideramos una posición estacionaria (sin movimiento) y totalmente horizontal, lo pulsamos y así establecemos el valor llamado zero-g, que sirve para compensar la fuerza gravitatoria según nuestra localización (en Barcelona es 9.803 m/s^2).


El led se enciende sólo durante el periodo de calibración.


En el programa almacenado en Arduino se utiliza el factor scale para fijar al máximo la gravedad a fin que sea considerada 1 gee = 9.8m/s^2.

Software
- Arduino 0021
- Processing 1.5


Se puede apreciar en la consola de la aplicación los grupos de 9 valores que se van recibiendo desde el Arduino, siendo estos:
  • los valores en mV de los ejes X,Y,Z
  • el valor XY respecto la posición de calibraje
  • el factor correctivo de la gravedad versus ADC
  • los milligee (la gravedad en miles)
  • el pitch
  • el roll
A continuación se facilita la primera versión del código fuente para ambos entornos, necesarios para que interactuen entre ellos.

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);
}



Videos
Como resultado de lo publicado en el presente artículo, un par de videos de su funcionamiento.







jueves, 7 de julio de 2011

Servidor de 6Tb y creciendo...

El servidor de datos local basado en FreeNAS, que ampliamente se ha hablado en este blog, dispone en estos momentos de una capacidad total de 6Tb para datos con capacidades de crecimiento dada su escalabilidad tanto en hardware como por el propio sistema operativo NAS.

La configuración actual acutual es:

Placa base (Gigabyte GA-P31-ES3G-E)
4 puertos SATA
2 puertos IDE con adaptador a 2xCF
8 puertos USB2

Controladoras PCI
1x Sil3114 de 4 puertos SATA
1x Sil3124 de 4 puertos SATA (Port Multiplier y NCQ)

Sistema operativo
1x CF de 64Mb para el S.O. FreeNAS
1x CF de 8 Gb para scripts y ficheros intermedios

Datos
1x HD de 2Tb MDT Green
1x HD de 1Tb Seagate Green
1x HD de 750Gb MDT Green
1x HD de 750Gb WesternDigital Green
3x HD de 500Gb Seagate

El servidor sigue siendo ampliable mediante:
1 puerto eSata (externo)
1 puerto SATA/ PortMultiplier (interno)

Destacar que el consumo actual se situa entorno a los 65W.