Daft Punk Helmet Project by ThreeFN

Arduino, Seeeduino Serials and mutants. Share your problems and experence on arduino compatible board such as seeeduino/stalker, etc.

Moderators: lily.li, violet, salmanfarisvp

User avatar
seeedstudio-fan128
Staff
Staff
Posts: 46
Joined: Thu Feb 19, 2009 11:58 pm
Location: China
Contact:

Daft Punk Helmet Project by ThreeFN

Post by seeedstudio-fan128 » Wed Oct 07, 2009 5:06 pm

Daft Punk Helmet Project
by ThreeFN
BDA74087-63B9-4DB1-A592-0057D601BE74.jpg
BDA74087-63B9-4DB1-A592-0057D601BE74.jpg (47.63 KiB) Viewed 16649 times
The History:

This project began back in October of 2006 as a challenge by a friend. After I had shown him the film Interstella 5555, one of Daft Punks signature films, he challenged me to make a replica Guy-Manuel de Homem-Christo helmet, including a full face “screen” made from LEDs from some of the duos Japan interviews. Since that day this project has been a minor, and sometimes major, obsession of mine.
When I began to spec the project, the original resolution was 15x40 RGY LEDs. This somehow morphed into 16x32 RGB LEDs, and finally into 16x24 RGB after more detailed measurements and a few iterations of a solid model mock up.

The project largely waddled in purgatory for years. I wrote many design documents, mostly as sketches in power points, thinking about the different ways the project could be completed. I had a little programming experience with ADA95, an all but forgotten language. I also had no microcontroller experience to speak of. A friend at university was largely my source of technical uC knowledge, and I’m sure I drove him nuts with all of my questions.

I started with the idea of using the MAX7965, however no one had managed to accomplish RGB, and over the past 3 years I have heard of only one or two more that have tried. Most discovered timing problems that gave abysmal frame rates. Next I was drawn to the Sparkfun LED backpacks, since they provided and integrated solution, but it didn’t seem particularly applicable. At that point I had accepted that I would have to custom build my own LED screen out of individually wired LEDs, and the Sparkfun backpack’s cost and size/shape was becoming more of a hindrance as I got deeper into the design. I also wasn’t sure how well it would play with the LEDs I would eventually use, as it was very much designed for the LED matrix unit it ships with and didn’t look particularly friendly to a custom hack job.

As I was coming to the conclusion that I would have to make my own controller boards, most likely a cloned but smaller version of the Sparkfun backpack, and was within days of downloading Eagle and giving it a shot, I found the Rainbowduino. It was like the stars had aligned. I had a little knowledge of the arduino language at this point from an unrelated RFID door unlocker project, so I wouldn’t have to jump into the programming totally blind. The rainbowduino also fixed a lot of the problems I would have had with the Sparkfun backpack or my DIY clone. The drive current is adjustable, the pin out is logically grouped by color (not the case with the sparkfun) and it was daisy chainable right out of the box. And it was cheaper, even when I bought the prebuilt LED matrices to prototype with. Within hours I had ordered 6 of them and I began the long and extremely trying task of rewriting the firmware.

Goal & Purpose:

Part of my goal with this project is I want it to be an “immersive experience” for people seeing the complete costume and helmet. I don’t want it to simply look cool, running static loops of animations like something from the Las Vegas strip. I want it to respond and interact in a cool way. Ideally, I would be able to have a simple conversation with someone using only images and responses shown on the display. I would like to really look, and act, like a robot, with no voice and just a display for interaction with viewers. It’s all about suspension of disbelief.

The best way to explain my approach to this project and the method to my madness is a perpetual need to “one-up.” Sometimes this means going further than what has already been done, like doing RGB instead of Daft Punks RGY. Sometimes this means adding things that I thought would be cool way back when, such as my virtual eye OSD system. Sometimes this means going as far as my skills and available hardware will let me go, such as my spectrum analyzer animation. The spectrum analyzer was definitely in the “when pigs fly” category way back when I first started in 2006. And now it’s been implemented. Suffice it to say, I’m a particularly driven individual on this project.

This project has been boiling for so long in the back of my head that it’s a mild obsession. I don’t think I will ever be truly happy or truly finished. I will always find new and exciting ideas that I want to implement. The need to one-up always seems to put my project in the realm of just out of reach, and yet I am continuously able to proceed in a forward direction, and that is part of why I continue to increase the complexity of this project, because I continue to surprise myself and accomplish what I think can’t be done.

The Work:

There were many problems that had to be overcome, most of which I had figured out before even ordering the rainbows. The default firmware had done a lot of the heavy lifting, low level, shift out LED control for me, so I could instead focus on extending the command and communication levels of the software. I decided to stick with the I2C communication bus for a few reasons: it was already populated with up and downstream connectors, it required the minimum number of bus wires, and it was the architecture I wanted with a single master and multiple addressable slaves on one bus.

The default commands were a good starting point, but since my screen wasn’t single row “billboard” style and I wanted to do complex animations calculated on the master arduino, I needed the ability to send color data for all pixels all at once as part of a single command. This meant a minimum of 96 bytes of data if I wanted the full 4 bits per color, and of course I wanted it. I immediately decided to do the I2C bus speed hack that boosts the arduino’s default 100KHz speed up to 400KHz. The arduino I2C bus buffer is only 32 bytes, so I implemented a simple handshake routine where the master status callback would now return the number of the next desired block of data. Theoretically this would improve error handling though in practice I’ve never seen issues that weren’t related to a deliberately interrupted block from a reprogramming of the master.

