BlinkMs + arduino + random colours + microswitch + potentiometers = ARGH!

Hi all,

I’ve got an arduino/BlinkM problem I was hoping I might be abel to find help with. Here’s what I’m looking to do;

I currently have a microswitch (switchPin in the code below), which when triggered activates a BlinkM. A potentiometer then controls the colour of the light. I need help in developing the code from what I have into something that does this;

Once the microswitch is LOW, BlinkM #1 will be assigned a random colour value (probably one of 6 possibilities). BlinkM#2 will be attached to the pot, which will be used to control its colour (it will not affect BM#1). Once the colour of BM#2 is tuned to match BM#1, a signal will be sent to actuate another part of the circuit. This will cause the microswitch to trigger to HIGH, at which point both BM’s need to fade to off.

Once the microswitch returns to a LOW state, both BMs need to come back on, with BM#1 being assigned a new colour and BM#2 retaining the colour that it was previous tuned to.

Can anyone help me out with any or all of this? I know it’s asking a lot but I’m getting way out of my depth here and could really use a little assistance!

Here’s the code I’ve cobbled together so far:

#include "Wire.h" 
#include "BlinkM_funcs.h" 

const int blinkm_addr = 0; 
const int hue_pot_pin = 0; 
int switchPin = 7; 
int val = 0; 

void setup() 
{ 
Serial.begin(19200); 
pinMode(switchPin, INPUT); 
BlinkM_beginWithPower(); 
BlinkM_stopScript(blinkm_addr); // turn off startup script 
Serial.println("BlinkMKnobHue ready"); 
} 

void loop() 
{ 
val = digitalRead(switchPin); 

if (val == LOW){ 
// read the hue pot, values range from 0-1023, blinkm's 0-255, thus /4 
int hue_val = analogRead(hue_pot_pin) / 4; 
Serial.println(hue_val); 
// set blinkms with hue; brightness & saturation is max 
BlinkM_fadeToHSB( blinkm_addr, hue_val, 255, 255 ); 
delay(50); // wait a bit because we don't need to go fast 
} else { 
BlinkM_fadeToHSB( blinkm_addr, 0, 0, 0 );} 

}

Thanks in advance,

Tim

Once the colour of BM#2 is tuned to match BM#1

How is the color to be "tuned"? If you expect to turn a potentiometer to do this, you're going to need more than one. One for red, one for green, and one for blue. Unless you only want to control one color.

a signal will be sent

What kind of signal? Sent by what? To what?

to actuate another part of the circuit.

Which does what? What is this circuit?

This will cause the microswitch to trigger to HIGH

How?

at which point both BM's need to fade to off.

Fade to off or just turn off? Fade how? Red first, then blue, then green? Or some other way?

Once the microswitch returns to a LOW state

How does this happen?

Can anyone help me out with any or all of this?

Not yet. We need a bunch of answers first.

Hi Paul, thanks for the reply. Here are some answers;

How is the color to be "tuned"? If you expect to turn a potentiometer to do this, you're going to need more than one. One for red, one for green, and one for blue. Unless you only want to control one colour.

This is already handled by the BlinkM_funcs.h library. One pot controls the R,G & B values to give full spectrum colour shift.

What kind of signal? Sent by what? To what?

I left this out to avoid over complicating things. Once the colour of BM#2 matches BM#1, I need the code to tell an attached solenoid to engage (this is acting as a lock on a drawer). Once engaged, the drawer will be opened. This will release the microswitch, which then returns a HIGH value. The solenoid circuit is already built, but obviously isn't integrated into this circuit.

Which does what? What is this circuit?

The solenoid mentioned above.

How?

By the microswitch releasing and returning a HIGH value, as mentioned above.

Fade to off or just turn off? Fade how? Red first, then blue, then green? Or some other way?

They both fade straight to off. This is already handled by my code: BlinkM_fadeToHSB( blinkm_addr, 0, 0, 0 );

How does this happen?

By the drawer closing again and activating the microswitch.

Not yet. We need a bunch of answers first.

Hope that clarifies things a bit.

This is already handled by the BlinkM_funcs.h library.

Got a link to this library? Given the fact that the BlinkM_fadeToHSB() function takes three arguments, in addition to which module to manipulate, it looks like those three values are red, green, and blue. I'd like to confirm or deny this, though.

Sure, here you go (second tab).

Lamp.ino (1.25 KB)

That’s the sketch, not the library.

Sorry, my bad. Here you go;

BlinkM_funcs.h (13.1 KB)

The library has:

static void BlinkM_fadeToHSB(byte addr, byte hue, byte saturation, byte brightness)

So, you are specifying a hue value. I can't see how that relates to a specific color, though.

