Go Down

Topic: Two Methods At Once (Read 4019 times) previous topic - next topic

SimpleSDK

I am working on a Daft Punk helmet and just received my custom PCB two days ago and finished soldering it today and it works great! However, the one thing I can't think of to do is to do two methods at once.

Here's my video:

http://www.youtube.com/watch?v=uRGNAZAsgrg

You see I have LED's going across then 4 rows going up and down. The ones going side to side are in one method, and the ones going up and down in another. They both go one after the other, but I would like to have them animate at the same time. How could I make this happen?

Thank you!

scswift

#1
Apr 03, 2011, 02:16 pm Last Edit: Apr 03, 2011, 02:24 pm by scswift Reason: 1
It might help to know something about this custom PCB, but I'm gonna assume it can handle lighting any combination of LEDs at once.

Also it would really help to see your code.  But since you haven't posted it, I'm going to assume what you have is basically a simple loop with a delay between each LED change.

You could get complicated with the code to animate the leds but if you just want this simple animation pattern to go in both directions at once, you probably don't need to do that.  What you do need to do is post the code so we can take a look at it.

I assume the code is something like this:

turn on led 1
delay 250
turn off led 1
turn on led 2
delay 250
turn off led 2
turn on led 3
delay 250
turn off led 3
turn on led 4
delay 250
turn off led 4

If so, you need to figure out where it goes from displaying the first pattern to displaying the second pattern, and interleave the code.  In the case of the above, if you wanted leds 3 and 4 to animate at the same time as leds 1 and 2, you would do this:

turn on led 1
turn on led 3
delay 250
turn off led 1
turn off led 3
turn on led 2
turn on led 4
delay 250
turn off led 2
turn off led 4

But that makes assumptions about how the circuit is constructed.  It assumes you can turn on leds 1 and 3 at the same time.  That may not be the case.  If it is not the case, then things need to get a lot more complicated, and what you'd need to do is switch back and forth between leds 1 and 3 so rapidly that they both appear to be on at once.  This would cut the brightness of both leds in half however.

The above also assumes that the two patterns contain the same number of leds, and that they animate at the same speed.  If that is not the case, then what you need to do is change your code so that instead of using delays, you read the current time, and decide if it is time to change the led which is lit.  Then you can have two variables pattern1 and pattern2 which tell you which led you're lighting in that particular pattern at that particular moment, and pattern1time and pattern2time, which tell you the time at which you should next increment the led that is lit in that particular pattern.  After changing the led which is lit, you then do something like pattern1time = time + 250, where time is the current time in milliseconds, and that will cause the function to wait until 250ms has passed before it changes the LED again.

SimpleSDK

Ok I understand, but I'm not understanding the way of how it would work like how you are explaining. If you wanted to see my code, here it is:
Code: [Select]

void setup() {
  /* Cheek LED's */
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
 
  /* Chin LED's */
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
}

void loop() {
   cheekAnimations();
   chinAnimations();
}


/* --- All of the animations for the helmet -- */

void cheekAnimation() {
  digitalWrite(3, HIGH);
  delay(300);
  digitalWrite(3, LOW);
  digitalWrite(4, HIGH);
  delay(300);
  digitalWrite(4, LOW);
  digitalWrite(5, HIGH);
  delay(300);
  digitalWrite(5, LOW);
  digitalWrite(6, HIGH);
  delay(300);
  digitalWrite(6, LOW);
  digitalWrite(7, HIGH);
  delay(300);
  digitalWrite(7, LOW);
  digitalWrite(8, HIGH);
  delay(300);
  digitalWrite(8, LOW);
  digitalWrite(9, HIGH);
  delay(300);
  digitalWrite(9, LOW);
  digitalWrite(8, HIGH);
  delay(300);
  digitalWrite(8, LOW);
  digitalWrite(7, HIGH);
  delay(300);
  digitalWrite(7, LOW);
  digitalWrite(6, HIGH);
  delay(300);
  digitalWrite(6, LOW);
  digitalWrite(5, HIGH);
  delay(300);
  digitalWrite(5, LOW);
  digitalWrite(4, HIGH);
  delay(300);
  digitalWrite(4, LOW);

  // now pin 3 will light up by repeating
}

void chinAnimations() {
  digitalWrite(10, HIGH);
  delay(300);
  digitalWrite(10, LOW);
  digitalWrite(11, HIGH);
  delay(300);
  digitalWrite(11, LOW);
  digitalWrite(12, HIGH);
  delay(300);
  digitalWrite(12, LOW);
  digitalWrite(13, HIGH);
  delay(300);
  digitalWrite(13, LOW);
  digitalWrite(12, HIGH);
  delay(300);
  digitalWrite(12, LOW);
  digitalWrite(11, HIGH);
  delay(300);
  digitalWrite(11, LOW);
 
  // now pin 10 will light up by repeating
}