After I had implemented the ability to send a “full frame” of color data that could be written one-for-one to the rainbows display buffer, I began doing my early animations and static images. I quickly realized that complex animations that took considerable computation time tanked on frame rate due to the relatively long transmission time of 3 blocks of data at 32 bytes per block. I did some optimization of the code but the frame rate was still not quite sufficient in my opinion. I also realized that a lot of my static images contained three or fewer colors and those were taking up a lot of my PROGMEM space when they each had 3*32*6=576 bytes per “screen.” I had only programmed ten static images before I had run out of the 14K of flash I had on my Arduino 168. This meant I needed a new data structure and command set that was more efficient.

To fix my space/frame rate problem, I made three limited color command/data types: monochrome, dichrome, and trichrome. As the names imply, each one is prefaced with one, two, or three color values much like the base command set. This is followed by sets of 8 bytes, one for each color. The 8 bytes contain on/off bits for each led, row by row, left to right. This greatly reduced the memory footprint of many of my static images, and it meant that animations could be more complex with very good frame rates so long as they used a reduced color set. This was especially helpful with my Conway’s Game of Life animation. My frame rates running a single color loop with very little master side calculation (close to the maximum possible) look something like this:
Full RGB: ~24fps
Trichrome: ~80fps
Dicrhome: ~110fps
Monochrome: >160fps

The main reason for the incredibly high frame rates is that the chromatic commands can all fit in the first block of transmission (<32 bytes). Most transmission delay is due to the delay required after the Wire.endTransmission when the buffer is emptied and sent on the bus. Even at only 250us this delay adds up quickly with 6 rainbows, and it is present no matter how big the transmission data amount.
The firmware has largely remained unchanged since the implementation of the chromatics. I’ve been meaning to put a few two dedicated random white noise animations directing into the firmware, but haven’t gotten around to it after having a function problem. I’m sure I could add quadchrome up to the Nth degree, but having trichrome whittled down most of my flash memory outlay, and that was its primary purpose. The increased frame rate was just a very nice bonus.

I’ve also thought about adding my own ASCII character system to the firmware, but with the chromatics already programmed and having very good frame rates, I’m finding very little need to do things on the slave side rather than the master side.

The How-To:

There isn’t much to say on how to get to the same place I am. OK, that’s not true, I wrote a whole manual document which you will find along with the code. I’ve copied the comments included in the code below for some starting information:
//=====================================================================
//Rainbowduino Seeedmaster V2
//Originally provided by Seeed Studio
//Modified by Scott C.
//=====================================================================

//=====================================================================
//This is master-side code that contains some prebuilt functions for
//sending commands to a Rainbowduino running V2.7 or later
//The original commands have not been changed, so this code
//could theoretically send commands to V2, but only 'R' commands. Both
//the master and slave code have been modified to support multiple data
//transmission session over the IIC communications bus, due to the Wire
//Library limitation of only 32 bytes per transmission. This is most
//evident in changes to the function SendCMD.
//
//In addition a few new command types have been added. A command
//starting with 'F' sends color data for each of the 64 leds set up
//similiar to the buffer on the Rainbowduino (byte per two leds). This
//allows for complex animations to be calculated on the master, and
//then the "frame" of data for all leds to be sent to the slave
//Rainbowduino. This is particularly helpful for animations involving
//more than one Rainbowduino comprising a "screen."
//
//There are also three other command types dubbed "chromatics."
//Monochromatic (one color), dichromatic (two), and trichromatic
//(three) frames can be sent with commands starting with 'M','D', and
//'T' respectively. Each of these commands consists of the relavent
//number of RGB values, followed by 8 bytes per unique color. Each
//byte in one of these sets represents a line on the display, 1 meaning
//the led is on, 0 off. These commands are much smaller, and transmit
//in the first transmission session so they are much faster, especially
//important for large screens with many Rainbowduinos.
//
//It is highly recommended for 'F' commands and large screens to modify
//the Wire library for the faster 400KHz transmission.
//Info on how to do this can be found here:
//http://www.arduino.cc/cgi-bin/yabb2/YaB ... 41668644/0
//
//VERY BIG NOTE: The functions outlined below, specifically ShowFrame,
//can very quickly eat up your available SRAM. I developed this on the
//older 168 chip, and kept a very keen eye for minimizing SRAM usage
//with unsigned char datatypes whereever possible. However, a single
//input array of the kind in ShowFrame is 96 bytes, 1/10th of the 1K
//SRAM is gone right there. the 168 has made way for the 328, but I
//recommend becoming familiar with PROGMEM and rewrite your functions
//to extract data from flash memory, rather than defining the data like
//normal variables. Not having enough SRAM shows up as very bizarre
//errors that are difficult to track down and fix, and you will not
//be notified at compile time. Moving images and data to PROGMEM
//allows you to see how much storage you are using at compile time,
//since PROGMEM variables are stored in flash and become part of the
//sketch size in flash memory. Overstepping the available flash memory
//will throw an error when compiled/uploaded.
//
//The screen I rewrote this code for is 6 Rainbowduinos, and the master
//stores over 30 images using chromatics and a handful of full RGB
//images and is only 7.5K in flash memory. Some examples of this can
//be found by searching Youtube for user ThreeFN.
//======================================================================

The Rest of the Project:

There are now so many parts to this project, it can be really tricky to keep it all straight in my head, let alone be able to explain it. I will try and break it down into its logical parts as best I can.
The Display: the backbone of this project. Consisting of the 6 rainbowduinos that will drive a custom built 16x24 RGB LED matrix that will be hand wired.

