Clon Ambilight / Boblight con Arduino para XBMC

post

En esta ocasión aprovechamos para presentaros un proyecto sencillo, económico y muy resultón, que hará que vuestro salón destaque con luz propia.

Para este montaje hemos reutilizado pixel leds que nos han sobrado de un mega-proyecto que os presentaremos en breves, pero si donde hay un led hay alegría, nuestra oficina tiene que ser más empalagosa que disneyland  en la casa de la pradera ;)

Para meternos un poco en el tema, ¿Que nos cuenta wikipedia sobre el ambilight?

Ambilight es un sistema de retroiluminación impuesto por Philips para la línea de sus televisores planos de plasma y LCD. El Ambilight sirve para regular el contraste dentro de la habitación.

Ambilight es el resultado de un profundo estudio llevado a cabo sobre el modo en que las personas ven la televisión en casa. Entre los consumidores que probaron Ambilight, más del 70% opinaron que la iluminación alrededor del televisor contribuía a que la experiencia resultase más relajante y a que se mejorasen parámetros de la imagen tales como contraste, profundidad y viveza de los colores. Y el uso del color para la función Ambilight originaba una diferencia aun mayor. La SMTPE (Society of Television and Motion Picture Engineers) también recomienda las pantallas retroiluminadas para incrementar el rendimiento del televisor al máximo.

Ambilight es una tecnología diseñada para mejorar la experiencia visual y se puede utilizar con cualquier tipo de señal de televisión. Sea cual sea la fuente de la señal, la tecnología Ambilight analiza las señales entrantes y produce la luz lateral ambiental adecuada para el contenido que se está visualizando en la pantalla.

En nuestro caso, la conectaremos a una raspberry pi con raspbmc en su última versión, la cual facilita mucho el asunto al tener ya soporte oficial para boblight ;)

Se puede usar en XBMC corriendo en linux, osx y windows.

El montaje se puede hacer o bien con los puertos gpio de la propia raspberry, o delegando el control de los leds a un arduino, lo cual libera la cpu de carga, modo que hemos elegido en este caso.

Materiales necesarios para el montaje:

  1. Arduino uno, mega o equivalentes (se pueden usar leonardo y due, pero es desaprovecharlos y hay que sacar los pines del ICSP)
  2. 50 Leds direccionables con controlador WS2801
  3. Fuente de alimentación de mínimo 2A (para los 50 leds usados, hay que dimensionarla acorde a los leds utilizados)
  4. Cables con conector macho para breadboard (muy útiles y baratos)

Los leds direccionables pueden venir en 3 formatos principalmente, tiras (strip), encapsulado de goma tipo bullet, o encapsulado de goma plano. También los hay en unos pcb cuadrados, pero son más para iluminación en exteriores. En otro post hablaremos mas sobre su funcionamiento y como se direccionan. Recomendamos bullet o planos, ya que con las cintas habría que cambiar todo el archivo de config al llevar mas leds.

Y como unas imágenes valen más que 1000 palabras… bullet, planos y strip

bullet_ws2801 plano_ws2801 strip_ws2801

Lo primero, cargamos el sketch en el

[code lang=”arduino”]
#include <SPI.h>

// LED pin for Arduino:
#define LED_DDR DDRB
#define LED_PORT PORTB
#define LED_PIN _BV(PORTB5)

static const uint8_t magic[] = {‘A’,’d’,’a’};
#define MAGICSIZE sizeof(magic)
#define HEADERSIZE (MAGICSIZE + 3)

#define MODE_HEADER 0
#define MODE_HOLD 1
#define MODE_DATA 2

static const unsigned long serialTimeout = 15000; // 15 seconds

void setup()
{
uint8_t
buffer[256],
indexIn = 0,
indexOut = 0,
mode = MODE_HEADER,
hi, lo, chk, i, spiFlag;
int16_t
bytesBuffered = 0,
hold = 0,
c;
int32_t
bytesRemaining;
unsigned long
startTime,
lastByteTime,
lastAckTime,
t;

LED_DDR |= LED_PIN; // Enable output for LED
LED_PORT &= ~LED_PIN; // LED off

Serial.begin(115200); // Teensy/32u4 disregards baud rate; is OK!

SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV16); // 1 MHz max, else flicker

uint8_t testcolor[] = { 0, 0, 0, 255, 0, 0 };
for(char n=3; n>=0; n–) {
for(c=0; c<25000; c++) {
for(i=0; i<3; i++) {
for(SPDR = testcolor[n + i]; !(SPSR & _BV(SPIF)); );
}
}
delay(1); // One millisecond pause = latch
}

Serial.print("Ada\n"); // Send ACK string to host

startTime = micros();
lastByteTime = lastAckTime = millis();

// loop() is avoided as even that small bit of function overhead
// has a measurable impact on this code’s overall throughput.

