0

We are working on a project to control the reaction of a system to a lever, whose position is monitored by two IR sensors at the ends of its travel, the Reward sensor and the Trigger sensor.

There are three modes of action:

Mode1: lever has to start at TriggerSensor, and a success is recorded if and when the lever is moved to RewardSensor

Mode2: lever starts at TriggerSensor and has to be held for 4 seconds. At the end of this interval a tone is played for 2 seconds, the reward interval. Within this 2 seconds, if the lever is moved to the RewardSensor, a success is recorded.

Mode3: same as Mode2, but the initial 4 second timeout is of random length.

We also want to use the following lines:

digitalWrite(TriggerSensorOut, digitalRead(TriggerSensorIn)); //This is to record to our computer the states of the trigger sensor digitalWrite(RewardSensorOut, digitalRead(RewardSensorIn)); //This is to record to our computer the states of the reward sensor

to constantly write the state of both sensors to our computer. However, this doesn't work as planned: there are delays between the execution of the mode functions (as described in full code below).Essentially, we are struggling to come up with a suitable way to time things correctly.

Please see full code below

// -----LIBRARIES

//#include <elapsedMillis.h>

// ----CONSTANTS (won't change)

const int TriggerSensorIn = 2;   //  Input from trigger sensor, LOW = broken
const int RewardSensorIn = 3;    //  Input from reward sensor, LOW = broken
const int ModeStateIn1 = 4;      //  Input 1 from switch to define paradigm mode
const int ModeStateIn2 = 5;      //  Input 2 from switch to define paradigm mode
const int RewardSignalOut = 12;   //  Output signal of reward, parallel taken off to counter module
const int ServoResetOut = 6;     //  Servo reset output signal
const int ToneOut = 10;          //  Audio stimulus
const int TriggerSensorOut = 7;  //  Output from trigger sensor for DAC board recording
const int RewardSensorOut = 8;   //  Output from reward sensor for DAC board recording

//------- VARIABLES (will change)

boolean backPressed = false;

int timeoutWindow = 4000;    // 4 second preliminary interval
int rewardWindow = 2000;    // 2 second reward interval

unsigned long currentMillis = 0;

//===============

void setup() {

  // initialise the digital pins as inputs and outputs

  pinMode(TriggerSensorIn, INPUT);
  pinMode(RewardSensorIn, INPUT);
  pinMode(ModeStateIn1, INPUT);
  pinMode(ModeStateIn2, INPUT);

  pinMode(RewardSignalOut, OUTPUT);
  pinMode(ServoResetOut, OUTPUT);
  pinMode(ToneOut, OUTPUT);
  pinMode(TriggerSensorOut, OUTPUT);
  pinMode(RewardSensorOut, OUTPUT);

}

//===============

void giveReward() {
  // This function is the protocol for recording a reward
  currentMillis=millis();
  digitalWrite(RewardSignalOut, HIGH);
  while (millis()>currentMillis+200) {
    digitalWrite(RewardSignalOut, LOW);
  }
}

//===============

void servoReset() {
  // This function is the protocol for resetting servos after a failed action
  currentMillis=millis();
  digitalWrite(ServoResetOut, HIGH);
  while (millis()>currentMillis+200) {
    digitalWrite(ServoResetOut, LOW);
  }
}

//===============

void mode1() {
  // This function is the protocol for controlling the system during mode 1, no time constraint on the action
  if (digitalRead(TriggerSensorIn == LOW)) {
    backPressed = true;

    if (backPressed == true && digitalRead(RewardSensorIn == LOW)) {
      giveReward();
      backPressed = false;
    }
  }
}

//===============

void mode2() {
  if (digitalRead(TriggerSensorIn == LOW)) {
    currentMillis=millis();
    while (digitalRead(TriggerSensorIn == LOW)) {
      while (millis() > currentMillis + timeoutWindow) {
        tone(ToneOut, 3000, 2000); 
        {
          goto rewardSeeking2;
        }
      }
    }

rewardSeeking2:
    currentMillis=millis();  // reset timer
    if (millis() < (currentMillis + rewardWindow) && digitalRead(RewardSensorIn == LOW)) {
      giveReward();
    }
    else if (millis() > (currentMillis + rewardWindow)) {
      servoReset();
    }
  }
}