The Virtual Eye System: The VES is a combination of a small CMOS camera, an on screen display (OSD) chip, and set of video glasses. Since I won’t be able to see through the LED screen, I needed a camera/goggle system to supplement my vision. I one-upped this requirement by adding the OSD that will be used as to give status information. Early testing on this stuff has been completed, and I say that there are a lot of wires needed for this, since each part has its own video and power connection requirement.
495BFEF6-1489-46F8-A777-C86D6207081E.jpg
495BFEF6-1489-46F8-A777-C86D6207081E.jpg (93.66 KiB) Viewed 16649 times
The Interface: with the addition of the VES OSD the interface actually became a lot simpler. I had long planned for a set of armlet control panels with buttons on them to give input to the system. These were used by Daft Punk in their system, but the lack of vision would hamper the use of traditional buttons due to limited vision. I thought of a method to get around this problem by using buttons placed in the fingertips of the plated ‘robot’ gloves I would be wearing. With these button gloves and an on screen menu system, it could be very easy and innocuous to manipulate the display. I’m looking into methods other than push buttons right now, such as bend resistors or hall effect sensors so that the finger tips can be smaller and require less pressure/pain to push.
963F37B3-78E3-4C30-9CC5-A1AC243B44AE.jpg
963F37B3-78E3-4C30-9CC5-A1AC243B44AE.jpg (14.09 KiB) Viewed 16649 times
he Power System: I’m planning on 5 hours of un-tethered run time. This means I will probably run the whole system off of an external laptop battery, which will plug into a power distribution and monitoring system. I have a particularly nifty idea to also have the power supply for the battery as part of the system, so that I can plug into the wall outlets on the fly through a plug “tail,” maintaining the suspension of reality and the immersive-ness of the costume.
E78B6D7B-386A-40F5-9B13-089831C62D43.jpg
E78B6D7B-386A-40F5-9B13-089831C62D43.jpg (30.34 KiB) Viewed 16649 times
The Under Suit: I’d like to be able to wear a variety of different exterior costumes with the helmet to suit the mood and to change things up from Daft Punks signature leather outfits. To allow for different exterior costumes but still keep the cables, connections, and components manageable I’ve been working on an electronics under suit that will be worn under whatever costume I decide to wear that day. This not only gives something to sew cables and connections to permanently, it also gives not to use a backpack to contain all of the parts I’m going to need to carry around. I think it would add a lot if I didn’t need a backpack; certainly it would add to the one-up factor and a clean appearance. Practicality may win out and require a backpack, but I’m still very much try to keep components flat and small so that they can be put in pockets sewn into the under suit.

The Project Now:

The current problem that occupies my thoughts is manufacturing the helmet. My company machinist has become very interested in the project and has offered machine time and assistance in making my molds, simplifying my work tremendously. I will continue to write all of the code as yet unwritten of course. The virtual eye and information management system is next on that list.

I continue to move forward, but it all seems to go in slow motion. It’s taken me years to get to this point, and it will certainly take months for me to finish. My highest hopes are for a debut during the US convention season next spring/summer. I’m hoping to debut at a big con, like Comic Con or Dragon Con.

Additional Media:

I have made a few videos of my project, which were recently reposted to Vimeo for the competition. You can find these videos on Vimeo or on Youtube under the username ThreeFN.

http://vimeo.com/user2397196

http://www.youtube.com/user/ThreeFN

I am also post regular progress on The Daft Club Forums under the same user name:

http://www.thedaftclub.com/showthread.p ... 4&page=287

Source code download
Rainbow_Command_Beta2.zip
(20.67 KiB) Downloaded 619 times

ThreeFN
Pre-kindergarten
Pre-kindergarten
Posts: 8
Joined: Tue Sep 08, 2009 8:15 am

Re: Daft Punk Helmet Project by ThreeFN

Post by ThreeFN » Thu Oct 08, 2009 1:26 am

Here is the manual that is included in the code zip. Included here for reference.

Rainbow Command Beta 2 - Manual

After heavily modifying the Rainbowduino beta code for my own purposes, I decided that the functionality I had added would be useful for most users. I wanted to have more control over each led or ‘pixel,’ without having to pre-code all potential ‘frames’ I wanted to see on the rainbowduino. A command structure that would allow for a rainbowduino to receive an entire frame as part of the command allows a user to arrange complex animations on the master arduino, and then send the frames to be displayed on each of the rainbowduinos in use, be it one or many.

In order to be able to send a full set of RGB data, similar to what will be contained in the displaying buffer on the rainbowduino, at least 96 bytes needed to be sent (one byte containes a brightness value for one color for two adjacent leds). But things of course are never that easy, since the Wire library used by the arduino for IIC communication can only send 32 bytes in a single send session. To overcome this, both the master and rainbowduino communication code had to be altered to support multiple data sessions. The end user will probably not notice this in any serious way. However, with up two 4 ‘long’ communication sessions taking place before a single frame, it is reasonably easy to confuse things. I have tried to set up the handshake in such a way that there is decent error rejection, however it is still reasonably easy to confuse things by interrupting communication. To avoid potential problems, make sure that the rainbowduino(s) come on before the master arduino. You will notice that there is a delay in the SeeedMaster setup() function to facilitate this when both run from the same power source. However, it is very common to run the SeeedMaster and the rainbowduino from different power supplies, so make sure you implement so way to insure that SeeedMaster starts it’s loop() function last (increase delay, etc).

A few quick notes about using the functionality I’ve added to the rainbowduino. The biggest pointer I can give is to be aware of your memory footprint. A single array set up as ColorData[3][8][4] is 96 bytes of memory. Multiply that by a few rainbowduinos to make up a ‘screen,’ and multiply a few more times for a simple frame-to-frame animation and you will have used up all of your available SRAM. I suggest for frame-to-frame animations that you become familiar with moving constant variables to the flash memory using PROGMEM. This will greatly reduce your SRAM usage. I developed the code on an older Arduino with an ATMega 168 which only has 1K memory, so I tried to use the smallest variable possible (usually unsigned char, same as a byte) wherever possible.

Command Structure

