TRON Legacy - Identity Disc: Custom with Lights and Sounds

Good selection of parts Zook, I hope they work out as I may use this setup for the 2.0 disc (though I'm looking into wireless on/off switching so I don't have to have any physical buttons).

Have you thought about including an impact switch (think lightsabers) for activating the clash an swing sounds? They are cheap as chips on ebay, though I got mine from the spinmaster disc I modded.
 
Good selection of parts Zook, I hope they work out as I may use this setup for the 2.0 disc (though I'm looking into wireless on/off switching so I don't have to have any physical buttons).

Have you thought about including an impact switch (think lightsabers) for activating the clash an swing sounds? They are cheap as chips on ebay, though I got mine from the spinmaster disc I modded.

Canobi, can you post a link to an impact chip? I have a little compass & accelerometer breakout chip. It might be able to do the type of effect your describing.

Wireless switch would be good. I just realized today, I'm going to need 2 switches actually. One On/Off to control power to the arduino from the batteries, the second momentary switch to control modes. I figured I could hide the momentary switch behind the trapezoidal bevel panel.

Any other thoughts on cool switch options?

I'm other news been working with the Arduino Micro for a few days. I've been able to Control simple LEDs, Switch through multiple modes, Got some simple tones playing, and controlled the motor. I've not played with the LED strips, sound module, amp, or compass & accelerometer yet.
 
No prob.


They are also known as a vibration sensor/switch. The one I have is a spring in a tube with one being + and the other -. When it's hit or shaken the spring makes contact with the tube wall completing the circuit. As such, you can treat it like a normal monentary push button switch when writing it in your arduino sketch :thumbsup

This is the module version

http://pages.ebay.com/link/?nav=item.view&id=111220273402


This is just the switch on its own

http://pages.ebay.com/link/?nav=item.view&id=350940273258


I bought the accelerometer to activate the throw sounds, though mine doesn't have the compass function like yours. I'm not bothered though as it only cost me £0.99 and I haven't even managed to get the LED to blink on the arduino yet (I think i found a tiny pair of components touching on one end so I'm taking it in to work to fix it monday).
 
Canobi, Thanks for link to the switches. I'm not sure they'll work well with the Sound Chip I have. It has a pretty bad delay between tracks. In order to resolve this I'm going to make one long first track, Power Up and Loop. And then Just a second power down track.

If I can find a way to mix sound better, or reduce the delay then maybe the vibration sensor will work.

Here's a video of the Power Up as Track 1, Loop as Track 2, and a very buggy action at the moment to the Track 3 power down.


I might try another speaker to get more watts out and louder sound... but for now it sort of works.

However as you can see in the video, only get full power to my speaker when I hold the momentary switch down. Can I fix this? What is wrong with my circuit? If I pull the resistor from the button, full power/sound hits the speaker, however the button doesn't work.

Also planning to make the trapezoidal switch sort of like a push button rocker. On end will power on, other end cycle though modes

-Z
 
Last edited by a moderator:
Hmm, it seems like the amp isn't getting enough power. It's possible that as you hold the button down, it gets a better connection and therefor more juice so maybe give the amp it's own supply and see if that helps.

The vibration switch should work just like your button, just add de-bounce code.

Was there anything in the data sheet for the player regarding time delay on playback?
 
The 4xAAs it looks like you are powering the circuit with probably just don't supply the kind of power that the amp, trinket and card reader need so you will need to power it with something else. Maybe consider getting a DC 3.3v wall adapter with a current rating of around 1 amp or so, that should power everything nicely, excluding the LEDs. When you start powering the neopixels make sure that you don't attach their power lines to the trinket pins, only connect the data line to the trinket. The power lines should be connected directly to the power supply which should be able to source ~3.5 amps per meter @ 5v, otherwise you would fry the arduino chip as it can only source ~20mA from its pins. Just a word of warning, I've had a couple of close calls with short circuits and over current draw.
 
The 4xAAs it looks like you are powering the circuit with probably just don't supply the kind of power that the amp, trinket and card reader need so you will need to power it with something else. Maybe consider getting a DC 3.3v wall adapter with a current rating of around 1 amp or so, that should power everything nicely, excluding the LEDs. When you start powering the neopixels make sure that you don't attach their power lines to the trinket pins, only connect the data line to the trinket. The power lines should be connected directly to the power supply which should be able to source ~3.5 amps per meter @ 5v, otherwise you would fry the arduino chip as it can only source ~20mA from its pins. Just a word of warning, I've had a couple of close calls with short circuits and over current draw.