//===============

void mode3() {
  timeoutWindow=random(1000,5000);
  if (digitalRead(TriggerSensorIn == LOW)) {
    currentMillis=millis();
    while (digitalRead(TriggerSensorIn == LOW)) {
      while (millis() > currentMillis + timeoutWindow) {
        tone(ToneOut, 3000, 2000); 
        {
          goto rewardSeeking3;
        }
      }
    }

rewardSeeking3:
    currentMillis=millis();  // reset timer
    if (millis() < (currentMillis + rewardWindow) && digitalRead(RewardSensorIn == LOW)) {
      giveReward();
    }
    else if (millis() > (currentMillis + rewardWindow)) {
      servoReset();
    }
  }
}

//===============

void loop() {

  digitalWrite(TriggerSensorOut, digitalRead(TriggerSensorIn));  //This is to record to our computer the states of the trigger sensor
  digitalWrite(RewardSensorOut, digitalRead(RewardSensorIn));  //This is to record to our computer the states of the reward sensor


  if (digitalRead(ModeStateIn1) == LOW && digitalRead(ModeStateIn2) == LOW) {
    // Using the two mode selective switches to define mode1
    mode1();
  }

  else if (digitalRead(ModeStateIn1) == LOW && digitalRead(ModeStateIn2) == HIGH) {
    // Using the two mode selective switches to define mode2
    mode2();
  }

  else if (digitalRead(ModeStateIn1) == HIGH && digitalRead(ModeStateIn2) == LOW)  {
    // Using the two mode selective switches to define mode3
    mode3();
  }
}

//===============END
  • while (millis() > currentMillis + timeoutWindow) looks wrong to me. I'd think the > should be a < . – Gerben Jul 14 '15 at 12:47
  • Even with a < it would be wrong because of the millis() rollover. The right way to write that would be while (millis() - currentMillis < timeoutWindow). – Edgar Bonet Jul 14 '15 at 15:05
  • Goto? GOTO?!?!?!?! AAAAAARRRRRGGGHHHH!!!!!! NO!!!!! – Majenko Jul 14 '15 at 15:17
  • what would you recommend using instead of GOTO, just use break? – pastoral Jul 14 '15 at 15:36
  • Well, goto has its use, see for example the way in the linux kernel device drivers undo partial initialization, when some intermediate test fails. However here its use seems strange: it's inside a while loop that actually gets executed only once (therefore it could be turned into and "if"). And the execution breaks out of the outer while when the inner condition is verified. Since it's not possible to add readable code to a comment here, I'll try to put it in a separate answer. – Igor Stoppa Jul 14 '15 at 18:40
1

This is a snippet of how I would refactor the code:

void mode3() {
  int timeout = millis() + random(1000,5000);
  while (digitalRead(TriggerSensorIn == LOW) && 
         millis() < timeout) {
  };
  if (digitalRead(TriggerSensorIn == LOW) && 
         millis() > timeout) {
     tone(ToneOut, 3000); 
     timeout = millis() + rewardWindow;
     while (millis() < timeout)
       if (digitalRead(RewardSensorIn == LOW)
         giveReward();
  }
  noTone();
}

....

void loop() {
  // This is to record to our computer the states of
  // the trigger sensor
  digitalWrite(TriggerSensorOut, digitalRead(TriggerSensorIn));  

  // This is to record to our computer the states of
  // the reward sensor
  digitalWrite(RewardSensorOut, digitalRead(RewardSensorIn));  


  int msin1 = digitalRead(ModeStateIn1);
  int msin2 = digitalRead(ModeStateIn2);

  if (msin1 == LOW)
      if (msin2 == LOW)
          mode1();
      else
          mode2();
  else if (msin2 == LOW)
    mode3();
}

But I think you should first try to write it down in plain English and verify that at least that algo works. Then you can think how to transpose it into code.

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.