The command structure had to be changed to allow for multiple data sessions to occur, so RainbowCMD is not [4][32] as opposed to [5]. For the ‘R’ commands carried over from the previous version, the new command will look like this:

RainbowCMD[0] [ ‘R’ , Command , Shift , R , G , B , Index]
The command order itself hasn’t changed, only that it needs to be prefaced with [0] because the array has an additional dimension.

New Commands

This is what you probably wanted to read, the new commands available with version 2.7.

FRAME command

The Frame command is set up so that you can send color data for each pixel at the full 4 bit resolution per color. This will give you a total of 4096 unique color combinations. The first session of data (RainbowCMD[0]) contains only the ‘F’ character in the 0 position. The second, third, and forth data session contain the color data formatted as 4 bytes per row, one row after the other. The table bellow should help visualize this:

Image

Each color byte, aka two pixels side by side, gives you 4 bit brightness control, first 4 bits for the left pixel and the last 4 for the right pixel. Make sure that when you populate the command this is how you go about assigning brightness values to each pixel, and not using any other data type. It is usually best to use hexadecimal to do this.

CHROMATIC Commands

The frame command is very useful for lots of applications, as it essentially give your full pixel by pixel color control of a rainbowduino. However, these commands are very large and take some time to transmit and process. Most of the delay comes from the fact that each data session requires adding a delay to let the rainbowduino receive and process the Frame command it has just been sent. Since there are 4 of these commands, there is such a delay, ‘screens’ of multiple rainbowduinos can have a rather low overall frame rate. To mitigate this I created three additional commands that are much sorter (<30 bytes) and can be sent in the first data session much like the ‘R’ commands, but that still contain pixel-by-pixel control data. For this I created Monochromatic (one color), Dichromatic (two colors), and Trichromatic (three colors) commands.

A chromatic command lets you specify a color that you would like assigned to all pixels you choose, and if that pixel is on that color displays, otherwise the pixel is off/dark. With the di/trichromatic commands you have two or three specific colors, and pixel data for each color just like in the monochromatic case. It is worth noting that the first color will overwrite the second, and second overwrites the third. This is useful if you just want to add another layer of color on top of an existing image you’ve already put in your code. The color is COMPLETELY overwritten, meaning if layer 2 is red, and layer 1 is blue, the shared pixels will be blue, not purple.

The data structure for each command is straightforward. It starts like all commands with a character, ‘M’, ‘D’, and ‘T’ respectively. This is followed by the values for the colors that will be used (input as 4 bit RGB like pretty much everything so far), followed by 8 bytes per color that determines which pixels will be lit. these 8 bytes each represent a row, and a byte is populated with bits that determine if a pixel is on (1) or off (0).

Here is a byte-by-byte table of how each command structured. Note that all the bytes are in the first data session. Also note that a single color only occupies 4 bits, so more than one color per byte means that the left value will need to be bitwise shifted and bitwise OR’d with the right value to populate the byte.

Image

mshaub
Pre-kindergarten
Pre-kindergarten
Posts: 12
Joined: Mon Oct 12, 2009 2:46 pm

Re: Daft Punk Helmet Project by ThreeFN

Post by mshaub » Mon Oct 12, 2009 2:55 pm

Your work is very impressive, and I'm trying to learn by following your examples. I had a heck of a time getting your program installed on my Rainbowduino, and ended up using a USB ISP programmer from Adafruit. That seemed to work, but I cannot compile the SeeedMaster2.pde you included in my Arduino 17 (running on an intel mac osx10.5).

Specifically, I'm getting:
error: invalid types 'unsigned char[int]' for array subscript

and the IDE has highlighted this line:
RainbowCMD[0][0]='F';

Honestly, I'm feeling way over my head and it's quite possible that I've made a bone-headed mistake. Please let me know if you have any ideas about the issue here. Thank you, and good luck on your interesting project.

_mike

ThreeFN
Pre-kindergarten
Pre-kindergarten
Posts: 8
Joined: Tue Sep 08, 2009 8:15 am

Re: Daft Punk Helmet Project by ThreeFN

Post by ThreeFN » Wed Oct 21, 2009 2:09 am

mshaub wrote:Your work is very impressive, and I'm trying to learn by following your examples. I had a heck of a time getting your program installed on my Rainbowduino, and ended up using a USB ISP programmer from Adafruit. That seemed to work, but I cannot compile the SeeedMaster2.pde you included in my Arduino 17 (running on an intel mac osx10.5).

Specifically, I'm getting:
error: invalid types 'unsigned char[int]' for array subscript

and the IDE has highlighted this line:
RainbowCMD[0][0]='F';

Honestly, I'm feeling way over my head and it's quite possible that I've made a bone-headed mistake. Please let me know if you have any ideas about the issue here. Thank you, and good luck on your interesting project.

_mike
Sorry about the ridiculous delay in my reply, apparently I don't have email updates set up.

For starters, make sure that you use the I2C speed hack, it will make a large display work faster/better. And make sure that you do this hack and then update(compile/upload) both your rainbowduino and the arduino you're using for a master. If you change only one, they won't be able to communicated very well/at all. To program the rainbow you do need a uart board or an ISP. If you could only able to use the ISP, I sorry but I don't know what the problem could be. I use the Uart from Seeed and it loaded the code just fine. The code included for loading to the Rainbowduino is the EXACT same code I use in all of my videos and hasn't been modified since about mid summer.

And second, apparently I'm clueless. I included a much older version of the file in my code submission by mistake. I was trying to update the old beta so that I didn't drag over superfluous code from my personal project, but apparently didn't finish it on the file I submitted. I also apparently never tried to compile the file either. No wonder no one in the polls likes me ;)

I found this version which does compile fine, but I can't test it at the moment unfortunately, since I'm away from my rig.

