I'm building a model tramway. I've been using infrared BEAM sensors (from Pi Hut). I have found them to be reliable. However, I have encountered an issue and would be grateful for guidance.
When the sensor beam is blocked it returns a 0.
I use the following line of code to read the sensor status.
while (digitalRead(SENSOR1) == 1) {delay(50);}
or
while (digitalRead(SENSOR1) != 0) {delay(50);}
If the sensor returns a 0 (zero), the sketch moves on. This has always worked reliably for me but I now have a sensor that seems to get random zeros and the code moves on whether the input is a zero or not.
I have two of these sensors using identical code. One works well, the other doesn't. I've replaced the sensors (twice), replaced the cables, even replaced the Arduino Mega.
One of the sensors is connected to pin 12, the other to pin 13. If I swap the pins, the fault switches to the other sensor. This would indicate that the wiring and sensors are not the issue. Also, as the code is identical, it can't be the code.
If I reverse the code, ie
while (digitalRead(SENSOR1) == 0) {delay(50);}
the sensor works. (except that it's the opposite of what I want to achieve.
So, the question is, Is there a better way than using the while command?
I need the sensor to wait until the model tram passes, then move to the next bit of the sketch.
I appreciate that there's not much detail here and I may not have been sufficiently clear but I'm completely stuck as to why two identical sensors, with identical wiring and code, should behave differently. I'd be very grateful for some better way to read the sensor so that the sketch doesn't progress until the tram passes the sensor.
Many thanks
Thanks. I will attempt to edit the above to include the setup part of my code.
I have pulled out only the parts of the sketch that make these two sensors function as it's a big sketch.
// SERVO LIBRARY - loads servo control library
#include <Servo.h>
// ASSIGN PINS
int SENSOR2 = 13; // White
int SENSOR1 = 12; // yellow
void setup() {
Serial.begin(9600);
// INITIALISE PINS
pinMode(SENSOR2, INPUT_PULLUP);
pinMode(SENSOR1, INPUT_PULLUP);
}
//____________________________________ MAIN LOOP ______________________________________
void loop() {
// Checks HILLBOTTOM sensor - if SENSOR1 is HIGH, while loops until SENSOR2 goes low
Serial.println(digitalRead(SENSOR1));
while (digitalRead(SENSOR1) == 1) {delay(50);}
//<code here changes PWM duty cycle to increase average voltage>
// Checks HILLTOP sensor - SENSOR2 is HIGH, 'while' loops until SENSOR2 goes LOW
Serial.println(digitalRead(SENSOR2));
while (digitalRead(SENSOR2) == 1) {delay(50);}
//<code here changes PWM duty cycle to decrease average voltage>
}
Tram reaches bottom of hill and passes SENSOR1.
SENSOR1 goes LOW
increase average voltage to climb hill
Tram passes SENSOR2 at top of hill
SENSOR2 goes LOW
decrease average voltage
There's a whole lot more to this sketch involving servos, PWM module and relays. This all works fine.
SENSOR1 seems to mostly ignore its status.
SENSOR2 works fine.
If is swap the signal cables over (pin 12 & 13), the fault moves to the other sensor.
I have run a 'cut down' version of the sketch to ensure it's not other components or sections of code causing the issue.
Thank you.
I have included as much of the code as I dare below.
I can include the whole lot if required.
I agree with WHILE LOOPS being blocking. I don't really need to do other things in sequence as the sketch is a very linear process. However, a better and uncomplicated method would be much appreciated.
So here is a code-version with debug-printing
inside the while-loops the value of sensor 1 / sensor 2 gets printed only if the value changes
// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
// a detailed explanation how these macros work is given in this tutorial
// https://forum.arduino.cc/t/comfortable-serial-debug-output-short-to-write-fixed-text-name-and-content-of-any-variable-code-example/888298
#define dbg(myFixedText, variableName) \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName);
#define dbgi(myFixedText, variableName,timeInterval) \
{ \
static unsigned long intervalStartTime; \
if ( millis() - intervalStartTime >= timeInterval ){ \
intervalStartTime = millis(); \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName); \
} \
}
#define dbgc(myFixedText, variableName) \
{ \
static long lastState; \
if ( lastState != variableName ){ \
Serial.print( F(#myFixedText " " #variableName" changed from ") ); \
Serial.print(lastState); \
Serial.print( F(" to ") ); \
Serial.println(variableName); \
lastState = variableName; \
} \
}
#define dbgcf(myFixedText, variableName) \
{ \
static float lastState; \
if ( lastState != variableName ){ \
Serial.print( F(#myFixedText " " #variableName" changed from ") ); \
Serial.print(lastState); \
Serial.print( F(" to ") ); \
Serial.println(variableName); \
lastState = variableName; \
} \
}
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *
// SERVO LIBRARY - loads servo control library
#include <Servo.h>
// ASSIGN PINS
int SENSOR2 = 13; // White
int SENSOR1 = 12; // yellow
void setup() {
Serial.begin(115200);
while(!Serial); // wait for the serial interface to be ready
Serial.println( F("Setup-Start") );
PrintFileNameDateTime();
// INITIALISE PINS
pinMode(SENSOR2, INPUT_PULLUP);
pinMode(SENSOR1, INPUT_PULLUP);
Serial.println( F("leaving setup()") );
}
//____________________________________ MAIN LOOP ______________________________________
void loop() {
// Checks HILLBOTTOM sensor - if SENSOR1 is HIGH, while loops until SENSOR2 goes low
//Serial.println(digitalRead(SENSOR1));
while (digitalRead(SENSOR1) == 1) {
dbgc("01",digitalRead(SENSOR1) );
dbgc("02",digitalRead(SENSOR2) );
delay(50);
}
//<code here changes PWM duty cycle to increase average voltage>
// if you would post this code more debug-printing could be added
// which would enable a more detailed analysis
// Checks HILLTOP sensor - SENSOR2 is HIGH, 'while' loops until SENSOR2 goes LOW
// Serial.println(digitalRead(SENSOR2));
while (digitalRead(SENSOR2) == 1) {
dbgc("01",digitalRead(SENSOR1) );
dbgc("02",digitalRead(SENSOR2) );
delay(50);
}
//<code here changes PWM duty cycle to decrease average voltage>
// if you would post this code more debug-printing could be added
// which would enable a more detailed analysis
}
void PrintFileNameDateTime() {
Serial.println( F("Code running comes from file ") );
Serial.println( F(__FILE__) );
Serial.print( F(" compiled ") );
Serial.print( F(__DATE__) );
Serial.print( F(" ") );
Serial.println( F(__TIME__) );
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
unsigned long MyTestTimer = 0; // Timer-variables MUST be of type unsigned long
const byte OnBoard_LED = 2;
void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
static unsigned long MyBlinkTimer;
pinMode(IO_Pin, OUTPUT);
if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
}
}
change the baudrate in the serial monitor to the modern value 115200
and then flash this code-version into your arduino-uno
post what you get printed in the serial monitor
If you use the inbuilt LED for anything, this also uses pin D13 on the Mega2560.
So if you are setting the LED on or off for any reason, that is also changing the digitalRead value of that pin independently of the sensor operation.
It will be stressing the digitalwrite components of the Mega and stressing the output components of the sensor.
Pin D13 also has a resistor 1k resistor in series with the LED to ground (0v) so this relatively strong pulldown could even affect your sensor output, even if you are not driving the LED on or off in the sketch.
Just try another pin, like D11.
If that doesn't work --
The weak INPUT_PULLUP may be insufficient in this application.
Supplement that with a 10kΩ resistor (this will pull it up harder).
Thank you. So, would you place the resistor in series within the sensor signal cable?
I'm still puzzled as to why on sensor works well and the other doesn't. It's the one on pin 12 that's problematic. I have tried using other pins.
Best method for analysing such problems is to use a digital storage oscilloscope
But this is an investment of $200 to $500
Not worth to solve a single problem.
another way is the debug-printing.
So simply upload my code-version and look into the serial monitor