for(;;) {

// Implementation is a simple finite-state machine.
// Regardless of mode, check for serial input each time:
t = millis();
if((bytesBuffered < 256) && ((c = Serial.read()) >= 0)) {
buffer[indexIn++] = c;
bytesBuffered++;
lastByteTime = lastAckTime = t; // Reset timeout counters
} else {
// No data received. If this persists, send an ACK packet
// to host once every second to alert it to our presence.
if((t – lastAckTime) > 1000) {
Serial.print("Ada\n"); // Send ACK string to host
lastAckTime = t; // Reset counter
}
// If no data received for an extended time, turn off all LEDs.
if((t – lastByteTime) > serialTimeout) {
for(c=0; c<32767; c++) {
for(SPDR=0; !(SPSR & _BV(SPIF)); );
}
delay(1); // One millisecond pause = latch
lastByteTime = t; // Reset counter
}
}

switch(mode) {

case MODE_HEADER:

// In header-seeking mode. Is there enough data to check?
if(bytesBuffered >= HEADERSIZE) {
// Indeed. Check for a ‘magic word’ match.
for(i=0; (i<MAGICSIZE) && (buffer[indexOut++] == magic[i++]););
if(i == MAGICSIZE) {
// Magic word matches. Now how about the checksum?
hi = buffer[indexOut++];
lo = buffer[indexOut++];
chk = buffer[indexOut++];
if(chk == (hi ^ lo ^ 0x55)) {
// Checksum looks valid. Get 16-bit LED count, add 1
// (# LEDs is always > 0) and multiply by 3 for R,G,B.
bytesRemaining = 3L * (256L * (long)hi + (long)lo + 1L);
bytesBuffered -= 3;
spiFlag = 0; // No data out yet
mode = MODE_HOLD; // Proceed to latch wait mode
} else {
// Checksum didn’t match; search resumes after magic word.
indexOut -= 3; // Rewind
}
} // else no header match. Resume at first mismatched byte.
bytesBuffered -= i;
}
break;

case MODE_HOLD:

// Ostensibly "waiting for the latch from the prior frame
// to complete" mode, but may also revert to this mode when
// underrun prevention necessitates a delay.

if((micros() – startTime) < hold) break; // Still holding; keep buffering

// Latch/delay complete. Advance to data-issuing mode…
LED_PORT &= ~LED_PIN; // LED off
mode = MODE_DATA; // …and fall through (no break):

case MODE_DATA:

while(spiFlag && !(SPSR & _BV(SPIF))); // Wait for prior byte
if(bytesRemaining > 0) {
if(bytesBuffered > 0) {
SPDR = buffer[indexOut++]; // Issue next byte
bytesBuffered–;
bytesRemaining–;
spiFlag = 1;
}
// If serial buffer is threatening to underrun, start
// introducing progressively longer pauses to allow more
// data to arrive (up to a point).
if((bytesBuffered < 32) && (bytesRemaining > bytesBuffered)) {
startTime = micros();
hold = 100 + (32 – bytesBuffered) * 10;
mode = MODE_HOLD;
}
} else {
// End of data — issue latch:
startTime = micros();
hold = 1000; // Latch duration = 1000 uS
LED_PORT |= LED_PIN; // LED on
mode = MODE_HEADER; // Begin next header search
}
} // end switch
} // end for(;;)
}

void loop()
{
// Not used. See note in setup() function.
}
[/code]

Una vez cargado el firm al arduino y conectados los leds,  al darle alimentación deberían de encenderse los leds en rojo, verde y azul. Si es así, ya lo tenemos listo!

Las tiras de leds tienen 4 cables (no tomar como referencia los colores, ya que en cada envío el chino los mandan distintos, tanto en posición como en color dependiendo de la remesa), 2 de alimentación, uno de señal y otro de reloj. En las cintas vienen perfectamente visibles. en los encapsulados, viene grabado en el pcb.

El cable de clock se conecta al clock del bus SPI, pin 13 en el arduino uno
El cable data se conecta al MOSI del SPI (master – to – slave data), pin 11 en el arduino
uno.

wiring-ambilight

Solo nos quedaría colocar los leds. Aqui cada uno se las ingenia como puede, canaletas, chapilla de madera, rejillas etc…

Nosotros hemos optado por tacos brida de pegar, con unas bridas agarrando los leds. Se nos acabaron durante el montaje, de ahí que no haya foto completa montado ;)

Viendo la tv por la parte trasera, hay que empezar por la parte inferior, e irlos colocando en dirección contraria a las agujas del reloj. Unas fotos para aclarar el montaje:

pruebas medio colocados

colocandodetalle colocando

Con esto, ya tendríamos la parte hardware finalizada, sencillo, no? ;)

Ahora vamos a conectarlo al raspbmc en su última versión (a partir de junio-julio). La instalación de raspbmc vamos a dejarla de lado ya que hay cientos de tutoriales en internet. Si hay alguna duda, podéis dejarla en los comentarios de la entrada.

Necesitamos saber la ip de nuestra raspi en la lan, la podemos ver en información del sistema.

Nos conectaremos por SSH con putty o algún otro cliente (user:pi / pass: raspberry)
Como esta última versión ya trae soporte para boblight, solo tenemos que añadir nuestro archivo de config.

En breves subiré el mío, pero mientras os dejo el que he usado inicialmente.

SSH:
sudo wget https://www.dropbox.com/s/f6u82rv22tofbgl/boblight_gpio.conf -O /etc/boblight.conf –no-check-certificate

Y a partir de ahí, solo os queda jugar con los valores del archivo de config para adaptarlo a vuestras necesidades, pero ya funcionaría correctamente.

sudo nano /etc/init/boblight-dispmanx.conf

Para activarlo, en la configuración de raspbmc, activar boblight (esta en el apartado de activar ssh, web, etc…)

Y así queda tras el primer arranque!

primera prueba

Cualquier duda, podeis dejarla en los comentarios.

Salu2!

Fuentes:

http://www.grabthiscode.com/diy/como-montar-tu-sistema-ambilight-en-casa-y-no-morir-en-el-intento/

http://www.briefer.es/2013/04/ambilight-con-arduino-adalight-ws2801-xbmc-y-boblight

Dejar una respuesta

Categorías

Entradas recientes

Comentarios recientes

Archivos

Meta