Code: Select all

#include <Wire.h>
//=====================================================================
//Rainbowduino Seeedmaster V2
//Originally provided by Seeed Studio
//Modified by Scott C.
//=====================================================================

//=====================================================================
//This is master-side code that contains some prebuilt functions for
//sending commands to a Rainbowduino running V2.7 or later
//The original commands have not been changed, so this code
//could theoretically send commands to V2, but only 'R' commands.  Both
//the master and slave code have been modified to support multiple data
//transmission session over the IIC communications bus, due to the Wire
//Library limitation of only 32 bytes per transmission.  This is most
//evident in changes to the function SendCMD.
//
//In addition a few new command types have been added.  A command 
//starting with 'F' sends color data for each of the 64 leds set up
//similiar to the buffer on the Rainbowduino (byte per two leds).  This
//allows for complex animations to be calculated on the master, and
//then the "frame" of data for all leds to be sent to the slave
//Rainbowduino.  This is particularly helpful for animations involving
//more than one Rainbowduino comprising a "screen."
//
//There are also three other command types dubbed "chromatics."
//Monochromatic (one color), dichromatic (two), and trichromatic 
//(three) frames can be sent with commands starting with 'M','D', and
//'T' respectively.  Each of these commands consists of the relavent
//number of RGB values, followed by 8 bytes per unique color.  Each
//byte in one of these sets represents a line on the display, 1 meaning
//the led is on, 0 off.  These commands are much smaller, and transmit
//in the first transmission session so they are much faster, especially
//important for large screens with many Rainbowduinos.
//
//It is highly recommended for 'F' commands and large screens to modify
//the Wire library for the faster 400KHz transmission.
//Info on how to do this can be found here:
//http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1241668644/0
//
//VERY BIG NOTE: The functions outlined below, specifically ShowFrame,
//can very quickly eat up your available SRAM.  I developed this on the
//older 168 chip, and kept a very keen eye for minimizing SRAM usage
//with unsigned char datatypes whereever possible.  However, a single
//input array of the kind in ShowFrame is 96 bytes, 1/10th of the 1K
//SRAM is gone right there.  the 168 has made way for the 328, but I
//recommend becoming familiar with PROGMEM and rewrite your functions
//to extract data from flash memory, rather than defining the data like
//normal variables.  Not having enough SRAM shows up as very bizarre 
//errors that are difficult to track down and fix, and you will not
//be notified at compile time.  Moving images and data to PROGMEM 
//allows you to see how much storage you are using at compile time, 
//since PROGMEM variables are stored in flash and become part of the 
//sketch size in flash memory.  Overstepping the available flash memory 
//will throw an error when compiled/uploaded.
//
//The screen I rewrote this code for is 6 Rainbowduinos, and the master 
//stores over 30 images using chromatics and a handful of full RGB 
//images and is only 7.5K in flash memory.  Some examples of this can
//be found by searching Youtube for user ThreeFN.
//======================================================================
#define waitingcmd 0x00
#define morecmd 0x10
#define processing 0x20
#define checking  0x30

#define transcmd 0xA0
#define checkslavestate 0xB0
#define slavedone 0xC0

unsigned char State= transcmd;
unsigned char slavestate= waitingcmd;

unsigned char RainbowCMD[4][32];
unsigned long timeout;


void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
  for(int i;i<4;i++){
    for(int j;j<32;j++){
      RainbowCMD[i][j]=0x00;
    }
  }
}

void loop()
{
  int i;
  for (i=0;i<5;i++)
  {
    ShowImage(4,i,0);
    delay(500);
  }

  int test;
  unsigned char shift;
  for(test='0';test<'9';test++)
  {
    for(shift=0;shift<16;shift++){
      ShowChar(4,test,15,0,0,shift);
      delay(100);
    }
  }

  for(test='A';test<'Z';test++)
  {
    for(shift=0;shift<16;shift++){
      ShowChar(4,test,0,15,0,shift);
      delay(500);
    }
  }

  for(test='a';test<'z';test++)
  {
    for(shift=0;shift<16;shift++){
      ShowChar(4,test,0,0,15,shift);
      delay(100);
    }
  }

}


//--------------------------------------------------------------------------
//Name:ShowColor
//function: Send a conmand to Rainbowduino for showing a color
//parameter: Address: rainbowduino IIC address
//                 red,green,blue:  the color RGB    
//----------------------------------------------------------------------------
void ShowColor(int Address,unsigned char red , unsigned char green, unsigned char blue)
{
  RainbowCMD[0][0]='R';
  RainbowCMD[0][1]=0x03;
  RainbowCMD[0][2]=red;
  RainbowCMD[0][3]=((green<<4)|(blue));

  SendCMD(Address);
}


//--------------------------------------------------------------------------
//Name:ShowImage
//function: Send a conmand to Rainbowduino for showing a picture which was pre-set in Rainbowduino Flash
//parameter: Address: rainbowduino IIC address
//                 number:  the pre-set picture position
//                 shift: the picture  shift bit for display
//----------------------------------------------------------------------------
void ShowImage(int Address, unsigned char number,unsigned char shift)
{
  RainbowCMD[0][0]='R';
  RainbowCMD[0][1]=0x01;
  RainbowCMD[0][2]=(shift<<4);
  RainbowCMD[0][4]=number;

  SendCMD(Address);
}


//--------------------------------------------------------------------------
//Name:ShowChar
//function: Send a conmand to Rainbowduino for showing a color
//parameter: Address: rainbowduino IIC address
//                 red,green,blue:  the color RGB  
//                 shift: the picture  shift bit for display
//                 ASCII:the char or Number want to show
//----------------------------------------------------------------------------
void ShowChar(int  Address,unsigned char ASCII,unsigned char red, unsigned char blue ,unsigned char green,unsigned char shift)
{
  RainbowCMD[0][0]='R';
  RainbowCMD[0][1]=0x02;
  RainbowCMD[0][2]=((shift<<4)|(red));
  RainbowCMD[0][3]=((green<<4)|(blue));
  RainbowCMD[0][4]=ASCII;

  SendCMD(Address);
}