I tried to do for statements instead of all those digitalWrite's, but they didn't work correctly. Thanks for helping!

scswift

#3
Apr 03, 2011, 11:11 pm Last Edit: Apr 05, 2011, 03:04 am by scswift Reason: 1
Okay, well your functions look like a good candidate for the interleaving method, since the first animation has 12 led changes, and the second has 6, and those are even multiples, and the timing is identical, but I'm gonna do you a favor and show you how to animate LEDs properly since you will likely need to animate other LEDs on your helmet besides these at the same time.

Code: [Select]


  unsigned long time;

  void setup() {

    /* Cheek LED's */
      pinMode(3, OUTPUT);
      pinMode(4, OUTPUT);
      pinMode(5, OUTPUT);
      pinMode(6, OUTPUT);
      pinMode(7, OUTPUT);
      pinMode(8, OUTPUT);
      pinMode(9, OUTPUT);
     
    /* Chin LED's */
      pinMode(10, OUTPUT);
      pinMode(11, OUTPUT);
      pinMode(12, OUTPUT);
      pinMode(13, OUTPUT);   
   
  }


  void loop() {

    time = millis();

    cheekAnimations();
    chinAnimations();
     
  }   
   
  void cheekAnimations() {
   
    const int cheekSpeed = 300;
   
    static unsigned long nextTime;
    static int led;
    static int increment = 1;
    int x;
   
    if (time >= nextTime) {

      for (x = 0; x < 7; x++) { // Turn off all leds in this group.  Easier than keeping track of which one we should turn off each time.
        digitalWrite(3+x, LOW);
      }       
     
      digitalWrite(3+led, HIGH);

      led = led + increment;
      if ((led == 0) || (led == 6)) { increment = -increment; } // Change direction next update.
     
      nextTime = time + cheekSpeed;

    }
   
  }


  void chinAnimations() {
   
    const int chinSpeed = 300;
   
    static unsigned long nextTime;
    static int led;
    static int increment = 1;
    int x;
   
    if (time >= nextTime) {

      for (x = 0; x < 4; x++) {
        digitalWrite(10+x, LOW);
      }       
     
      digitalWrite(10+led, HIGH);
     
      led = led + increment;
      if ((led == 0) || (led == 3)) { increment = -increment; } // Change direction next update.

       nextTime = time + chinSpeed;

    }
     
  }


Try changing the constants, and you'll see you can animate the two portions at different speeds.

scswift

Oh, and note that even though I used the same variable names in the two functions, those variables are entirely seperate.  So the variable led in function 1 coexists with the variable led in function 2, and each holds a different value.  And the word "static" in front of those variables means that unlike the other variables delcared in the function, they retain their values when the function exits, and they are initialized to 0 if no other value is specified.  But if a value is specified, they are initialized to that only on the first go through the function, unlike the non-static variables like X which are recreated each time through the function, and which would be reinitialized every time if an initiaization value were specified.  But since one is not, x could be anyhting when the function begins.  But that's okay because it's used in the loop which sets it to 0 at the start of it.

johnwasser

#5
Apr 03, 2011, 11:35 pm Last Edit: Apr 04, 2011, 07:32 pm by johnwasser Reason: 1
If you want to light each LED of both sets in turn for 300 milliseconds:

Code: [Select]

const int CheekPins[] = {3,4,5,6,7,8,9,8,7,6,5,4};  // gives forward and back
const int CHEEK_COUNT = sizeof CheekPins / sizeof (int);

const int ChinPins[] = {10,11,12,13};
const int CHIN_COUNT = sizeof ChinPins / sizeof (int);

int CheekStep = 0;
int ChinStep = 0;

void setup()
  {
  int i;
  /* Cheek LED's */
  for (i=0; i< CHEEK_COUNT; i++)
    pinMode(CheekPins[i], OUTPUT);  // Yes, it's OK to set the pinMode twice on some pins

  /* Chin LED's */
  for (i=0; i< CHIN_COUNT; i++)
    pinMode(ChinPins[i], OUTPUT);
  }

void loop()
    {
    digitalWrite(CheekPins[CheekStep], HIGH);
    digitalWrite(ChinPins[ChinStep], HIGH);
    delay(300);
    digitalWrite(CheekPins[CheekStep], LOW);
    digitalWrite(ChinPins[ChinStep], LOW);

    CheekStep = (CheekStep+1) % CHEEK_COUNT;
    ChinStep = (ChinStep+1) % CHIN_COUNT;
    }


(Edited the code to correct some typos mentioned below.  It now compiles without error.)
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp
See who has no social life: https://forum.arduino.cc/index.php?action=stats :)