Having a wall amp would run things now, but the goal is to have the prop un-tethered. Its looking like I'm going to run out space for batteries. The amp may end up being a nice to have. The Sound Module does okay without it. I need to try everything with the final light configuration to see how it performs.

I picked up a multimeter, any tips on how to use it to analyze my project would be appreciated.

-Z
 
Sorry, I didn't mean to suggest that it was going to be tethered, I have just found that having a dedicated wall power supply to be a really nice thing to have. It means not having to worry much about having enough amperage and there isn't a chance that the power supply will run out of power with use as would happen with a battery. Once you get all the other parts working then add in the batteries, it saves a bit of hassle. Also, use LiPo batteries if you can and if not I think your next best choice would be some high discharge NiMH packs. A 2 cell LiPo runs at 7.4v so you will need two regulators, 5v and 3.3v, of some kind, either "linear regulators" or a much more efficient, but more costly, "switching regulators." If you use NiMH you might be able to get away with a 4-5 cell pack which would deliver 4.8v or 6v respectively and then only have to use one regulator to drop the voltage for the 3.3v stuff, and then just directly connecting the Neopixels, though 6v is their limit so you would have to be careful.
 
Classic breadboard noob mistake! I think the button was driving some of the Gain pins on the amp. Its working okay now.

I need a full-size breadboard...

With the sound module sort of figured out, I brute force programmed the inner ring lights. not very elegant code but works!


Outer Ring is going to be the tougher of the two rings
 
Last edited by a moderator:
Outer Ring Light Test:


I'll scrub and annotate my arduino code in end. If folks are interested in sooner I can start posting rough chunks for those playing along...

Time to play with the compass and see if I can make the disc react a bit in light and sound to movement and then start to put everything together.

And then some more 3D modeling.

-Z
 
Last edited by a moderator:
Yes please :)


That looks fantastic zook, your disc is going to absolutely rock :thumbsup
 
Last edited:
zookone,

Quite a cool coding feat, and it's really cool that you are considering how to make the disc react to movement. Once you conquer that, have you given any thought to adding software that would allow you to throw the disc, and it uses GPS to come back to you? Or get real sophisticated and have it calculate angles and routes while in flight so that it can hit multiple walls before returning?

Another idea that wouldn't involve so much software would be some kind of retractable hidden blade on the outer band so that it can cut metal (and other stuff like in the film). I mean, you are trying to get this as authentic as possible, right?

And finally, consider little helicopter blades and gyroscopes inside, so that you could hold it over your head, and have it just "float up and away". This combined with a high intensity LED spotlight shining down as it floats away would make a really cool addition as well.

Keep the videos coming! ;) ;) ;)
 
zookone,

Quite a cool coding feat, and it's really cool that you are considering how to make the disc react to movement. Once you conquer that, have you given any thought to adding software that would allow you to throw the disc, and it uses GPS to come back to you? Or get real sophisticated and have it calculate angles and routes while in flight so that it can hit multiple walls before returning?

Another idea that wouldn't involve so much software would be some kind of retractable hidden blade on the outer band so that it can cut metal (and other stuff like in the film). I mean, you are trying to get this as authentic as possible, right?

And finally, consider little helicopter blades and gyroscopes inside, so that you could hold it over your head, and have it just "float up and away". This combined with a high intensity LED spotlight shining down as it floats away would make a really cool addition as well.

Keep the videos coming! ;) ;) ;)

Ha ha, no but I am going to make 2 blade options that you can swap out though, flush blade & activated blade.

I'm going to hold the disc together with magnets so you can split it easily and swap blade, coding, batteries, etc.

Your other ideas are awesome, however I want to focus on a primitive rod baton that will make digital lightcycle below me when I jump in the air first. ;)

I was thinking about cycling 4 haptic motors in loop pattern around the disc. This might mimic the feeling of a gyro of sorts, i just have (1) motor right now thought. I'll have to see if I have enough output pins on the Micro, and the motors may really eat battery up, not sure.
 
Greetings Programs!

I've got everything working together and on batteries! Below is a video and my half annotated Arduino code to date. The code is hardly optimized if anyone has any ideas to improve it, that would be greatly appreciated. Total brute force, and scrapped to together.


