Pages: 1 [2]   Go Down
Author Topic: MegaBrite & DMX video ceiling  (Read 3124 times)
0 Members and 1 Guest are viewing this topic.
SF Bay Area
Offline Offline
Edison Member
*
Karma: 11
Posts: 1244
Arduino Ninja
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Each MegaBrite has its own voltage regulator for the PWM logic and oscillator, and each LED channel has its own current regulator. I think the last time I ran 80 MegaBrites together, I was using a power supply capable of 50 amps.

It's still a good idea to use 6-pin cables between each MegaBrite. First it provides a good ground reference for all the data cables...second it allows you to go several modules before needing to tap in power using the screw terminals. You can connect power and ground to the screw terminals every 5 to 8 modules, in my experience. Definitely cuts down on the amount of wiring needed, since the screw terminals are not as fast to wire as the 6-pin connectors you can just plug together in seconds.

Savings between four and six conductors is probably less than 10 cents.

Definitely inspect every connection before turning it on. It's easy to wire these wrong when you have more than 50 things to get right. I would suggest just adding a few to the chain every time, power it up, make sure it works, power it down. That way you don't risk killing an entire chain of modules.
Logged

Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

0
Offline Offline
Newbie
*
Karma: 0
Posts: 30
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

is DMX really suitable for passing this much information ?
I don't know how many frames per second you intend to have but controlling individual pixels by DMX sounds to me a lot like swatting flies with a sledgehammer !!
Logged

SF Bay Area
Offline Offline
Edison Member
*
Karma: 11
Posts: 1244
Arduino Ninja
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

DMX is just a neverending stream of raw 8-bit values. As long as you have the software to send out the correct values, it's as minimal and efficient as you can get without some kind of compression scheme.
Logged

Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's a video of the first prototype.



It just uses 9 MegaBrites at the moment and no DMX control yet. I've just made a very simple controller which allows me to set colours for testing out different diffuser materials and spacing of the MB. Also tried separating the MB into their own cell, which gives clearer colours, but not sure if it's the look we'll go for.

« Last Edit: July 20, 2010, 09:41:01 am by headfull » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Shodan,
DMX seems to be the standard solution to this kind of LED video installation. Check out software like Madrix, http://www.madrix.com/
It has some decent effects and video in via a video card. I plan to use my normal VJ setup on a separate computer and just feed the video out into the PC with Madrix running.
The resolution of even a massive video wall is very low (compared to normal video). Our planned installation is about 27 x 99 px (5 x 16 meters). So that's 2673 pixels = 8019 DMX channels. Spread that over 16 DMX universes (2 arduino megabrite chains per universe) and (fingers crossed) it will be ok. One of the guys from Madrix said they had run over 80 DMX512 universes no problems.
Because DMX512 is a standard for lighting and other devices, it's a good choice for future compatibility of the video wall.
But if you think there is a better way, please let me know. Buying 16 DMX USB interfaces is expensive. I'm not committed to using DMX yet, but will be soon once I buy those interfaces.
Thanks
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Macegr
Thanks again for the tips.
 smiley
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's some documentation of the second prototype using 81 MegaBrites and now working with Madrix software via DMX. There are a few mistakes in the code still so the channel addressing is a bit weird, but it works enough to show you this test. It was really easy to get this going thanks to the sample code on the Macetech site
http://docs.macetech.com/doku.php/megabrite
and the excellent work of Max Pierson
http://blog.wingedvictorydesign.com/2009/03/20/receive-dmx-512-with-an-arduino/



I didn't have the diffuser material we are going to use in the production version so have just used what I had at hand, which in this case was shoji window screens (I live in Japan). But they work pretty good as a diffuser


I invested a lot of time trying to find a cheap and easy way to attach MegaBrites to the aluminium frame. I'll be attaching about 3200 of them, so it's gotta be super easy and quick to do, but also durable enough to last. The solution I think we will use is this 15mm PVC pipe cut to 10mm lengths and cable ties. A bit of 15mm pipe fits around the pins on the underside of the MegaBrite perfectly and a cable tie goes under the red LED and around the unit. It's actually pretty strong and only allows a little twist, but no other rotation.




