Hi, I hope I'm posting this in the right place but I can't really put my finger on where this issue is happening. I'm still a beginner with this stuff so apologies if I've made any mistakes. Would appreciate suggestions
I'm trying to build a capacitive touch based directional padlock (i.e. N S E W based combination). Youtube tutorial link: No more Directional Locks.... could this be the end for Escape Rooms?! - YouTube. Code at bottom of post.
However! I was struggling to not get the cap touch modules not to constantly trigger when simply touching wood, metal, whatever I glued them to, so instead I devised a workaround using an ESP32 with the cap touch function to detect when some copper contacts connected to some touch pins had been touched and send a 100ms HIGH pulse to my arduino "NSEW pins".
The circuit looks like this
Code here:
int nPin = 17;
int sPin = 2;
int ePin = 0;
int wPin = 5;
int nBef = 0;
int sBef = 0;
int eBef = 0;
int wBef = 0;
int nAft;
int sAft;
int eAft;
int wAft;
int tol = 30;
void setup()
{
Serial.begin(115200);
delay(5000); // give me time to bring up serial monitor
Serial.println ("MUTINY ESP32 NSEW TOUCH PIN CODE");
Serial.print ("PIN");
Serial.print ("\t");
Serial.print ("BefVal");
Serial.print ("\t");
Serial.println ("AftVal");
pinMode (nPin, OUTPUT);
pinMode (sPin, OUTPUT);
pinMode (ePin, OUTPUT);
pinMode (wPin, OUTPUT);
digitalWrite (nPin, LOW);
digitalWrite (sPin, LOW);
digitalWrite (ePin, LOW);
digitalWrite (wPin, LOW);
}
void loop()
{
nAft = touchRead(T0); // GPOI 4
sAft = touchRead(T3); // GPOI 15
eAft = touchRead(T8); // GPOI 33
wAft = touchRead(T9); // GPOI 32
Serial.print ("nTouch");
Serial.print ("\t");
Serial.print (nBef);
Serial.print ("\t");
Serial.println (nAft);
Serial.print ("sTouch");
Serial.print ("\t");
Serial.print (sBef);
Serial.print ("\t");
Serial.println (sAft);
Serial.print ("eTouch");
Serial.print ("\t");
Serial.print (eBef);
Serial.print ("\t");
Serial.println (eAft);
Serial.print ("wTouch");
Serial.print ("\t");
Serial.print (wBef);
Serial.print ("\t");
Serial.println (wAft);
Serial.println ();
if ((nBef > tol) && (nAft < tol)) {
Serial.println ("North (green) trigger");
digitalWrite (nPin, HIGH);
delay (100);
digitalWrite (nPin, LOW);
Serial.println ();
}
if ((sBef > tol) && (sAft < tol)) {
Serial.println ("South (blue) trigger");
digitalWrite (sPin, HIGH);
delay (100);
digitalWrite (sPin, LOW);
Serial.println ();
}
if ((eBef > tol) && (eAft < tol)) {
Serial.println ("East (yellow) trigger");
digitalWrite (ePin, HIGH);
delay (100);
digitalWrite (ePin, LOW);
Serial.println ();
}
if ((wBef > tol) && (wAft < tol)) {
Serial.println ("West (white) trigger");
digitalWrite (wPin, HIGH);
delay (100);
digitalWrite (wPin, LOW);
Serial.println ();
delay(1000);
}
nBef = nAft;
sBef = sAft;
eBef = eAft;
wBef = wAft;
delay(100);
}
The esp reads the 4 touch pins, every loop, and if it detects that the new touch read is low and the previous read is high (copper contact is being touched), it sends a 200ms high pulse to the Arduino pins A0-A3
I tested this with 4 LEDs and the 100ms high pulse is being sent, it lit the correct disparate LEDs in a way I would expect. It seems THIS code is working.
However, when the output pins are hooked up to the arduino running the code attached at the bottom of this post, there's random behaviour. When a copper contact is touched, the serial monitor on my Arduino tells me it is detecting voltage at three random pins consecutively. Really weird, this was shown after pressing the Up contact.
What I'm expecting the monitor to dispay is simply "Step:0 Input:U - Correct!" but this is telling me when the pulse is detected it also detects a bunch of other pins being triggered
I had expected the 200ms pulse , along with the INPUT_PULLUP function to be read by a single pin on the Arduino and trigger the mp3 soundbites etc.
The only thing I could think of is that even though I've programmed my esp to only send a voltage to a single pin on contact touch, there may be some interference or small voltage being applied to other pins. This voltage might be very small, hence, it didn't trigger my 4x LED troubleshooting setup.
Another error could be that the 200ms pulse and the cap touch modules the video do not behave in a way that is comparable and my "workaround" using the ESP32 is not going to make the code work as intended.
Current troubleshooting things ive tried, will update with any suggestions people make:
- Increasing the delay on trigger to 200ms, no change
- Slowing down the code by adding a 100ms delay once the arduino detected an input, no change.
- Swapping out for a new arduino (but not a new ESP)
Code on arduino:
#include <AltSoftSerial.h>
#include <Wire.h>
#include <MD_YX5300.h>
/**
* Electronic Direction Lock
*
* Players must enter the correct sequence of directional input (i.e. U/D/L/R or N/E/S/W)
* to activate a relay, releasing a maglock or some other output.
*
* The script demonstrates various customisable behaviour:
* - The correct input sequence may be of any length
* - Each direction entered may be accompanied by audio or visual feedback to confirm input was registered
* - Directions may be entered using pushbuttons, touch sensors, or any other momentary inputs arranged in 4-way cardinal directions
* - Relay may either unlock automatically as soon as the last direction in the sequence is entered,
* or players may have to explicity press a "submit" button to submit their input
* - Sequence of directions input may optionally be displayed on an LCD screen
*/
// DEFINES
// If AUTOCHECK is defined, the sequence entered by the player will be automatically checked
// against the correct solution after every direction input, and will trigger the relay as soon
// as the last direction is correctly input.
// Otherwise, players must manually press a "submit" button to check the combination entered
#define AUTOCHECK
// If USE_AUDIO is defined, a command is sent via software serial interface to play a sound effect
// on a connected YX5300 serial MP3 player board when an input is received, and when the correct sequence
// is input. If SFX are not required and no audio player is connected, we exclude the audio code to
// prevent the script waiting for an acknowledgement from the sound player that will never be sent
#define USE_AUDIO
// INCLUDES
// For debouncing button input. See https://github.com/thomasfredericks/Bounce2
#include <Bounce2.h>
// CONSTANTS
// Enumerate each of the possible directional inputs
enum Dir {Down, Right, Up, Left};
// Also create descriptive names (for debugging/visual display)
const char* dirStr[] = {"D", "R", "U", "L"};
// Specify the Arduino GPIO pins to which those directional buttons are attached
const byte dirPins[4] = {A0,A1,A2,A3};
// This pin is driven low when correct sequence entered
const byte relayPin = 2;
// The number of directional steps in the solution
const int numSteps = 8;
// The correct sequence of directions that players must enter
const byte correctSequence[numSteps] = {Up, Up, Down, Down, Left, Right, Left, Right};
// GLOBALS
// Create an array of Bounce objects for each input button
Bounce dirSwitches[4] = {Bounce(), Bounce(), Bounce(), Bounce()};
// What step of the sequence is the player currently on?
int currentStep = 0;
#ifdef USE_AUDIO
// Initialise a software serial interface on the approriate Rx/Tx pins (8/9)
AltSoftSerial altSerial;
// And create an MP3 object based on the serial connection
MD_YX5300 mp3(altSerial);
#endif
// Is the sequence of inputs the player entered correct so far?
bool inputCorrect = true;
void setup() {
// Initialise a serial connection (used for debugging only)
Serial.begin(115200);
Serial.println(__FILE__ __DATE__);
// Attach a debouncer to every direction switch
for(int i=0; i<4; i++){
dirSwitches[i].attach(dirPins[i], INPUT_PULLUP);}
// Initialise the output pin
pinMode(relayPin, OUTPUT);
digitalWrite(relayPin, HIGH);
#ifdef USE_AUDIO
// Initialise the serial interface to the MP3 player
altSerial.begin(9600);
mp3.begin();
// Volume is a value from 0-30
mp3.volume(30);
#endif
}
void loop() {
// Loop through all the inputs
for(int i=0; i<4; i++){
// Update the state of this switch
dirSwitches[i].update();
// ...has it just been pressed?
if(dirSwitches[i].rose()){
#ifdef USE_AUDIO
// Play the first sound effect on the SD card (i.e. "001.mp3")
mp3.playTrack(1);
#endif
// Print some debug information
Serial.print(F("Step:"));
Serial.print(currentStep);
Serial.print(F(" Input:"));
Serial.print(dirStr[i]);
// If this input was the correct next value in the sequence
if(i == correctSequence[currentStep]){
// Debug only
Serial.println(F(" - Correct!"));
}
// If the direction entered was incorrect
else {
// Set flag that user has made at least one incorrect entry in the sequence
inputCorrect = false;
// Debug only
Serial.print(F(" - Incorrect!"));
if(currentStep < numSteps){
Serial.print(F(" Should have been "));
Serial.println(dirStr[correctSequence[currentStep]]);
}
else {
Serial.println(F(" Sequence too long."));
}
}
// Continue to the next element of the sequence
currentStep++;
// If autocheck is enabled, we check the sequence entered and unlock
// as soon as the final input is entered
#ifdef AUTOCHECK
if(currentStep == numSteps){
if(inputCorrect){
onSolve();
}
else {
onFailure();
}
}
#endif
}
}
}
// This function is called when players submit the correct sequence of directions
void onSolve() {
// Debug
Serial.println("Solved!");
#ifdef USE_AUDIO
// Play the second sound effect on the SD card (i.e. "002.mp3")
mp3.playTrack(2);
#endif
// Release the maglock
digitalWrite(relayPin, LOW);
delay(5000);
digitalWrite(relayPin, HIGH);
// And reset the controller
currentStep = 0;
inputCorrect = true;
}
// This function is called when player's submit an incorrect sequence of directions
void onFailure() {
// Debug
Serial.println("Incorrect!");
#ifdef USE_AUDIO
// Play the third sound effect on the SD card (i.e. "003.mp3")
mp3.playTrack(3);
#endif
delay(2000);
// And reset the controller
currentStep = 0;
inputCorrect = true;
}