Canobi Thanks a ton for the sounds. I'm going to send you back my modifications here shortly. I added the whine to the "On", & extra ambiance, also cleaned up the Disc Loop to remove a sound spike/hop, the Off I made no changes to that I remember. I ended up making a long ON with a 3 min blade loop. I could not get the short loops with out long delay.

It seems 28 inner ring lights was too much for the batteries to handle. I'm going to have to cut them apart, and re-solder a custom 16 light strip. one light for each inner ring segment.

I've got the haptic motor mapped to the compass. The disc vibrates when the blade is on and when you bring the disc up level to the ground, it will amps up the vibration.

Amp was not needed, I pulled it out and will use on another project in the future.

I'll have a Fritzing schematic soon - I'm using Fritzing to keep track of my work and is super helpful!

I have some resistors, a diode and transistor in the breadboard. What is this best way to solder and work with these after I move off the breadboard?

Arduino Code:

Code:
/*


Rough working version of TRON Legacy Identiy Disc Code 
Custom Disc Prop


by zook_one //:LDSO http://www.ldso.net


FYI there is still a lot of junk code in here to pull out...


Big thanks to Adafruit and rest of the Arduino Community for sharing so much information and helpful code examples!
Thanks to Canobi for help in sourcing SoundFX clips
Sample video of this code in action can be viewed here: http://youtu.be/8lgh8ytL7jk


IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
and minimize distance between Arduino and first pixel.  Avoid connecting
on a live circuit...if you must, connect GND first.
*/




#include <Adafruit_NeoPixel.h>     //needed for the NeoPixel Strips


#include <Wire.h>                  //needed for the motor control
#include <Adafruit_Sensor.h>       //needed for the motor control Unified Sensor Libary for the compass/accel
#include <Adafruit_LSM303_U.h>     //needed for the motor control Libary for the compass/accel
#include <WTV20SDBreakout.h>       //library for the sound module


/* Assign a unique ID to this sensor at the same time */
Adafruit_LSM303_Mag_Unified mag = Adafruit_LSM303_Mag_Unified(12345);


// constants won't change. They're used here to 
// set pin numbers:




int busyPin = 4;  // The pin number of the sound module busy pin.
int dataPin = 5;  // The pin number of the sound module data pin.
int clockPin = 6;  // The pin number of the sound module clock pin.
int resetPin = 7;  // The pin number of the sound module reset pin.


int motorPin = 10; // Pin out for the small vibrating motor


int ledPin = 13; //Pin out for (4) four Disc Read Mode LEDs


#define PIN_inner 8  // the digital pin the data line of the inner ring NeoPixel is connected to
#define PIN_outer 9  // the digital pin the data line of the outer blade NeoPixel is connected to


// variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int modeCounter = 0;          // counter for the number of button presses
int buttonState = 0;         // variable for reading the disc mode pushbutton status
int lastButtonState = 0;     // previous state of the button


volatile int state = LOW; //Interrupt Code State


// Modifed NeoPixel sample for the holiday craft project


// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip_inner = Adafruit_NeoPixel(16, PIN_inner, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip_outer = Adafruit_NeoPixel(38, PIN_outer, NEO_GRB + NEO_KHZ800);


#define hi_cyan strip_outer.Color(25, 200, 200) //defines color of outer ring (R,G,B), Brightness) from 0 to 255
#define hi_white strip_outer.Color(210, 210, 210) //defines color of outer ring "flashes" (R,G,B), Brightness) from 0 to 255


WTV20SDBreakout WTV20SDBreakout(resetPin,clockPin,dataPin,busyPin)  ; //sound module setup


void setup() {
  
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  
  // initialize the motor pin as an output: 
  pinMode(motorPin, OUTPUT);
  
  attachInterrupt(2, my_interrupt_handler, FALLING);
  
  //Initializes the sound module.
  WTV20SDBreakout.reset();
  WTV20SDBreakout.volume(3); //sets the volume for the sound module
  
  strip_inner.begin();
  strip_inner.show(); // Initialize all pixels to 'off'
  
  strip_outer.begin();
  strip_outer.show(); // Initialize all pixels to 'off'
}