Here's a video of it hooked up to Madrix...

[media]http://www.youtube.com/watch?v=M1qFlCoRxdg[/media]
« Last Edit: August 13, 2010, 12:33:22 pm by headfull » Logged

SF Bay Area
Offline Offline
Edison Member
*
Karma: 11
Posts: 1244
Arduino Ninja
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This is going to be the best thing ever, in the entire world. I might have to fly to Japan.
Logged

Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@macegr
there are a lot of beers with your name on them waiting for you when this club opens in December.
X-mas in Japan?
Thanks for all the help!


Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi

below is the code I've got running at the moment. There are a few problems I haven't been able to solve so I would appreciate someone taking a look. I've basically just taken Max Pierson's DMX reception code and edited out the EEPROM addressing bits as I want the addressing to be done in the code as it'll never change. And I've added in MaceTech's sample ShiftBrite code and the conversion from DMX to serial in the action() function.

My main problem is probably to do with a mistake in the addressing. The green LED in first MegaBrite in the chain doesn't work. I'm guessing this is the very first DMX address. Madrix software is sending channels 1 thru 243. Any ideas?

Thanks
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
/***********************************************************
* MegaBrite_DMX - DMX controlled MegaBrites video panel
* v01 2010.08.14
* by VJ Headfull (AKA Jamie Goodenough) http://www.headspace.jp
*
* Original DMX-512 Reception code by Max Pierson http://blog.wingedvictorydesign.com
* Original MegaBrite code by MaceTech http://docs.macetech.com
*
* Released under the WTFPL license, but please mention above contributers and share alike.          
*
************************************************************/

/******************************* MegaBrite declarations *****************************/
#define clockpin 13 // CI
#define enablepin 10 // EI
#define latchpin 9 // LI
#define datapin 11 // DI
 
#define NumLEDs 81

int LEDChannels[NumLEDs][3] = {0};
int SB_CommandMode;
int SB_RedCommand;
int SB_GreenCommand;
int SB_BlueCommand;

/******************************* Addressing variable declarations *****************************/

#define NUMBER_OF_CHANNELS 244
//the number of channels we want to receive.
// 81 megabrites * 3 LEDs = 243 channels
// 243 + 1 = 244
// NOTE: not sure why we need to add one here, but it works.

unsigned int dmxaddress = 4;
// The dmx address we will be listening to.
// NOTE: Madrix software is sending channels 1 thru 243
// Start channel = 1, plus 3 because...
 /*  this will allow the USART receive interrupt to fire an additional 3 times for every dmx frame.  
  *   Here's why:
  *   Once to account for the fact that DMX addresses run from 0-511, whereas channel numbers
  *        start numbering at 1.
  *   Once for the Mark After Break (MAB), which will be detected by the USART as a valid character
  *        (a zero, eight more zeros, followed by a one)
  *   Once for the START code that precedes the 512 DMX values (used for RDM).  */
  
/******************************* MAX485 variable declarations *****************************/

#define RECEIVER_OUTPUT_ENABLE 2
/* receiver output enable (pin2) on the max485.  
*  will be left low to set the max485 to receive data. */

#define DRIVER_OUTPUT_ENABLE 3
/* driver output enable (pin3) on the max485.  
*  will left low to disable driver output. */

#define RX_PIN 0   // serial receive pin, which takes the incoming data from the MAX485.
#define TX_PIN 1   // serial transmission pin


/******************************* DMX variable declarations ********************************/

volatile byte i = 0;              //dummy variable for dmxvalue[]
volatile byte dmxreceived = 0;    //the latest received value
volatile unsigned int dmxcurrent = 0;     //counter variable that is incremented every time we receive a value.
volatile byte dmxvalue[NUMBER_OF_CHANNELS];    
/*  stores the DMX values we're interested in using--
 *  keep in mind that this is 0-indexed. */
volatile boolean dmxnewvalue = 0;
/*  set to 1 when updated dmx values are received
 *  (even if they are the same values as the last time). */


/******************************* Timer2 variable declarations *****************************/