Once the colour of BM#2 matches BM#1, I need the code to tell an attached solenoid to engage (this is acting as a lock on a drawer).

In whose opinion? In other words, does the user turn a pot that controls the 2nd Blinky and, when the user likes the match, press another button, and if the pot value and random value match, fire the solenoid? Or, does the user turn the pot until the colors match, and when the pot output matches the random color of Blinky #1, should the solenoid be opened automatically?

What is the purpose of matching colors this way? There will only be 255 discrete colors. Making them match won't be too difficult for most people. Now, using the BlinkM_fadeToRGB() function would allow a lot more color choices.

The library has:

static void BlinkM_fadeToHSB(byte addr, byte hue, byte saturation, byte brightness)

So, you are specifying a hue value. I can't see how that relates to a specific color, though.

This is my point. At the moment I can cycle through the colour spectrum via the pot using this code. I need to feed the actual colour values back into the code so that the it knows when the two BlinkM's are matched.

Once the colour of BM#2 matches BM#1, I need the code to tell an attached solenoid to engage (this is acting as a lock on a drawer).

In whose opinion? In other words, does the user turn a pot that controls the 2nd Blinky and, when the user likes the match, press another button, and if the pot value and random value match, fire the solenoid? Or, does the user turn the pot until the colors match, and when the pot output matches the random color of Blinky #1, should the solenoid be opened automatically?[/quote]