void loop() {
  
    int mode = modeCounter;
      
    switch (mode) {
    case 0:    // power up disc
      Serial.print("mode number:  ");
      Serial.println(modeCounter);
      innerRing(strip_inner.Color( 110, 155, 150)); //defines color of inner ring (R,G,B), Brightness) from 0 to 255
      modeCounter++;
      break;
      
    case 1:    // Resting On Mode
      Serial.print("mode number:  ");
      Serial.println(modeCounter);
      analogWrite(motorPin, 0);
      strip_outer.show(); // Initialize all pixels to 'off'
      break;
      
    case 2:    // initial blade activation - push directly to loop effect- case 2
      Serial.print("mode number:  ");
      Serial.println(modeCounter);
      WTV20SDBreakout.asyncPlayVoice(0); //Plays audio file number 1
      colorWipe_On(hi_cyan, 10); // Cyan
            modeCounter++; 
      //WTV20SDBreakout.asyncPlayVoice(1);
      break;
      
    case 3:    // blade loop effect
      Serial.print("mode number:  ");
      Serial.println(modeCounter);
      
      //WTV20SDBreakout.asyncPlayVoice(1); //Plays audio file number 1
      //delay(5000);
      theaterChase(strip_outer.Color(  25, 200, 200), 10); // Cyan
      //strip_outer.show(); // Initialize all pixels to 'off'
      
      mag.begin();
      sensors_event_t event; 
      mag.getEvent(&event);
 
        /* Display the results (magnetic vector values are in micro-Tesla (uT)) */
        Serial.print("X: "); Serial.print(event.magnetic.x); Serial.print("  ");
        Serial.print("Y: "); Serial.print(event.magnetic.y); Serial.print("  ");
        Serial.print("Z: "); Serial.print(event.magnetic.z); Serial.print("  ");Serial.println("uT");
        //delay(100);
  
        if (event.magnetic.z <= 0)
        {
            analogWrite(motorPin, (event.magnetic.z *-2));
        }
        else
        {
            analogWrite(motorPin, (event.magnetic.z * 2));
        }
                          
      break;
      
      case 4:    // blade power down
      Serial.print("mode number:  ");
      Serial.println(modeCounter);
      modeCounter++;
      WTV20SDBreakout.asyncPlayVoice(2); //Plays audio file number 1
      colorWipe(hi_white, 2); // White 
      colorWipe(hi_cyan, 1); // Cyan
      reverseColorWipe(strip_outer.Color(0, 0, 0), 100); 
      break;
  } 
  delay(1);        // delay in between reads for stability
}
 
// fade_up - fade up to the given color
//void fade_up(int num_steps, int wait, int R, int G, int B) {
   //uint16_t i, j;
   
   //for (i=0; i<num_steps; i++) {
      //for(j=0; j<strip.numPixels(); j++) {
         //strip.setPixelColor(j, strip.Color(R * i / num_steps, G * i / num_steps, B * i / num_steps));
      //}  
   //strip.show();
   //delay(wait);
   //}  
//} // fade_up




void my_interrupt_handler()
{
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 200ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > 200)
  {
      digitalWrite(ledPin, state);  
      modeCounter++; 
      
      if (modeCounter >= 3){
      //WTV20SDBreakout.pauseVoice();
      //delay (10);
      //WTV20SDBreakout.asyncPlayVoice(2); //Plays audio file number 2
      //colorWipe(hi_white, 2); // White 
      //colorWipe(hi_cyan, 1); // Cyan
      //reverseColorWipe(strip_outer.Color(0, 0, 0), 100); 
      //strip_outer.show(); // Initialize all pixels to 'off'
      modeCounter = 4;
      }
      //if (modeCounter > 4){
      //modeCounter = 4;
      //}
      Serial.print("mode number:  ");
      Serial.println(modeCounter);
     Serial.print("interrupt worked"); 
  }
  last_interrupt_time = interrupt_time;
} 


//void stateChange()
//{
  //state = !state;
  //digitalWrite(ledPin, state);  
  //modeCounter++; 
      //Serial.print("mode number:  ");
      //Serial.println(modeCounter); 
//}