//---------------------------------------------------------------------------
//Name:ShowFrame
//function: Send a frame to rainbowduino for displaying
//parameter: Address: rainbowduino IIC address
//           Frame: The array to be sent formatted as [color][row][dots]  
//           *Note: The 4 bit value for two leds brightnesses is stored as a 
//                  byte, so each dots is two leds side by side
//           *Eg: dots = 0xF3 would be first led at max brightness and second 
//                at 3.
//----------------------------------------------------------------------------
void ShowFrame(unsigned char  Address, unsigned char Frame[3][8][4])
{
  unsigned char color,row,dots;

  RainbowCMD[0][0]='F';
  for (color=0;color<3;color++){
    for (row=0;row<8;row++){
      for (dots=0;dots<4;dots++){
        RainbowCMD[color+1][(4*row)+dots]=Frame[color][row][dots];
      }
    }
  }

  SendCMD(Address);
}
//---------------------------------------------------------------------------
//Name:ShowMono
//function: Send a monochromatic frame to rainbowduino for displaying
//parameter: Address: rainbowduino IIC address
//           red,green,blue: the color to show when a led is on, 0-15 per color
//           Frame: The array to be sent formatted as [row]
//           *Note: the byte of each row is one bit per led, and where it's 
//                  on or off (1 or 0), cannot be written with B10101010
//----------------------------------------------------------------------------
void ShowMono(unsigned char  Address, unsigned char red, unsigned char green, unsigned char blue, unsigned char Frame[8])
{
  unsigned char row;

  RainbowCMD[0][0]='M';
  RainbowCMD[0][1]=(red&0x0F);
  RainbowCMD[0][2]=((green&0x0F)<<4)|(blue&0x0F);
  for (row=0;row<8;row++){
    RainbowCMD[0][row+3]=Frame[row];
  }

  SendCMD(Address);
}

//---------------------------------------------------------------------------
//Name:ShowDich
//function: Send a dichromatic frame to rainbowduino for displaying
//parameter: Address: rainbowduino IIC address
//           red1,green1,blue1,red2,green2,blue2: the color to show when a led is on
//           for each of two colors, 0-15
//           *Note: a 1 color will overwrite a 2 color occupying the same led
//                  this can be useful for just adding on another layer of color to
//                  an existing image
//           Frame: The array to be sent formatted as [color][row]
//           *Note: the byte of each row is one bit per led, and where it's 
//                  on or off (1 or 0), cannot be written with B10101010
//----------------------------------------------------------------------------
void ShowDich(unsigned char  Address, unsigned char red1, unsigned char green1, unsigned char blue1, unsigned char red2, unsigned char green2, unsigned char blue2, unsigned char Frame[2][8])
{
  unsigned char color,row;

  RainbowCMD[0][0]='D';
  RainbowCMD[0][1]=((red1&0x0F)<<4)|(green1&0x0F);
  RainbowCMD[0][2]=((blue1&0x0F)<<4)|(red2&0x0F);
  RainbowCMD[0][3]=((green2&0x0F)<<4)|(blue2&0x0F);

  for (color=0;color<2;color++){
    for (row=0;row<8;row++){
      RainbowCMD[0][(color*8)+row+4]=Frame[color][row];
    }
  }
  SendCMD(Address);
}


//---------------------------------------------------------------------------
//Name:ShowTrich
//function: Send a trichromatic frame to rainbowduino for displaying
//parameter: Address: rainbowduino IIC address
//           red1,green1,blue1,red2,green2,blue2,red3,green3,blue3: the color 
//               to show when a led is on for each of two colors, 0-15
//           *Note: a 1 color will overwrite a 2 color, etc occupying the same led
//                  this can be useful for just adding on another layer of color to
//                  an existing image, 1 > 2 > 3
//           Frame: The array to be sent formatted as [color][row]
//           *Note: the byte of each row is one bit per led, and where it's 
//                  on or off (1 or 0), cannot be written with B10101010
//----------------------------------------------------------------------------
void ShowTrich(unsigned char  Address, unsigned char red1, unsigned char green1, unsigned char blue1, unsigned char red2, unsigned char green2, unsigned char blue2, unsigned char red3, unsigned char green3, unsigned char blue3, unsigned char Frame[3][8])
{
  unsigned char color,row;

  RainbowCMD[0][0]='T';
  RainbowCMD[0][1]=((red1&0x0F)<<4)|(green1&0x0F);
  RainbowCMD[0][2]=((blue1&0x0F)<<4)|(red2&0x0F);
  RainbowCMD[0][3]=((green2&0x0F)<<4)|(blue2&0x0F);
  RainbowCMD[0][4]=(red3&0x0F);
  RainbowCMD[0][5]=((green3&0x0F)<<4)|(blue3&0x0F);

  for (color=0;color<3;color++){
    for (row=0;row<8;row++){
      RainbowCMD[0][(color*8)+row+6]=Frame[color][row];
    }
  }
  SendCMD(Address);
}