The latter (user turns pot so that BM2 matches BM1, at which point the solenoid engages.

What is the purpose of matching colors this way? There will only be 255 discrete colors. Making them match won't be too difficult for most people. Now, using the BlinkM_fadeToRGB() function would allow a lot more color choices.

I don't know if you've used BlinkM's before, but their colour mixing is pretty awful once you get out of the red end of the spectrum (the yellow is spectacularly bad). I can't afford to be too specific about the colour values that the user is asked to match, otherwise they won't actually be able to tell the difference in the colour they're seeing. I think the best I can hope for are the six primary and secondary colours. The actual process of unlocking is fairly easy, but finding the physical pot won't be :)

The latter (user turns pot so that BM2 matches BM1, at which point the solenoid engages.

The actual process of unlocking is fairly easy, but finding the physical pot won't be

So, once the person finds the physical pot, they close their eyes and turn it until the solenoid clicks.

I'm missing the point of the BlinkMs then. What I've heard you way is that the Arduino will pick a random value, and send it to the 1st BlinkM. Then, the user will turn a pot, with the Arduino reading the value frequently, sending the value to another BlinkM, until the reading matches the value sent to the 1st BlinkM. At which time, the solenoid fires automatically.

I'm sure I'm missing something...

Both BlinkM’s will be outputting colour. BlinkM#1’s colour output is determined by the random code (e.g 255,0,0) and is only changed once the circuit is reset (once the drawer has been opened and closed again). BlinkM#2’s colour output is determined by the position of the pot (e.g. 0, 255, 255). When the pot is turned and BM#2 hits the same colour as BM#1 (so both are red), the drawer unlocks.

It’s basically a lock puzzle. BM#1 tells you what colour you need to tune BM#2 to.

BM#1 tells you what colour you need to tune BM#2 to.

I get that. What I don't get is that as soon as the values match, the solenoid is activated. A blind person could match the colors just by listening for the solenoid to activate.

If you had to match the color, and then press a button, and the solenoid would activate if the colors matched, then there would be some security/challenge involved.

Trust me, for this application it works. Are you able to assist with my questions regarding the code?

Are you able to assist with my questions regarding the code?

Sure. I'm not really sure what help you need, though.

You can get a random number for the 1st BlinkM using

int hue_one = random(0, 256);

You are reading the pot value now, using:

int hue_val = analogRead(hue_pot_pin) / 4;

Each time you read the value, you need to compare hue_val to hue_one.

if(hue_one == hue_val)
{
}

In the curly braces, you need to power the solenoid pin for a period of time.

digitalWrite(solPin, HIGH);
delay(20);
digitalWrite(solPin, LOW);

You'll need to experiment with the time value to see how long the pin needs to be high to make the solenoid open the drawer.

You'll need an else block to go with this if:

if (val == LOW){

which you have. In that else block, you need to fade both BlinkMs back to 0.

Some local variables will need to become global or static, so values are persisted for the next go-round.

Did I miss anything?

Hi Paul,

Thanks for the help, I'm going through this now. Could you advise as to where this line should be?

int hue_one = random(0, 256);

If I add it to my void setup it picks a random colour once when the sketch is run, but this colour does not change each time the microswitch is thrown.

If I add it to my void loop, each time it's called the LED flashes through random colours, but does not stop on one.

Thanks,

Tim

Could you advise as to where this line should be?

That really should be split into two parts - a declaration (global) and the initialization.

int hue_val;
hue_val = random(0, 256);

If you put the initialization part in setup(), it will only be called once per reset.

If you put it in loop(), it might, depending on where you put it, be called the right number of times, too often, or not often enough. The key, then, is to put it in the right place.

As far as reading the switch, I think you are going to have to detect transitions - when the switch goes from pressed to released or from released to pressed. You would, for instance, want to select a new color when the switch became pressed. Or possibly, when it became released, depending on your needs.

Detecting the change is easy.

int currState;
int prevState = LOW; // Could be HIGH, depending on the switch wiring
void loop()
{
   currState = digitalRead(microPin);
   if(currState != prevState)
   {
      // A transition occurred
      if(currState == LOW) // Assumes pullup resistor wired or the internal one is used
      {
         // Transition from released to pressed
      }
      else
      {
         // Transition from pressed to released
      }
   }
}

Thanks Paul, I figured it out after I wrote that post. Here's what I'm currently using;

#include "Wire.h"
#include "BlinkM_funcs.h"

const int candle_blinkm_addr = 1;
const int indicator_blinkm_addr = 2;
const int hue_pot_pin = 0;
int mswitch_pin = 7;
int mswitch_val;
int indicator_blinkm;
int random_RGB;
int new_random_RGB;

void setup()
{
  Serial.begin(19200);
  pinMode(mswitch_pin, INPUT);
  BlinkM_beginWithPower();
  BlinkM_stopScript(candle_blinkm_addr);
  BlinkM_stopScript(indicator_blinkm_addr);  // turn off startup script
  Serial.println("BlinkMKnobHue ready");
}

void loop() 
{
  mswitch_val = digitalRead(mswitch_pin);
  random_RGB = random(0,256);
  if (mswitch_val == LOW){ //LOW = microswitch closed, HIGH = microswitch open
    int hue_val = analogRead(hue_pot_pin) / 4;
    BlinkM_fadeToHSB(candle_blinkm_addr, hue_val, 255, 255);
    BlinkM_fadeToHSB(indicator_blinkm_addr, new_random_RGB, 255, 255);
  } 
  else {
    int hue_val = analogRead(hue_pot_pin) / 4; 
    BlinkM_fadeToHSB(candle_blinkm_addr, 0, 0, 0 );
    BlinkM_fadeToHSB(indicator_blinkm_addr, random_RGB, 255, 0);
    new_random_RGB = random_RGB;  
    delay(300);}
  }

Now on to the next bits...

Hi Paul, here' what I'm at;

#include "Wire.h"
#include "BlinkM_funcs.h"

const int candle_blinkm_addr = 1;
const int indicator_blinkm_addr = 2;
const int hue_pot_pin = 0;
int mswitch_pin = 7;
int mswitch_val;
int indicator_blinkm;
int random_RGB;
int new_random_RGB;
int solenoid = 9;
int hue_val;

void setup()
{
  Serial.begin(19200);
  pinMode(mswitch_pin, INPUT);
  BlinkM_beginWithPower();
  BlinkM_stopScript(candle_blinkm_addr);
  BlinkM_stopScript(indicator_blinkm_addr);  // turn off startup script
  Serial.println("BlinkMKnobHue ready");
  BlinkM_setFadeSpeed(indicator_blinkm_addr, 10);
  randomSeed(5);
}

void loop() 
{
  mswitch_val = digitalRead(mswitch_pin);
  random_RGB = random(0,256);
  if (mswitch_val == LOW){ //LOW = microswitch closed, HIGH = microswitch open
    int hue_val = analogRead(hue_pot_pin) / 4;
    BlinkM_fadeToHSB(candle_blinkm_addr, hue_val, 255, 255); //
    BlinkM_fadeToHSB(indicator_blinkm_addr, new_random_RGB, 255, 255);
  } 
  else {
    int hue_val = analogRead(hue_pot_pin) / 4;
    BlinkM_fadeToHSB(candle_blinkm_addr, 0, 0, 0 );
    BlinkM_fadeToHSB(indicator_blinkm_addr, random_RGB, 255, 0);
    new_random_RGB = random_RGB;  
    delay(300);
  }
  
  if (hue_val == random_RGB){
    digitalWrite(solenoid, HIGH);
  } else {
    digitalWrite(solenoid, LOW);
  }
}

There are a couple of issues;

  1. I'm not sure that the solenoid unlock code is working properly. For now I'm using an LED in place of the solenoid, and although its lighting up when the colour values match, it's also lighting up when the pot is at other values. I'm wondering if its also reacting to the new_random_RGB integer at all? Can you see why this might be happening?

  2. Once the solenoid is HIGH, I need the act of moving the microswitch state to HIGH to cause the solenoid to move to LOW. I.E this;

microswitch is engaged (the drawer is closed) candle_blinkm is tuned so its colour matches indicator_blinkm solenoid is engaged (drawer is unlocked) user opens drawer microswitch becomes disengaged user closes drawer microswitch becomes engaged solenoid is automatically disengaged (drawer becomes locked again) indicator_blinkm receives a new RGB value circuit it ready to use again.

Thanks again for you help with this so far, I really appreciate it.

I'd like to make a couple of suggestions. First:

int random_RGB;

is to contain a value passed to the BlinkM_fadeToHSB() function. I really think that RGB in the name is inappropriate.

Second, I think the structure of your program would be clearer is each { was on it's own line.

As to your problem, it seems to me that you want to activate the solenoid only when mswitch_val is LOW. You want to deactivate the solenoid only when mswitch_val is HIGH. At a minimum, this change will address issue #2.

You've also fallen into the classic trap of having a global variable:

int hue_val;

and a local variable:

    int hue_val = analogRead(hue_pot_pin) / 4;

with the same name.

Then, you have:

  if (hue_val == random_RGB){

Can you be sure which hue_val you are referring to? (Yes, I know that the answer is that you can, but the point is that global and local variables of the same name is a bad idea, generally).

Finally, I think the real problem with issue #1 is this:

void loop()
{
  // snipped some code
  random_RGB = random(0,256);
  // snipped some more code
  if (hue_val == random_RGB)
  {
  }
  // snipped some more code
}

On each pass through loop, you create a new random number. This happens millions of times a second.

What you want to be using in the if test is new_random_RGB, not random_RGB.

Also note that you want to assign a new value to new_random_RGB BEFORE you call BlinkM_fadeToHSB() in the else block.

Last, but not least, is the fact that you really want to do some things only when the mswitch_val state changes, not every time through loop. You need to keep track of the previous state, too, and only do some of the stuff you are doing when the state changes.

If you need help implementing any of these suggestions, say so.

Hi Paul, thanks for the feedback. I've cleaned up the code as you suggested, which is making it easier to read;

#include "Wire.h"
#include "BlinkM_funcs.h"

const int candle_blinkm_addr = 1;
const int indicator_blinkm_addr = 2;
const int hue_pot_pin = 0;
const int solenoid = 9;
const int mswitch_pin = 7;
int mswitch_val;
int indicator_blinkm;
int random_HSB;
int new_random_HSB;

void setup()
{
  Serial.begin(19200);
  pinMode(mswitch_pin, INPUT);
  BlinkM_beginWithPower();
  BlinkM_stopScript(candle_blinkm_addr);
  BlinkM_stopScript(indicator_blinkm_addr);  // turn off startup script
  Serial.println("BlinkMKnobHue ready");
  BlinkM_setFadeSpeed(indicator_blinkm_addr, 10);
  randomSeed(5);
}

void loop() 
{
  mswitch_val = digitalRead(mswitch_pin);
  random_HSB = random(0,256);
  int hue_val = analogRead(hue_pot_pin) / 4;
  if (mswitch_val == LOW) //LOW = microswitch closed, HIGH = microswitch open
  { 
    BlinkM_fadeToHSB(candle_blinkm_addr, hue_val, 255, 255);
    BlinkM_fadeToHSB(indicator_blinkm_addr, new_random_HSB, 255, 255);
  } 
  else 
  {
    new_random_HSB = random_HSB;  
    BlinkM_fadeToHSB(candle_blinkm_addr, 0, 0, 0 );
    BlinkM_fadeToHSB(indicator_blinkm_addr, random_HSB, 255, 0);
  } 
  if ((hue_val == new_random_HSB) && (mswitch_val = LOW))
  {
    digitalWrite(solenoid, HIGH);
    delay (1000);
  } 
  else 
  {
    digitalWrite(solenoid, LOW);
  }
}

I'm having trouble with this line:

  if ((hue_val == new_random_HSB) && (mswitch_val = LOW))

If I take out the && (mswitch_val = LOW)), the LED comes on when the colours match. However, adding this line means that the LED never comes on. I'm sure it's something trivial, but I don't know what to change in order to get it working. Have I used the wrong function perhaps?

I'm also unsure as to what you're referring to when you say this;

Last, but not least, is the fact that you really want to do some things only when the mswitch_val state changes, not every time through loop. You need to keep track of the previous state, too, and only do some of the stuff you are doing when the state changes.