Arduino Uno intermittently stops writing to serial buffer

EDIT: solution found - see Arduino Uno intermittently stops writing to serial buffer - #9 by system - Interfacing w/ Software on the Computer - Arduino Forum

I'm using my Uno to control a stepper motor (with an EasyDriver) and a relay to control a valve.

The code below waits for me to send a single byte over serial then sends back a message to confirm that it's executed the command.

Here's the code:

// parameters
const int stepsPerRev = 200; // depends on stepper
const int microstepsPerStep = 8; // depends on EasyDriver
const float degreesPerRev = 360; // 360 deg per revolution
float microstepsPerDeg = (stepsPerRev * microstepsPerStep) /degreesPerRev; // 4.44 microsteps/degree
int numberVials = 8; // number of vials on sampler

// setup pins
#define DIR_PIN 2
#define STEP_PIN 3
#define RELAY_PIN 7
byte cmd;

void setup()
{
  Serial.begin(9600);
  pinMode(DIR_PIN, OUTPUT); 
  pinMode(STEP_PIN, OUTPUT);
  pinMode(RELAY_PIN, OUTPUT);
}

void loop()
{
  if (Serial.available()) {
      cmd = Serial.read();
      parsecommand(cmd);
  } 
}

void parsecommand(int cmd) {
    switch (cmd) 
    {
    case 48: // 0: switch valve off
      {
        digitalWrite(RELAY_PIN, LOW); 
        Serial.println("off");
        break;
      }
    case 49: // 1: switch valve on
      {
        digitalWrite(RELAY_PIN, HIGH);
        Serial.println("on");
//        Serial.flush();
        break;
      }
    case 50: // 2: advance one position
      {
        float degreesToMove = (360/numberVials);
        rotateDeg(degreesToMove);
        Serial.println("moved");
        break;
      }
    case 63: // ?: check arduino status 
      {
        Serial.println("ready");
        break;
      }
    default:
      {
        Serial.println("error");
      }
    }
}

void rotateSteps(int microsteps){ 
  //rotate a specific number of microsteps (8 microsteps per step)
  // (negitive for reverse movement)
  int dir = (microsteps > 0)? HIGH:LOW;
  digitalWrite(DIR_PIN,dir); 

  microsteps = abs(microsteps);
  float usDelay = 1400;

  for (int i=0; i < microsteps; i++)
  { 
    digitalWrite(STEP_PIN, HIGH); 
    delayMicroseconds(usDelay); 

    digitalWrite(STEP_PIN, LOW); 
    delayMicroseconds(usDelay); 
  }
} 

void rotateDeg(float deg) {
  float microstepsToMove = microstepsPerDeg * deg;
  int microstepsToMoveInt; // need to round to the nearaest integer

  if (microstepsToMove > 0.0) {
    microstepsToMoveInt = floor(microstepsToMove + 0.5);
  } 
  else {
    microstepsToMoveInt = ceil(microstepsToMove - 0.5);
  }

  rotateSteps(microstepsToMoveInt);
}

I'm talking to the Arduino with MATLAB r2013a on Windows 7. I send the command, wait a second, then see how many bytes are available. I then check again, and if the number of bytes hasn't changed and is non-zero, the buffer is read.

But the problem I'm having is that the Arduino seems to randomly stop writing to the serial buffer. 0 bytes are available. However, I can carry on sending commands from MATLAB and the Arduino moves the stepper/opens/closes the valve. It just doesn't write back and I need to know that the command has happened.

I only get this problem on Windows 7. I've tried it on Windows XP and Mac 10.8.3 with various versions of MATLAB and I can't reproduce the bug. I've also rewritten the serial code with Python and, again, only have this trouble on Windows 7.

Does anyone have any advice? I'm at my wit's end trying to fix this.