//--------------------------------------------------------------------------
//Name:SendCMD
//function: Send a 4 byte cmd or 96 byte frame, prefaced by cmd type byte
//parameter: Add: Address of Rainbow to send command to
//                Note: DO NOT CHANGE FROM TYPE int TO TYPE unsigned char
//                      ALL OTHERS MAY BE unsigned char
//----------------------------------------------------------------------------
void SendCMD(int  Add)
{   
  unsigned char OK=0;
  unsigned char i;
  char transnumber;
  unsigned char startnumber=0;
  unsigned char cmdsession=0;

  while(!OK)  //cycle until slave transmits it's done
  {                          
    switch (State)
    { 	

    case transcmd:  //transmit up to 32 bytes at a time
      switch (RainbowCMD[0][0]){  //if the data is a command
      case 'R':
        transnumber =5;  //only transmit the 5 bytes
        break;

      case 'T':
        transnumber=30;
        break;  

      case 'D':
        transnumber=20;
        break;

      case 'M':
        transnumber=11;
        break;

      case 'F':  //if it's a frame
        if (cmdsession==0) transnumber=1;  //the first session contains only the command byte
        else transnumber= 32;
        break;
      }


      Wire.beginTransmission(Add);  //start
      for (i=0;i<transnumber;i++){
        Wire.send(RainbowCMD[cmdsession][i]);
      }
      Wire.endTransmission();
      delayMicroseconds(230);

      State=checkslavestate;
      break;

    case checkslavestate:

      Wire.requestFrom(Add,1);   
      if (Wire.available()>0) 
        slavestate=Wire.receive();    
      else {
        slavestate =0xFF;
        timeout++;
      }

      if ((slavestate&0xF0)==morecmd){
        cmdsession=(slavestate&0x0F);
        State=transcmd;
      }
      else if ((slavestate==processing)||(slavestate==checking)) State=slavedone;
      else State=transcmd;


      if (timeout>5000)  //time out occurs
      {
        timeout=0;  //reset timout
        State=transcmd;  //trans failure, resend
      }

      //delayMicroseconds(10);
      break;


    case slavedone:  //trans done
      OK=1;  //trans confirmed and OK, will exit while loop
      State=transcmd;  //reset state for next call of cmd
      break;


    default:
      State=transcmd;
      break;

    }
  }
}
Hopefully that will get you started, or at least "Hello World"ing.

mshaub
Pre-kindergarten
Pre-kindergarten
Posts: 12
Joined: Mon Oct 12, 2009 2:46 pm

Re: Daft Punk Helmet Project by ThreeFN

Post by mshaub » Thu Oct 22, 2009 2:07 pm

I've gotten that latest code to work. Thank you so much. This is running much brighter than other examples I've tried, not sure if that's got more to do with the library or the i2c hack. Now that I've got your test patterns running I'll have to get to work making it do my bidding. Thanks again.

_mike S.

ThreeFN
Pre-kindergarten
Pre-kindergarten
Posts: 8
Joined: Tue Sep 08, 2009 8:15 am

Re: Daft Punk Helmet Project by ThreeFN

Post by ThreeFN » Thu Oct 22, 2009 10:16 pm

mshaub wrote:I've gotten that latest code to work. Thank you so much. This is running much brighter than other examples I've tried, not sure if that's got more to do with the library or the i2c hack. Now that I've got your test patterns running I'll have to get to work making it do my bidding. Thanks again.

_mike S.
You have the be careful, the "brightness" can sometimes be an indicator of a problem. A common error when you interrupt a communication session (for example programming the master while it was in the middle of a transmission) will be that the first 5 LED's or so of the first row will light up very bright blues and purples. I generally power cycle the system immediately in case there is any possibility for damage or increased wear. Always turn your rainbows on first or have a delay in the setup of your master arduino to allow for rainbow startup, this will prevent communication problems.

One thing to note is that the led matrix itself does have very high brightness rating. This is done because it is expected that people will use Persistence Of Vision (POV) and duty cycling in order to reduce circuit complexity. Theoretically, with 8 col, the LED is operating at 1/8th brightness even at full.

The increased subjective brightness might be due to my code. I did try and make sure to keep the base code that actually does the ON/OFF as it was well written and efficient. Essentially, all the rainbowduino has to do most of the time is just copy/paste from the incoming I2C buffer to the display buffer, or something similar. I always kept an eye on efficiency of the code and used the "quickest" method I could think of. Granted I'm not a programmer by trade so there is probably plenty of room for improvement.

Most of the real hardcore processing that generates the stuff for the display is all done by the master, which may relieve congestion on the rainbow, increasing the time dedicated to doing the POV cycle. Having not read any of the other project's code, I imagine more of it is done locally on the rainbow, consuming processing cycles and thus reducing brightness.

mshaub
Pre-kindergarten
Pre-kindergarten
Posts: 12
Joined: Mon Oct 12, 2009 2:46 pm

Re: Daft Punk Helmet Project by ThreeFN

Post by mshaub » Fri Oct 23, 2009 11:34 pm

I've read your instructions .doc and looked through the code, but I'm still struggling to make use of it. I'm having trouble figuring out exactly how to format the commands for a ShowFrame and ShowTrich on the SeeedMaster sketch.

I was hoping you had some test code laying around that I could throw in the loop() and see how it works. The sample ShowChar and ShowImage that you included were great for me to learn about.

ShowFrame and ShowTrich seem like they'll be overkill, as the effect I'm going for at the moment is very similar to the Raindrops game that was posted in the Carnival contest. His code is running all the frame drawing on the Rainbowduino, getting a new 1st line in from the Master Arduino and just shifting previous rows down on each redraw. That seems much more efficient than drawing the whole frame on the Master side and sending it through, but obviously much more limited (the difference between an LED stock ticker and an LED video screen).

Sorry that I haven't been able to make much use of your instruction manual, just not that good with the coding at this point. Thanks for any (more) help.

ThreeFN
Pre-kindergarten
Pre-kindergarten
Posts: 8
Joined: Tue Sep 08, 2009 8:15 am

Re: Daft Punk Helmet Project by ThreeFN