SimpleSDK

scswift - I uploaded the code you edited to the board and it was working great. However, after 30 - 40 times, the chin animations would stop and all light up at once. I edited one number to fix one problem, but that still kept happening.

johnwasser - I uploaded the code you wrote for me and it works nicely! The only issues were mis-spellings. Right now I am using your code and will most likely use your code for the rest of my project. Thank you!

Thank you to both of you for helping me out! I have definitely learned already and I am ready to continue my project. Thanks so much!!!

scswift

What number did you change in my code, and to fix what problem?

It sounds like one of the led variables got outside the range it was supposed to stay in, and that caused the function to set pins high which it should not.

John's code will work for this purpouse, but if you use his code you'll be back at square 1 if you're using the same microcontroller to update other leds in the helmet.






SimpleSDK

Inside of cheekAnimations()

Code: [Select]

if ((led == 0) | (led == 7)) { increment = -increment; } // Change direction next update.


I changed to...

Code: [Select]

if ((led == 0) | (led == 6)) { increment = -increment; } // Change direction next update.


And that fixed one of the LED's not getting turned on if I remember correctly.

scswift

You made the right change there. 

Another problem is I accidentally used bitwise OR instead of boolean OR.  So change the |'s in the IF statements to ||'s, like so:

if ((led == 0) || (led == 6)) { increment = -increment; } // Change direction next update.
if ((led == 0) || (led == 3)) { increment = -increment; } // Change direction next update.

But I don't see why that should affect the program, since (led == 0) and (led == 6) should each evaluate to true or false, which when converted to integers should be 1 or 0, and so a bitwise OR should produce the same result as a boolean OR, with the final value of 1 or 0 being interepreted as true or false for the purpouses of the if statement.

But perhaps I am wrong, and if (1) {} will not be interpreted as true.  If that is the case, then there's the bug which led to the crash.

SimpleSDK

I've been watching it after I edited the | and made it || and it does the exact same thing, yet the cheek goes and the chin stops.

Now I just uploaded John's code to it and it works how it should for a very long time and doesn't all light up at once.

I'll be editing this program within two weeks since that is the wait time for my other PCB's to get here. When I get those, that will be the real test of which of your guys' work works right with the helmet. I'll keep this topic updated when I get them and change the code around. :)

Thanks!

scswift

When you say the cheek goes, but the chin stops, do you mean the cheek continues to animate like it is supposed to, but all the lights come on in the chin?

Also, what exactly happens with the chin?  Does it animate back and forth for a while properly, then suddenly go all on?  Or does it only go back and forth once?  Or does it go one way then freeze? 

Try commenting out the function calls in the main loop, and uncommenting only one of them at a time.  In other words, see what happens if you animate only the cheek, and only the chin.

If the cheek has a bug, then you may see LEDs on the chin light.  If the chin has a bug, then you may see all the lights in it come on, but unless the bug is when it's going in reverse I don't expect leds will light on the cheek. 

Report what you see.  The code's not that complex I'm sure I've just made some stupid mistake somewhere.

johnwasser


jhnwasser - I uploaded the code you wrote for me and it works nicely! The only issues were mis-spellings. Right now I am using your code and will most likely use your code for the rest of my project. Thank you!


I corrected the typos in my post above, just in case someone else stumbles on this thread and wants to use the code.

Glad I was able to help.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp
See who has no social life: https://forum.arduino.cc/index.php?action=stats :)

SimpleSDK

Here is what happens scswift...

http://aleckazarian.com/misc/board-freeze.mov

John the only problem I see is that when I add the rainbow lights, they will go the same speed as the cheek and chin which is not what I want, but for now I'm using it.

scswift

#14
Apr 05, 2011, 03:11 am Last Edit: Apr 05, 2011, 03:13 am by scswift Reason: 1
Thanks.  I've found the bug!

The LEDs weren't all lighting at once.  They were just lighting one after the other very rapidly, as one does when multiplexing.

I added some debug code to print out the variables in the chin function, and uploaded it to a spare arduino I had laying around.  I then looked at the output of that since I didn't feel like hooking up a bunch of leds to duplicate your circuit.  I noticed that after approximately the same period of time as it takes for the leds in your video to mess up, the debuglog suddenly started updating a lot faster... and it was only supposed to update once for each change of chin LED.

I then double checked the timing code, and sure enough, somehow I'd declared static unsigned int nextTime in that function isntead of static unsigned long nextTime.

So as soon as time exceeded 65235, nextTime got screwed up, and was always less than time from that point on.  Which meant every time through the main loop the leds got updated.  So they were probably changing several hundred thousand times a second.

Just change that variable declaration and your problems will be solved.  Or copy the code above, where I've implemented all the bug fixes.



Go Up