(Please note that I've cut the jumper on the board to prevent the Arduino reseting on serial connections, otherwise the valve turns to its default off state whenever I connect).

MATLAB code is:

function autosampler(cmd)

if ispc == true
    port = 'COM3';
elseif ismac == true
    port = '/dev/tty.usbmodemfa131';
end

s = serial(port);
s.baudrate = 9600;
s.terminator = '';


    fopen(s);
    fprintf(s,cmd);
    
    cont = false;
    while cont == false
        % short pause, then check the number of bytes available
        pause(0.5)
        q1 = s.bytesavailable();
        
        if q1 == 0                      % no bytes available
            cont = false;               % restart loop
        elseif q1 > 0                   % bytes available
            pause(0.1)                  % wait
            q2 = s.bytesavailable();    % check again
            
            if q1 == q2                 % same number of bytes as last time?
                cont = true;            % exit loop
            else
                cont = false;           % continue loop
            end
        end
    end
    
    response = fread(s,q2);
    
    % convert from ASCII codes. Don't include the [13 10] at end.
    response = char(response(1:(end-2))');
    
    % print with timestamp
    fprintf('%s: %s\n',datestr(now),response)
    
    fclose(s)


end

I wonder if the problem might be caused by opening and closing the serial port for each command. I would try keeping the serial port open and keeping the rest of the code as-is.

johnwasser:
I wonder if the problem might be caused by opening and closing the serial port for each command. I would try keeping the serial port open and keeping the rest of the code as-is.

I actually used to do it like this. Unfortunately I can't remember why I switched to opening/closing like I am now... I'll give it a go again now.

If anyone else has any suggestions, please do post them.

Here's my MATLAB script. The idea is the Arduino cycles through opening the valve, waiting for a preset time, closes the valve, then moves the stepper. This is repeated several times.

clear
clc

s = serial('COM3')
s.baudrate = 9600;
s.terminator = '';

fopen(s)

cmd = repmat([1 0 2],1,7)

for i = 1:length(cmd)

    i
    
    if cmd(i) == 0
        fprintf('%s: pausing\n',datestr(now))
        pause(480)
    end
 
    fprintf(s,num2str(cmd(i)))
    
    cont = false;
    iter = 0;
    
    while (cont == false)
        
        % sometimes it gets stuck in a loop forever
        iter = iter + 1
        if iter == 100
            fclose(s)
            error('Too many iterations')
            break;
        end
        
        % short pause, then check the number of bytes available
        pause(0.5)
        q1 = s.bytesavailable()
        
        if q1 == 0                  % no bytes available
            cont = false            % restart loop
        elseif q1 > 0              % bytes available
            pause(0.5)              % wait
            q2 = s.bytesavailable() % check again
            
            if q1 == q2             % same number of bytes as last time?
               cont = true          % exit loop
            else
                cont = false        % continue loop
            end
        end
    end
  
    response = fread(s,q2)
    char(response')
end

fclose(s)

Unfortunately it gave the following error on the 11th iteration after the pause.

Error using serial/fprintf (line 144)
Unexpected Error: An error occurred during writing.

Error in jdmlab9_test_noclose (line 21)
    fprintf(s,num2str(cmd(i)))

Line 144 is the second to last line here:

% Call the fprintf java method.
try
   fprintf(igetfield(obj, 'jobject'), formattedCmd, mode);
catch aException
   error(message('MATLAB:serial:fprintf:opfailed', aException.message));
end

Any ideas?

    i

What does this do?

PaulS - it just prints the current value of i to the command prompt in MATLAB. It's there so I know what iteration of the loop the script is currently on.

EDIT 2: Spoke too soon - cryptic error again.

--

I'm beginning to think this may be a Java related bug.

I made the attached LabVIEW VI to control the Arduino. As far as I know, LabVIEW doesn't use Java. No errors - it works fine.

MATLAB on the otherhand does use Java. Arduino uses Java, right?

Edit: last frame of the structure just adds a pause after one of the commands. I want the Arduino to not do anything once the valve has been shut for a predetermined time.

labviewvi.tiff (48.5 KB)

error.tiff (18.4 KB)

I was having a similar problem, where the Uno worked without issue with my XP system, but then when I move the project to another room and hooked it up to a Windows 7 system, it would just stop communicating on the USB serial 5-10 minutes after the program started.

I tried a bunch of different things, including switching USB cables, flashing the USB/Serial chip, and connecting it to linux laptop, but the problem kept occurring. Eventually it occurred to me that the other USB devices connected (keyboard, mouse) could be causing the issue.

I brought the keyboard/mouse from my XP system and hooked them up to the Win7 system, and haven't had any further issues.

I found the source of this problem and thought I should post the solution here.

Turns out it was all down to the relay. I was using a mechanical relay (http://www.hobbytronics.co.uk/5v-relay-module?keyword=RELAY5VM). Replaced it with an optoelectronic relay and the problems disappeared. The relay did have a snubber diode on board, so I suspect it might have been some kind of electrical interference.

Lesson learned: avoid mechanical relays.