Post by ThreeFN » Sat Oct 24, 2009 1:01 am

mshaub wrote:I've read your instructions .doc and looked through the code, but I'm still struggling to make use of it. I'm having trouble figuring out exactly how to format the commands for a ShowFrame and ShowTrich on the SeeedMaster sketch.

I was hoping you had some test code laying around that I could throw in the loop() and see how it works. The sample ShowChar and ShowImage that you included were great for me to learn about.

ShowFrame and ShowTrich seem like they'll be overkill, as the effect I'm going for at the moment is very similar to the Raindrops game that was posted in the Carnival contest. His code is running all the frame drawing on the Rainbowduino, getting a new 1st line in from the Master Arduino and just shifting previous rows down on each redraw. That seems much more efficient than drawing the whole frame on the Master side and sending it through, but obviously much more limited (the difference between an LED stock ticker and an LED video screen).

Sorry that I haven't been able to make much use of your instruction manual, just not that good with the coding at this point. Thanks for any (more) help.
Yah, my code is designed to be "overkill" with the master sending full frames every time there is a refresh. That's because while a lot of my animations do use shifting values (fireplace is a cool example of shifting and decaying), there is no requirement to do so in the code. I could do a spinning pinwheel of color (coding difficulties aside) that would not shift in a linear fashion because the master does all the shifting. I wanted a lot of flexibility, the actual rainbowduino code is just like a "TV" that I can plug differ "devices" into (like you would plug your Wii or VCR into your TV) where the devices are really code running on the master. Also, with a large display made up of 6 rainbowduinos, it was easier to have the master decide which display got which commands rather than the rainbows talking amongst themselves.

Here is an example of what you should do if you just wanted to send a single frame every time the loop repeated using a trich command

Code: Select all

byte red1=15,green1=15,blue1=15;  //blueish white first color
byte red2=0,green2=0,blue2=0;  //all dark (black) second color
byte red3=15,green3=3,blue3=0;  //yellow third color

RainbowCMD[0][0]='T';  //this is the starting byte that tells the rainbow what command type is being sent

RainbowCMD[0][1]=((red1&0x0F)<<4)|(green1&0x0F);  //first color red and green sent as a single byte, that's why the red1 is bitwise shift 4 places left to occupy the first 4 bits before the two are bitwise OR'd together
RainbowCMD[0][2]=((blue1&0x0F)<<4)|(red2&0x0F);  //the bitwise AND with hex 0x0F is just to make sure the value only occupies the lowest 4 bits before it is bitwise OR'd
RainbowCMD[0][3]=((green2&0x0F)<<4)|(blue2&0x0F);
RainbowCMD[0][4]=(red3&0x0F);  //since there are an odd number of of color variables, this one gets its own byte, lucky him
RainbowCMD[0][5]=((green3&0x0F)<<4)|(blue3&0x0F);

//first color populating
for(byte i=0;i<8;i++){
  RainbowCMD[0][i+6]=0xC0;  //first two leds of each row will be white
}
//second color populating
for(byte i=0;i<8;i++){
  RainbowCMD[0][i+14]=0x30;  //third and forth led of each row will be black
}
//third color population
for(byte i=0;i<8;i++){
  RainbwoCMD[0][i+22]=0x0F;  //the last 4 leds of each row will all be yellow
}

SendCMD();  //sends the command from the buffer (RainbowCMD) we just populated

delay(1000); //wait a second since we're really just resending the same frame, no sense doing that every cycle with no pause
I'm at work so sorry can't be more help just yet, might get you started and seeing the patern. Use the second table from my manual above, that should help you understand how all the bits and bytes are layed out. You need to be comfortable understanding bitwise operators and thinking/understanding hex values since a lot of my stuff involves bit and byte manipulation in the name of efficiency. Eventually, it's also easier to use and understand when you want to turn a bunch of stuff on and off in multiples of 8.

mshaub
Pre-kindergarten
Pre-kindergarten
Posts: 12
Joined: Mon Oct 12, 2009 2:46 pm

Re: Daft Punk Helmet Project by ThreeFN

Post by mshaub » Sat Oct 24, 2009 2:41 am

Yes, I see a lot more of how all the data is packed so densely and am starting to get it. Unfortunately (aside from a misspelling of "Rainbwo" which I did catch, the compiling complains of another error: "too few arguments to function 'void SendCMD(int)' " I'm guessing that no where did I specify the address of the Rainbowduino (4) but I'm not sure where that would need to be added, or if that's the error.

I appreciate your help and look forward to a little more help on this one when you can. Thanks!

ThreeFN
Pre-kindergarten
Pre-kindergarten
Posts: 8
Joined: Tue Sep 08, 2009 8:15 am

Re: Daft Punk Helmet Project by ThreeFN

Post by ThreeFN » Sat Oct 24, 2009 2:58 am

mshaub wrote:Yes, I see a lot more of how all the data is packed so densely and am starting to get it. Unfortunately (aside from a misspelling of "Rainbwo" which I did catch, the compiling complains of another error: "too few arguments to function 'void SendCMD(int)' " I'm guessing that no where did I specify the address of the Rainbowduino (4) but I'm not sure where that would need to be added, or if that's the error.

I appreciate your help and look forward to a little more help on this one when you can. Thanks!
Whoops, yes, the address needs to be specified (my bad, i thought about this while I was writing but goofed and didn't put it in). The default address I believe is 4, but I haven't looked at the rainbowduino code in a while. I know it will be something between 4 and 9, since those are the only addresses I've ever used. If it's not 4, it's probably 9 in the rainbowduino firmware.

In case you hadn't noticed, I'm horrible at coding mostly due to errors like that (misspell, forgotten variables). My programming Prof's always said I knew fairly good theory but just couldn't type worth a darn.

Post Reply