volatile byte zerocounter = 0;          
/* a counter to hold the number of zeros received in sequence on the serial receive pin.  
*  When we've received a minimum of 11 zeros in a row, we must be in a break.  As written,
*  the timer2 ISR actually checks for 22 zeros in a row, for the full 88uS break.       */



/******************************* setup() ***********************************/

void setup() {
  
  /******************************* MegaBrite configuration ***********************************/
  
   pinMode(datapin, OUTPUT);
   pinMode(latchpin, OUTPUT);
   pinMode(enablepin, OUTPUT);
   pinMode(clockpin, OUTPUT);
   SPCR = (1<<SPE)|(1<<MSTR)|(0<<SPR1)|(0<<SPR0);
   digitalWrite(latchpin, LOW);
   digitalWrite(enablepin, LOW);
  
  
  
  /******************************* Max485 configuration ***********************************/
  
  pinMode(RECEIVER_OUTPUT_ENABLE, OUTPUT);
  pinMode(DRIVER_OUTPUT_ENABLE, OUTPUT);
  digitalWrite(RECEIVER_OUTPUT_ENABLE, LOW);
  digitalWrite(DRIVER_OUTPUT_ENABLE, LOW);    //sets pins 3 and 4 to low to enable reciever mode on the MAX485.

  pinMode(RX_PIN, INPUT);  //sets serial pin to receive data



  /******************************* USART configuration ************************************/
  
  Serial.begin(250000);
  /* Each bit is 4uS long, hence 250Kbps baud rate */
  
  cli(); //disable interrupts while we're setting bits in registers
  
  bitClear(UCSR0B, RXCIE0);  //disable USART reception interrupt
  
  
  
  /******************************* Timer2 configuration ***********************************/
  
  //NOTE:  this will disable PWM on pins 3 and 11.
  bitClear(TCCR2A, COM2A1);
  bitClear(TCCR2A, COM2A0); //disable compare match output A mode
  bitClear(TCCR2A, COM2B1);
  bitClear(TCCR2A, COM2B0); //disable compare match output B mode
  bitSet(TCCR2A, WGM21);
  bitClear(TCCR2A, WGM20);  //set mode 2, CTC.  TOP will be set by OCRA.
  
  bitClear(TCCR2B, FOC2A);
  bitClear(TCCR2B, FOC2B);  //disable Force Output Compare A and B.
  bitClear(TCCR2B, WGM22);  //set mode 2, CTC.  TOP will be set by OCRA.
  bitClear(TCCR2B, CS22);
  bitClear(TCCR2B, CS21);
  bitSet(TCCR2B, CS20);   // no prescaler means the clock will increment every 62.5ns (assuming 16Mhz clock speed).
  
  OCR2A = 64;                
  /* Set output compare register to 64, so that the Output Compare Interrupt will fire
  *  every 4uS.  */
  
  bitClear(TIMSK2, OCIE2B);  //Disable Timer/Counter2 Output Compare Match B Interrupt
  bitSet(TIMSK2, OCIE2A);    //Enable Timer/Counter2 Output Compare Match A Interrupt
  bitClear(TIMSK2, TOIE2);   //Disable Timer/Counter2 Overflow Interrupt Enable          
  
  sei();                     //reenable interrupts now that timer2 has been configured.
  
}  //end setup()




/******************************* loop() ***********************************/

void loop()  {
  // the processor gets parked here while the ISRs are doing their thing.
  //
  if (dmxnewvalue == 1) {    //when a new set of values are received, jump to action loop...
    action();
    dmxnewvalue = 0;
    dmxcurrent = 0;
    zerocounter = 0;      //and then when finished reset variables and enable timer2 interrupt
    i = 0;
    bitSet(TIMSK2, OCIE2A);    //Enable Timer/Counter2 Output Compare Match A Interrupt
  }
} //end loop()




/******************************* action() ***********************************/

void action() {

int counter = 0;

for(int j = 0; j < NumLEDs; j++)
  {
  
   LEDChannels[j][0] = map(dmxvalue[counter], 0, 255, 0, 1023);
   counter++;
   LEDChannels[j][1] = map(dmxvalue[counter], 0, 255, 0, 1023);
   counter++;
   LEDChannels[j][2] = map(dmxvalue[counter], 0, 255, 0, 1023);
   counter++;
  
  }
 
  WriteLEDArray();
  
  return;  //go back to loop()
} //end action()