void innerRing(uint32_t c){


      //inner strip start
        
      //strip_inner.show();
      //delay (2000);
      
      //strip_inner.setBrightness(100);
    
      strip_inner.setPixelColor(0, c);
      strip_inner.setPixelColor(1, c);
      strip_inner.show();
      delay (500);
    
      strip_inner.setPixelColor(2, c);
      strip_inner.setPixelColor(3, c);
      strip_inner.show();
      delay (500);
    
      strip_inner.setPixelColor(4, c);
      strip_inner.setPixelColor(5, c);
      strip_inner.show();
      delay (500);
    
      strip_inner.setPixelColor(6, c);
      strip_inner.setPixelColor(7, c);
      strip_inner.show();
      delay (500);
    
      strip_inner.setPixelColor(8, c);
      strip_inner.setPixelColor(9, c);
      strip_inner.show();
      delay (500);
    
      strip_inner.setPixelColor(10, c);
      strip_inner.setPixelColor(11, c);
      strip_inner.show();
      delay (500);
    
      strip_inner.setPixelColor(12, c);
      strip_inner.setPixelColor(13, c);
      strip_inner.show();
      delay (500);
    
      strip_inner.setPixelColor(14, c);
      strip_inner.setPixelColor(15, c);
      strip_inner.show();
      delay (500);
    
      strip_inner.setPixelColor(16, c);
      strip_inner.setPixelColor(17, c);
      strip_inner.show();
      delay (500);
    
      strip_inner.setPixelColor(18, c);
      strip_inner.setPixelColor(19, c);
      strip_inner.show();
      delay (500);
    
      strip_inner.setPixelColor(20, c);
      strip_inner.setPixelColor(21, c);
      strip_inner.show();
      delay (500);
    
      strip_inner.setPixelColor(22, c);
      strip_inner.setPixelColor(23, c);
      strip_inner.show();
      delay (500);
      
      strip_inner.setPixelColor(24, c);
      strip_inner.setPixelColor(25, c);
      strip_inner.show();
      delay (500);
    
      strip_inner.setPixelColor(26, c);
      strip_inner.setPixelColor(27, c);
      strip_inner.show();
      //delay (500);
    
      //strip_inner.setPixelColor(28, 0, 0, 255);
      //strip_inner.setPixelColor(29, 0, 0, 255);
      //strip_inner.show();
      //delay (500);
      //strip_inner.show();
      //delay (2000);
    
      //inner strip end  


}


//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
  
  for (int j=0; j<20; j++) {  //do 1000 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip_outer.numPixels(); i=i+3) {
        strip_outer.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip_outer.show();
      
      delay(wait);
     
      for (int i=0; i < strip_outer.numPixels(); i=i+3) {
        strip_outer.setPixelColor(i+q, 0);        //turn every third pixel off
        delay(2);
      }
    }
  }
}


//while (WTV20SDBreakout.playVoice(2));
//}


// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip_outer.numPixels(); i++) {
      strip_outer.setPixelColor(i, c);
      strip_outer.show();
      delay(wait);
  }
}


// Fill the dots one after the other with a color
void colorWipe_On(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip_outer.numPixels(); i++) {
      strip_outer.setPixelColor(i, c);
      delay(10);
      strip_outer.show();
      delay(wait);
  }
}


void reverseColorWipe(uint32_t c, uint8_t wait)
{
  for(int16_t i=(strip_outer.numPixels()-1); i>=0; i--)
{
  strip_outer.setPixelColor(i, c);
  strip_outer.show();
  modeCounter = 1;
  delay(5);
  }
}
 
Last edited by a moderator:
You could solder the parts freeform (without a circuit board, very small), or with a circuit board. For the circuit board, if its not too complex you could use a prototyping board or if its more complicated you might consider printing your own board, either with toner transfer/ chemicals or send it off to be fabricated at a board shop.
 
Thanks for the evolution disc sounds zook, they are just what I was looking for :)

To add to ookid's suggestions, PCB strip board is also useful for tying components after the breadboard phase. don't forget to use heatshrink tube when free for soldering to help prevent shorting the circuit.
 
zookone this build is awesome man. Cant wait to see it all done.
Looking at your arduino sketch shows iv got a long looooooong way to go to understanding coding. Im trying to do a "simple" sketch for my buzz lightyear costume and its just confusing as hell. So iv got a lot of respect for anyone who can do this. Keep it up
 
Last edited by a moderator:
This thread is more than 7 years old.

Your message may be considered spam for the following reasons:

  1. This thread hasn't been active in some time. A new post in this thread might not contribute constructively to this discussion after so long.
If you wish to reply despite these issues, check the box below before replying.
Be aware that malicious compliance may result in more severe penalties.
Back
Top