# Issue with time-dependant conditional I/O control flow (Arduino UNO)

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.

// -----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
backPressed = true;

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

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

void mode2() {
currentMillis=millis();
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);
currentMillis=millis();
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

// Using the two mode selective switches to define mode1
mode1();
}

// Using the two mode selective switches to define mode2
mode2();
}

// 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

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

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


....

void loop() {
// This is to record to our computer the states of
// the trigger sensor

// This is to record to our computer the states of
// the reward sensor