/******************************* ISR() ***********************************/

//Timer2 compare match interrupt vector handler
ISR(TIMER2_COMPA_vect) {
  if (bitRead(PIND, PIND0)) {  // if a one is detected, we're not in a break, reset zerocounter.
    zerocounter = 0;
    }
  else {
    zerocounter++;             // increment zerocounter if a zero is received.
    if (zerocounter == 22)     // if 22 0's are received in a row (88uS break)
      {  
      bitClear(TIMSK2, OCIE2A);    //disable this interrupt and enable reception interrupt now that we're in a break.
      bitSet(UCSR0B, RXCIE0);
      }
  }
} //end Timer2 ISR



ISR(USART_RX_vect){
  dmxreceived = UDR0;
  /* The receive buffer (UDR0) must be read during the reception ISR, or the ISR will just
  *  execute again immediately upon exiting. */
 
  dmxcurrent++;                        //increment address counter
 
  if(dmxcurrent > dmxaddress) {         //check if the current address is the one we want.
    dmxvalue[i] = dmxreceived;
    i++;
    if(i == NUMBER_OF_CHANNELS) {
      bitClear(UCSR0B, RXCIE0);
      dmxnewvalue = 1;                        //set newvalue, so that the main code can be executed.
    }
  }
} // end ISR



/******************************* MegaBrite Code ***********************************/

void SB_SendPacket() {
 
    if (SB_CommandMode == B01) {
     SB_RedCommand = 120;
     SB_GreenCommand = 100;
     SB_BlueCommand = 100;
    }
 
    SPDR = SB_CommandMode << 6 | SB_BlueCommand>>4;
    while(!(SPSR & (1<<SPIF)));
    SPDR = SB_BlueCommand<<4 | SB_RedCommand>>6;
    while(!(SPSR & (1<<SPIF)));
    SPDR = SB_RedCommand << 2 | SB_GreenCommand>>8;
    while(!(SPSR & (1<<SPIF)));
    SPDR = SB_GreenCommand;
    while(!(SPSR & (1<<SPIF)));
 
}
 
void WriteLEDArray() {
 
    SB_CommandMode = B00; // Write to PWM control registers
    for (int h = 0;h<NumLEDs;h++) {
        SB_RedCommand = LEDChannels[h][0];
        SB_GreenCommand = LEDChannels[h][1];
        SB_BlueCommand = LEDChannels[h][2];
        SB_SendPacket();
    }
 
    delayMicroseconds(15);
    digitalWrite(latchpin,HIGH); // latch data into registers
    delayMicroseconds(15);
    digitalWrite(latchpin,LOW);
 
    SB_CommandMode = B01; // Write to current control registers
    for (int z = 0; z < NumLEDs; z++) SB_SendPacket();
    delayMicroseconds(15);
    digitalWrite(latchpin,HIGH); // latch data into registers
    delayMicroseconds(15);
    digitalWrite(latchpin,LOW);
 
}

Logged

SF Bay Area
Offline Offline
Edison Member
*
Karma: 11
Posts: 1244
Arduino Ninja
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Not really sure...could it have something to do with the DMX address of 4 at the beginning? And then an offset due to the zero index arrays...

How about if you try to make the software address just that one LED. You might have to send starting on channel 2 maybe?

Or that LED might just be bad, unless you can make it work at another location.
Logged

Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

this is amazing.  i do visual design for a band and we have a ton of DIY stuff i've done already... we were considering moving to element labs gear for the next phase but this whole thread has me seriously reconsidering.  this will probably look incredible when finished.

offtopic maybe but:  which version of madrix did need to get to support the pixelmapping?  
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 1
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Any update on this incredible project?? I'd love to see some more photo's or video of the progress! Pretty please?
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 8
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Seconded on that. Such an inspiration.
Logged

Pages: 1 [2]   Go Up
Jump to: