0

I am trying to use two "infrared obstacle avoidance modules" to work with the following sketch. From all my research, I believe, a case statement is my best option because, (I understand) the sketch will not continue until the case is satisfied, however, I'm getting a weird outcome. When using two sensors with sketch below, the leds blink in an alternating pattern without any near the ir sensors.

If I use only one module the led will light until the sensor sees something, then the led turns off for the programmed delay then turns back on.

The outcome I'm looking for is eventually three modules, that will randomly light, when one lights it waits until something breaks the beam, then another will light and wait... Does anyone have any ideas how to make this work?

int ledselect;
int led1 = 2;
int led2 = 3;
int ir1 = 4;
int ir2 = 5;
int s1 = A0;
int s2 = A1;

void setup() {
  Serial.begin(9600);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(ir1, OUTPUT);
  pinMode(ir2, OUTPUT);
  pinMode(s1, INPUT);
  pinMode(s2, INPUT);

}
void loop() {
  ledselect = random(2);
  switch (ledselect) {

    case 0:
      digitalWrite(led1, HIGH);
      digitalWrite(ir1, HIGH);
      delay(50);
      while (analogRead(s1) >= 100)
      {
        delay(50);
        digitalWrite(led1, LOW);
        digitalWrite(ir1, LOW);
      }
      break;

    case 1:
      digitalWrite(led2, HIGH);
      digitalWrite(ir2, HIGH);
      delay(50);
      while (analogRead(s2) >= 100)
      {
        delay(50);
        digitalWrite(led2, LOW);
        digitalWrite(ir2, LOW);
      }
      break;
  }
}
  • the sketch will not continue until the case is satisfied ... that is not quite correct ... the case statement is just a decision structure that branches to different sections of the code depending on the value of a parameter .... it is similar to a series of if statements – jsotola Jul 5 at 15:09
0

What happens is:

  1. A random number is selected
  2. A light goes on
  3. It goes off when nothing is near (assuming a low value of an analog sensor means nothing near?)
  4. The same light or another light goes on (depending on the random led)
  5. Continue with 3.

Some reasons why this might fail:

  • Check the value (should it be higher or lower than 100?)
  • Maybe the sensor is not so accurate and sometimes give 0 or max values which are incorrect. To change this, read multiple times the sensor and take the average, or remove the lowest and highest few (to remove spikes) and take the average.

UPDATE

The body of the case statements are almost equal, make it a function called from both case statements:

Your code will look like:

void loop() {
  ledselect = random(2);
  switch (ledselect) {
    case 0:
      process(led1, ir1, s1);
      break;

    case 1:
      process(led2, ir2, s2);
      break;
  }
}

void process(int led, int sw, int ir)
{
  digitalWrite(led, HIGH);
  digitalWrite(ir, HIGH);
  delay(50);
  while (analogRead(sw) >= 100)
  {
    delay(50);
    digitalWrite(led, LOW);
    digitalWrite(ir, LOW);
  }
}

If you use the ternary operator ( x ? y : z, meaning if x than y else z), than your loop function will be:

void loop() {
  ledselect = random(2);
  process(ledselect == 0 ? led1 : led2, 
          ledselect == 0 ?  ir1 :  ir2,
          ledselect == 0 ?   s1 :   s2);
}

An even more elegant way, is to use an array for the parts (not sure what better name can be), instead of all variables naming 0 and 1, put them in arrays, and you get the following code below. If you make more parts, you just have the change the beginning of the code.

int ledselect;

const int NrOfParts = 2;

int leds     [NrOfParts] = {  2 , 3 };
int irs      [NrOfParts] = {  4,  5 };
int switches [NrOfParts] = { A0, A1 };

void setup() {
  Serial.begin(9600);
  for (int part = 0; part < NrOfParts; part++)
  {
    pinMode(leds    [part], OUTPUT);
    pinMode(irs     [part], OUTPUT);
    pinMode(switches[part],  INPUT);
  }
}

void loop() 
{
  ledselect = random(2);
  process(leds[ledselect], irs[ledselect], switches[ledselect]);
}

void process(int led, int sw, int ir)
{
  digitalWrite(led, HIGH);
  digitalWrite(ir, HIGH);
  delay(50);
  while (analogRead(sw) >= 100)
  {
    delay(50);
    digitalWrite(led, LOW);
    digitalWrite(ir, LOW);
  }
}

Update 2

An even better way is to create a structure (so you keep all information of one 'part' together).

This solution uses the & (dereference) operator, meaning it is like a variable pointing to a part.

int ledselect;

const int NrOfParts = 2;

struct Part
{
  int led;
  int ir;
  int sw;
};

Part _parts[NrOfParts] = 
{
  { 2, 4, A0 }, 
  { 3, 5, A1 } 
};

void setup() {
  Serial.begin(9600);
  for (int partNumber = 0; partNumber < NrOfParts; partNumber++)
  {
    Part& part = _parts[partNumber];
    pinMode(part.led, OUTPUT);
    pinMode(part.ir , OUTPUT);
    pinMode(part.sw ,  INPUT);
  }
}

void loop() 
{
  process(_parts[random(2)]);
}

void process(Part& part)
{
  digitalWrite(part.led, HIGH);
  digitalWrite(part.ir, HIGH);
  delay(50);
  while (analogRead(part.sw) >= 100)
  {
    delay(50);
    digitalWrite(part.led, LOW);
    digitalWrite(part.ir, LOW);
  }
}
  • 1
    Thank you Michel for your response. I used your suggestion to clean the sketch and greatly appreciate you taking the time to analyze my question and answer. – Bender Jul 9 at 11:38
  • I added some more alternatives, do not use them if you don't feel comfortable. – Michel Keijzers Jul 9 at 14:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.