2

I am trying to use the arduino yun to output the number of parts a machine has produced to a google spreadsheet. With the setup I have, I am able to output data to the spreadsheet temporarily. However, after some time, the yun stops working. The red LED I have on to indicate the code is running turns off, and I can no longer see the arduino in the port list. A reset of the 32u4 chip causes the LED to turn back on, indicating the code is running, but the board still does not appear in the port menu.

I have tested it at our workshop and it has run for 7-12 hours with no problems at all. It is only when we take it on to the production floor that we start experiencing these problems. Does anyone have any idea what the issue could be? Here is the most relevant part of the code:

#include <elapsedMillis.h>
#include <Process.h>
#include <Bridge.h>
#include "TimeLib.h"

// On Arduino:  0 - 1023 maps to 0 - 5 voltsf
#define VOLTAGE_MAX 5.0
#define VOLTAGE_MAXCOUNTS 1023.0

unsigned int buttonCount = 0;
float voltage = 0;
elapsedMillis timeSinceLastCycle = 0;
elapsedMillis transmitData = 0;
int pressFlag = 0;
Process date;
int hours, minutes, seconds;
int lastSecond = -1;
Process sendData;

String printDate() {

  // String currTime = String(hours) + ":" + String(minutes) + ":" + String(seconds);

  if (lastSecond != seconds) { // if a second has passed
    // print the time:
    if (hours <= 9) {
      Console.print("0");  // adjust for 0-9
    }
    Console.print(hours);
    Console.print(":");
    if (minutes <= 9) {
      Console.print("0");  // adjust for 0-9
    }
    Console.print(minutes);
    Console.print(":");
    if (seconds <= 9) {
      Console.print("0");  // adjust for 0-9
    }
    Console.println(seconds);

    // restart the date process:
    if (!date.running()) {
      date.begin("date");
      date.addParameter("+%T");
      date.run();
    }
  }

  //if there's a result from the date process, parse it:
  while (date.available() > 0) {
    // get the result of the date process (should be hh:mm:ss):
    String timeString = date.readString();

    // find the colons:
    int firstColon = timeString.indexOf(":");
    int secondColon = timeString.lastIndexOf(":");

    // get the substrings for hour, minute second:
    String hourString = timeString.substring(0, firstColon);
    String minString = timeString.substring(firstColon + 1, secondColon);
    String secString = timeString.substring(secondColon + 1);


    // convert to ints,saving the previous second:
    hours = hourString.toInt();
    minutes = minString.toInt();
    lastSecond = seconds;          // save to do a time comparison
    seconds = secString.toInt();
    String currTime = hourString + ":" + minString + ":" + String(seconds);
    return currTime;
  }
}

void checkVoltage() {

  int sensorValue = analogRead(A0);
  voltage = sensorValue * (VOLTAGE_MAX / VOLTAGE_MAXCOUNTS);

  Console.println(voltage);
  delay(50);
  if (voltage >= 4.9 && pressFlag == 0) {

    Console.println("Delaying");
    sensorValue = analogRead(A0);
    voltage = sensorValue * (VOLTAGE_MAX / VOLTAGE_MAXCOUNTS);

    if (pressFlag == 0 && voltage >= 4.9) {

      unsigned long int intCycleTime = timeSinceLastCycle;
      timeSinceLastCycle = 0;
      digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (HIGH is the voltage level)

      printDate();
      String pressTime = printDate();

      Console.print("PressTime is ");
      Console.println(pressTime);

      buttonCount++;
      Console.println(buttonCount);

      pressFlag = 1;



      String part1 = "curl -X POST -H \"Content-Type: application/json\" -d '{\"value1\":\"";
      String timeString = pressTime;
      Console.print(timeString + " seconds");
      String part2 = "\",\"value2\":\"";
      String numParts = String(buttonCount);
      String part3 = "\",\"value3\":\"";
      String strCycleTime = String(intCycleTime / 1000); // + " seconds";
      String part4 = "\"}' https://maker.ifttt.com/trigger/arduino2Request/with/key/gL8YmxeaUChOMJvmwpdXp -k";
      //curl -X POST -H "Content-Type: application/json" -d '{"value1":"1","value2":"2","value3":"3"}' https://maker.ifttt.com/trigger/arduino2Request/with/key/gL8YmxeaUChOMJvmwpdXp

      String curlString = part1 + timeString + part2 + numParts + part3 + strCycleTime + part4;

      // The curl string sends data to oue excel spreadhsheet using the IFTTT web service

      sendData.runShellCommandAsynchronously(curlString);

      elapsedMillis breakTimer = 0;
      /*while(sendData.running()){

          if(breakTimer > 5*1000){
            break;
          }
        } */


      Console.print("Data Available: "); // A value of 32 indicates a successful transmission of data, 0 also works if run asynchronously.
      Console.println(sendData.available());

      digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)

    }

  }
  else if (voltage < 2.5) {
    pressFlag = 0;
  }

}

void setup() {

  Bridge.begin();
  Console.begin();
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)

  // run an initial date process. Should return:
  // hh:mm:ss :
  if (!date.running()) {
    date.begin("date");
    date.addParameter("+%T");
    date.run();
  }
}

void loop() {

  checkVoltage();

  if ((timeSinceLastCycle > 300000) && (transmitData > 300000)) { // If 5 minutes have elapsed without a part being produced, output that the arduino is transmitting even if not part is available
    sendData.runShellCommand("curl -X POST -H \"Content-Type: application/json\" -d '{\"value1\":\"1\",\"value2\":\"Arduino Transmitting\"}' https://maker.ifttt.com/trigger/transmitData/with/key/gKRo-zSur5rj6rD5rviCaV2RHI5g56Dy0Vc0S_XJ-oO -k");
    transmitData = 0;
  }
}

UPDATE: I added a series of print statements to the checkVoltage function. The code above has been updated to reflect this. I found that it hung when trying to use sendData.runShellCommandAsynchronously. The output looks like

1.58
1.54
5.00
Delaying
PressTime is n" -d 
3

Could the network connection cutting out when trying to runShellCommand cause this issue?

MacMixer13
  • 73
  • 1
  • 8
  • One of the things I can see to go wrong over time is `buttonCount` overflow. Anyway, the code is incomplete. – Eugene Sh. Feb 24 '17 at 17:48
  • The thing is, it fails quite a while before overflow would become an issue. In addition, I am not concerned about the exact value of buttonCount, as my data processing script only checks to see if there is a number and tallies the entries again itself. This prevents miscounts when the machine powers down for a brief period and the value resets to 0. I have updated the code to include the complete code. – MacMixer13 Feb 24 '17 at 18:34
  • There are some noticeable gaps, particularly in the printDate function, due to where I previously had print statements. I took them out hoping that shrinking the code would fix my issue but no luck – MacMixer13 Feb 24 '17 at 18:40
  • 1
    I love this question. How many items did you test this with in your workshop, compared with the production line? The first thing I would check is *dynamic memory*, which is implicitly used by `String` and its `+` operator. You could use, much more efficiently, a single statically-allocated char[] buffer in flash memory + `sprintf()` + single format string stored in *PROGMEM* (see: [this](https://learn.adafruit.com/memories-of-an-arduino/optimizing-sram)). You can pretty easily compute the max length of your command using stored value limits. – Patrick Trentin Feb 25 '17 at 02:27
  • 1
    The signature for `printDate()` says it returns a `char *`, However, there is a path through the code that does not return anything. (when the `while()` is not entered. The compiler should have complained. When compiling, always enable all the warnings, then fix those warnings. (for `gcc`, at a minimum use: `-Wall -Wextra -pedantic` I also use: `-Wconversion -std=gnu99` ) – user3629249 Feb 25 '17 at 10:41
  • We tested about twice the number of entries in our workshop vs out in the field, so I don't think it was a case of overworking the arduino or anything like that. Thank you both for your suggestions, I will give them a try next time I take a look at the code. For now I found a workaround. I use a watchdog timer to detect if the code is hanging or not, and reset the board if it is. Because both of the boards are currently in use on the production floor I cannot test your suggestions, but if more boards are deployed I will test both of your theories and report back. Thank you for your help! – MacMixer13 Feb 27 '17 at 15:07

1 Answers1

1

So after following user3629249's solution, this issue appears to be resolved. Have now had multiple weeks of error free runtime. user3629249, if you want to repost your advice as an answer, I will accept it. Thank you to user3629249 and Patrick Trentin for your help!

My update ProcessDate function now contains:

if(date.available() >0){
  while (date.available() > 0) {
  // get the result of the date process (should be hh:mm:ss):
  String timeString = date.readString();

  // find the colons:
  int firstColon = timeString.indexOf(":");
  int secondColon = timeString.lastIndexOf(":");

  // get the substrings for hour, minute second:
  String hourString = timeString.substring(0, firstColon);
  String minString = timeString.substring(firstColon + 1, secondColon);
  String secString = timeString.substring(secondColon + 1);


  // convert to ints,saving the previous second:
  lastSecond = seconds;          // save to do a time comparison
  lastMinute = minutes;
  lastHour = hours;
  hours = hourString.toInt();
  minutes = minString.toInt();
  seconds = secString.toInt();
  String currTime = hourString + ":" + minString + ":" + String(seconds);
  return currTime;
} 
else{
        String currTime = ""; // If there is no result from the date process, return nothing. Should not happen.
        return currTime;
      }
    }
MacMixer13
  • 73
  • 1
  • 8