I have looked, Googled and researched all over by now and I have not been able to find anyone experiencing a similar issue to mine, so I thought now would be the time to ask my own question on SE.
If working properly, my circuit would do the following:
- The RFID reader reads a valid tag, the NFC Servo should rotate from 0 to 90 degrees and stay there.
- The user clicks a button.
- The Dispenser Servo starts at 160 degrees, then 180 degrees, then 30 degrees, and then back to 160 degrees.
- The NFC Servo goes back to 0 degrees.
However, what happens occasionally is that the NFC Servo jitters on its way back to 0, and then the next time an RFID tag is read, it will rotate to what looks like 180 or maybe more. After this, the Arduino is no longer capable of signalling to the NFC Servo, but the Dispenser Servo continues to work fine, as does the RFID Reader. Resetting the Arduino by pushing the Reset button re-establishes the connection to the NFC Servo so it works a couple of times, but it always ends up freezing before long.
The entire circuit includes an Arduino Uno R3, an Ethernet shield, two servos, one RFID reader, 2 buttons with built-in LED, and 4 white LEDs. I don't think the buttons or the LEDs are the issue, so in order to not overload you kind people with information, this is a simplified Fritzing sketch of the circuit:
Likewise, this is a simplified version of the Arduino code:
// Includes
#include <SPI.h>
#include <MFRC522.h>
#include <Ethernet.h>
#include <Servo.h>
// Ethernet variables
static uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x01 };
static uint8_t myip[] = { 10, 0, 0, 200 };
IPAddress pc_server(10,0,0,31); // The address to send to via Ethernet
EthernetClient client;
// RFID variables
#define RST_PIN 9
#define SS_PIN 8
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
boolean cardPresent = false;
boolean cardPresent_old = false;
String cardID = "";
String cardID_old = "";
// Servo variables
Servo servoNFC;
Servo servoDispenser;
#define servoNFCPin A2
#define servoDispenserPin A4
// Positions for the Servos in angles
int posNFC = 0;
int posNFCClosed = 90;
int posDispenser = 160;
// System variables
boolean hasReadNFC = false;
boolean hasDispensed = false;
String languageChosen = "";
void setup() {
Serial.begin(9600);
SPI.begin();
mfrc522.PCD_Init(); // Init MFRC522 (RFID reader)
Ethernet.begin(mac, myip);
delay(5000); // wait for Ethernet card
activateEthernetSPI(false);
// Attach servos
servoNFC.attach(servoNFCPin);
servoDispenser.attach(servoDispenserPin);
servoNFC.write(posNFC);
servoDispenser.write(posDispenser);
// Ready to start
Serial.println("Ready");
}
void loop() {
// PHASE 1 : Check for a token
if (!hasReadNFC) {
checkForNFC();
}
// PHASE 2 : check for button presses
// Omitted for simplification
// PHASE 3 : Dispense with servo
if (hasReadNFC) {
dispense();
printDiagnosis();
}
}
// CHECKS FOR A PRESENTED NFC TAG (TOKEN)
void checkForNFC() {
if(cardPresent) {
if ( mfrc522.PICC_ReadCardSerial()) {
getID();
}
hasReadNFC = true;
delay(500);
closeNFCServo(); // Close NFC coin slot
}
if ( mfrc522.PICC_ReadCardSerial()) {
getID();
}
cardPresent_old = cardPresent;
if ( ! mfrc522.PICC_IsNewCardPresent()) {
cardPresent = false;
return;
delay(10);
}
cardPresent = true;
delay(10);
}
// DISPENSES WITH SERVODISPENSER
void dispense() {
servoDispenser.write(160);
delay(2000);
servoDispenser.write(180);
delay(500);
servoDispenser.write(30);
delay(2000);
servoDispenser.write(160);
hasDispensedPill = true;
}
// PRINT RECEIPT
void printReceipt() {
Serial.println("Printing");
submitData();
}
// RESET THE SYSTEM
void resetSystem() {
hasReadNFC = false;
hasDispensed = false;
openNFCServo();
}
void submitData() {
activateEthernetSPI(true);
String datastring = "GET /machine//readval.php?tag=" + String(cardID) + " HTTP/1.0";
if(client.connect(pc_server,80)) {
client.println(datastring);
client.println("Connection: close");
client.println();
client.stop();
delay(100);
}
activateEthernetSPI(false);
resetSystem();
}
void activateEthernetSPI(boolean x) {
// change SPI/Slave... turn RFID shield off, ethernet on (LOW=on)
// http://tronixstuff.com/2011/05/13/tutorial-arduino-and-the-spi-bus/
digitalWrite(SS_PIN,x);
digitalWrite(10,!x);
}
void closeNFCServo() {
for (posNFC = 0; posNFC <= posNFCClosed; posNFC += 1) {
servoNFC.write(posNFC);
delay(10);
}
return;
}
void openNFCServo() {
for (posNFC = posNFCClosed; posNFC >= 0; posNFC -= 1) {
servoNFC.write(posNFC);
delay(10);
}
return;
}
void getID() {
String cardIDtmp = "";
for (byte i = 0; i < 3; i++) {
byte tmp = (mfrc522.uid.uidByte[i]);
cardIDtmp.concat(tmp);
}
// has ID changed?
if (cardIDtmp != cardID_old) {
cardID = cardIDtmp;
cardID_old = cardID;
}
}
I have already tried(without success):
- Making sure with delays that the servos don't run simultaneously.
- Detaching each servo after it's done with its task.
- Replacing the NFC Servo
Currently I am considering forcing the Arduino to reset itself via software (using the watchdog timer or the asm volatile (" jmp 0");
trick) after each iteration, but it's a bit of a messy fix, so I'd definitely prefer something more reliable.
I'm at my wits end, so I truly hope one of you have had a similar issue!