1
\$\begingroup\$

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:

  1. The RFID reader reads a valid tag, the NFC Servo should rotate from 0 to 90 degrees and stay there.
  2. The user clicks a button.
  3. The Dispenser Servo starts at 160 degrees, then 180 degrees, then 30 degrees, and then back to 160 degrees.
  4. 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:

Simplfied Fritzing sketch

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):

  1. Making sure with delays that the servos don't run simultaneously.
  2. Detaching each servo after it's done with its task.
  3. 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!

\$\endgroup\$
  • 1
    \$\begingroup\$ That has to be wrong. You have the servo PWM inputs connected to the analog inputs of the Arduino. Don't see how that could work at all. Check and see if the communication with the NFC thing uses the same interrupt or timer as the servo controller. And make sure you aren't sharing a digital pin between a servo and the NFC. And, post a circuit diagram instead of yhat wiring diagram. \$\endgroup\$ – JRE Jul 17 '18 at 15:09
  • 1
    \$\begingroup\$ Thanks for the reply! To be honest, I was also surprised to see that it works with the analog pins, but it does indeed work. But I have tried it myself multiple times, and this thread also acknowledges it: forum.arduino.cc/index.php?topic=500215.0 Not sure what you mean by Servo controller. Do you mean a shield or the like, because I am not using anything like that. I am controlling them directly from the Uno. As for the NFC reader, it runs on SPI, so shouldn't interfere with the servos. They also don't share a digital pin. What program can I use to create circuit diagrams? \$\endgroup\$ – jepster Jul 17 '18 at 16:39
  • \$\begingroup\$ I mean the object of type "Servo" that you use in your code. It has to use a timer or something in the background to generate the PWM for the servo. \$\endgroup\$ – JRE Jul 17 '18 at 16:43
  • \$\begingroup\$ Fritzing should be able to make circuit diagrams. Otherwise, try Kicad \$\endgroup\$ – JRE Jul 17 '18 at 16:44
  • \$\begingroup\$ Every time I see "delay" used that way it makes me cringe... (especially when it follows the "return"). Why don't you make a simple state machine controlled by one timer? Anyway, re your actual problem: check that servo can actually reach end positions without hitting mechanical limit and staying there heating up. Also a good way to diagnose is to get rid of everything else. Put closeNFCServo, openNFCServo in main loop and see if it moves for extended time while there is no other communication going on. \$\endgroup\$ – Maple Jul 18 '18 at 6:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.