Arduino Forum

Using Arduino => Interfacing w/ Software on the Computer => Topic started by: Thomas_Newton on Oct 27, 2012, 11:27 am

Title: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Oct 27, 2012, 11:27 am
Hi,

I have cobbled together a 6-DOF pick 'n' place robot with a couple of lasers for etching and cutting etc. which works fine for short jobs, but sometimes stalls unexpectedly when performing tasks taking several hours. It's based on a UNO board and driven from a VB 2008 app on a laptop at 38400 baud. To minimize interference I use as short a USB lead as possible between the two, and have LAN and all other software disabled while running. As it often has these hiccups at night, I haven't been able to pin down exactly how long the job has run, in case it's some kind of overflow or at least time-based fault.

Here's the VB output from the last stall:

Code: [Select]

x7574y0l3o14s0c12g16i252o14                           ' VB->Arduino (command)

-> x=7574 y=0 z=0 l=3 o1=14 s=0 c=12 g=16 i=252 o2=14 ' Arduino->VB (variables parsed OK)

-> OK                                                 ' Arduino->VB (Done/Ready for next)

x-7574y1                                              ' VB->Arduino

-> x=-7574 y=1 z=0 l=0 o1=0 s=0 c=0 g=0 i=0 o2=0      ' Arduino->VB (variables parsed OK)

-> OK                                                 ' Arduino->VB (Done/Ready for next)

x7574y0l3o14s0c12g16i252o14                           ' VB->Arduino (command)

-> x=7574 y=0 z=0 l=3 o1=14 s=0 c=12 g=16 i=252 o2=14 ' Arduino->VB (variables parsed OK)


The last command was carried out successfully, but either the Arduino failed to send it's 'OK', or the VB app never saw it. When I tried to force a command to the machine, the VB app crashed with 'The Port is Closed'. When I arrived at the machine this morning it had been working for about 15 hours. Though I can't say for certain that this timing is consistent. Perhaps I should time-stamp my debugging output?

Anyone had this happen to them before, or have any ideas on how I can trace it?


Many Thanks,

Thomas
Title: Re: VB Comms Failure During Long Jobs
Post by: robtillaart on Oct 27, 2012, 12:15 pm
Quote
Perhaps I should time-stamp my debugging output?

always a good idea.
for serious apps I recomment using a RealTime Clock(ds1307) , to be able to connect the error message of the arduino to the PC event log.

Can you post the whole Arduino code? (later we can check VB code too)
There might be an overflow involved if it is always around same time after startup.

Do you wrap your string send with tags to indicate begin of string and end of string? (like XML uses < and > )
This helps to synchronize longer packets of data.
Title: Re: VB Comms Failure During Long Jobs
Post by: MikMo on Oct 27, 2012, 05:33 pm
Are your VB code updating a text box or similar control with lots of data?

I had a problem with a program that worked perfectly for shorter runs but when running for say over 10 hours the textbox (displaying data recieved from Arduino) had so much text in it that it more or less made Windows stop working.

On the next crash you should start the task manager on your Windows machine and see if excessive memory or CPU usage is present.
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Oct 27, 2012, 07:39 pm
Good points, thanks.

@robtillaart

I have just ordered a ds1307, so hopefully I'll patch that in next week. Overflow does make sense, even though (I think) my Arduino code is free of counters. Perhaps something could be hidden in a library? When I started work on my machine I did use '<>' as start and end markers, but I still had the stalling problem after a few hours. I just use vbcrlf as line terminators now, which seems to work just as well. The lines never get any longer than the example I posted above. I am away from my Arduino sketch today (my Girlfriend has the laptop on a weekend course) but will post when I can.

@MikMo

That is very interesting indeed. I do have a lot of textboxes in my VB app, though none of them get updated during the run of the machine. I just set my parameters and press 'go'. I was running this from the IDE in debugging mode, I wonder if running the bare executable would behave differently? Also, you are very lucky to be living in CPH. It's one of my favourite cities, been there twice this year.
Title: Re: VB Comms Failure During Long Jobs
Post by: MikMo on Oct 27, 2012, 11:55 pm
Lot's of textboxes should not be a problem. My problem was a single textbox with litteraly megabytes of text added over time.
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 14, 2012, 01:13 pm
I'm still bashing away at this fault, I have tried a lot of different fixes (including USB registry tweaks) but as none of them helped I won't bother listing them here. Here are the relevant bits of my code in case I'm doing something superdumb. Both programs (especially the VB side) are quite big, so I've only included the serial sections. Please bear in mind that the code works perfectly FOR A WHILE, anything between 1 and 16 hours, but not indefinitely. The machine stops 'randomly' after executing a command successfully, and fails to get the 'OK' back to VB. Then VB freezes, and on re-running the app I get 'Port is Closed'. Despite applying DisableSelectiveSuspend, the only way I can recover the connection is by un/re-plugging the USB cable. And yes, I have tried many different USB cables too!

Arduino side:
Code: [Select]

// tjn 16/10/2012
//
// Status: Working! Interleaves X, Y1, Y2 and Z(B)
// Note: 78 Steps/mm using B servo in Full-wave mode, slack = 36

#include <Wire.h>
#include <iox.h>

// Variables get declared...

void setup() {
 Serial.begin(38400);
 inStr.reserve(40);          // easily enough for longest command (ie.x7000y7000z1404o13s0c19g6i270o14)
 pinMode(xctrl1, OUTPUT);    // X stepper pin1
 pinMode(xctrl2, OUTPUT);    // X stepper pin2
 pinMode(yctrl1, OUTPUT);    // Y1 stepper pin1
 pinMode(yctrl2, OUTPUT);    // Y1 stepper pin2
 pinMode(y2ctrl1, OUTPUT);   // Y2 stepper pin1
 pinMode(y2ctrl2, OUTPUT);   // Y2 stepper pin2
 pinMode(lpower, OUTPUT);    // Laser power
 pinMode(xypower, OUTPUT);   // XY stepper power
 pinMode(xsensors, INPUT);   // X-buffer switches
 pinMode(ysensors, INPUT);   // Y-buffer switches
 digitalWrite(xypower, LOW); // Power-down XY motors
 digitalWrite(lpower,LOW);   // Power-down laser
 Wire.begin();               // Start 2-wire communications (Arduino as master device)
 IOX.device(0x74, 16);       // 0x74 is address for Servo A (Pitch)
 IOX.write(0x0080, CFGPORT); // P07=INPUT Set ports LOW to make them OUTPUTS
 IOX.write(0x0000, INVPORT); // Set slave device invert ports to all NON-INVERT
 IOX.write(0x000, OUTPORT);  // Power-down Lamp/Fan
 Serial.println("OK?");
 Serial.flush();
 delay(100);
}

//Wait for input string and parse it into usable chunks

void loop() {
 if (stringComplete) {
   if(inStr.indexOf("x") >=0) xSteps = inStr.substring(inStr.indexOf("x")+1,inStr.indexOf("y")).toInt();
   else xSteps = 0;  // X Transit
   if(inStr.indexOf("y") >=0) {
     if(inStr.indexOf("z") >=0) y1Steps = inStr.substring(inStr.indexOf("y")+1,inStr.indexOf("z")).toInt();
     else y1Steps = inStr.substring(inStr.indexOf("y")+1).toInt(); // Y Transit
   }
   else y1Steps = 0;
   if(inStr.indexOf("z") >=0) {
     if(inStr.indexOf("l") >=0) zSteps = inStr.substring(inStr.indexOf("z")+1,inStr.indexOf("l")).toInt();
     else zSteps = inStr.substring(inStr.indexOf("z")+1).toInt(); // Z Transit
   }
   else zSteps = 0;
   if(inStr.indexOf("l") >=0) laserTime = inStr.substring(inStr.indexOf("l")+1).toInt();
   else laserTime = 0;  // Laser On/Off
   if(inStr.indexOf("o") >=0){
     laserTime = inStr.substring(inStr.indexOf("l")+1,inStr.indexOf("o")).toInt();      // Laser On Time
     offset1 = inStr.substring(inStr.indexOf("o")+1,inStr.indexOf("s")).toInt();        // Offset1
     space = inStr.substring(inStr.indexOf("s")+1,inStr.indexOf("c")).toInt();          // Space
     cut = inStr.substring(inStr.indexOf("c")+1,inStr.indexOf("g")).toInt();            // Cut
     gap = inStr.substring(inStr.indexOf("g")+1,inStr.indexOf("i")).toInt();            // Gap
     iterations = inStr.substring(inStr.indexOf("i")+1,inStr.lastIndexOf("o")).toInt(); // Iterations
     offset2 = inStr.substring(inStr.lastIndexOf("o")+1).toInt();                       // Offset2
   }
   else {
     offset1 = 0;
     space = 0;
     cut = 0;
     gap = 0;
     iterations = 0;
     offset2 = 0;
   }

   // Show VB immediate window that variables are good

   Serial.print("x=");
   Serial.print(xSteps,DEC);
   Serial.print(" y=");
   Serial.print(y1Steps,DEC);
   Serial.print(" z=");
   Serial.print(zSteps,DEC);
   Serial.print(" l=");
   Serial.print(laserTime,DEC);
   Serial.print(" o1=");
   Serial.print(offset1,DEC);
   Serial.print(" s=");
   Serial.print(space,DEC);
   Serial.print(" c=");
   Serial.print(cut,DEC);
   Serial.print(" g=");
   Serial.print(gap,DEC);
   Serial.print(" i=");
   Serial.print(iterations,DEC);
   Serial.print(" o2=");
   Serial.println(offset2,DEC);

// Do various things with motors and lasers...

   Serial.println("OK"); // Reset ready to receive next command from vb    
   inStr = "";              // Clear input string
   stringComplete = false;
   oxDir = xDir;
   oyDir = yDir;
   ozDir = zDir;
 }
}


VB (Express 2008) side:

Code: [Select]
   'setup form
   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
       If SerialPort1.IsOpen Then
           SerialPort1.Close()
       End If
       Try
           With SerialPort1
               .PortName = "Com7" 'check your ports!!! (AMD4400 = 5, Duemilanove = 4, UNO = 7)
               .BaudRate = 38400
               .Encoding = System.Text.Encoding.ASCII
           End With
           'Open the port and clear the input buffer
           SerialPort1.Open()
           SerialPort1.DiscardInBuffer()
       Catch Ex As Exception
           MsgBox(Ex.ToString)
       End Try
   End Sub
   
    'release resources after form is closed
       Private Sub Form1_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
           If SerialPort1.IsOpen() Then
               SerialPort1.Close()
           End If
   End Sub
   
    'This sub gets called automatically when the COM port receives data
       Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
           rxBuffer = (SerialPort1.ReadLine) 'Move recieved data into the buffer
           If rxBuffer.StartsWith("OK") Then 'Allows diagnostic messages from Arduino without interfering with comms
               enableSend = True
           End If
           Debug.WriteLine("-> " + rxBuffer)
   End Sub
   
Private Function Output(ByVal CurrentImage As Bitmap) As Bitmap
        For i = 0 to Whatever ' 1 to 7000-ish
                ' Build outString        
                Debug.WriteLine(outString)
               SerialPort1.Write(outString & vbCrLf)
               enableSend = False
               While enableSend = False
               End While
               outString = ""
        next i
End Function
Title: Re: VB Comms Failure During Long Jobs
Post by: robtillaart on Nov 14, 2012, 07:56 pm
if you use for example putty.exe to capture the output of arduino, does it fail after 16 hours too?


Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 14, 2012, 09:44 pm
I've had a number of monitors watching different jobs; Process Monitor, Comport Toolkit and Device Monitoring Studio. DMS was the most informative of the bunch, but only reflected exactly what VBs immediate window told me anyway. Arduino failed to send an 'OK', or the laptop never saw it. Process Monitor didn't really show anything strange, other than a double Thread Exit invoked in VB around the time of failure, but I'm not entirely convinced it was significant.

Currently running another test with Serial.flush() after the Arduino's 'OK' line. So far so good...

[EDIT]

Nope, crashed after almost exactly 8hrs. Reset the Arduino and had to un/re-plug twice before VB would acknowledge it's existence again!
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 17, 2012, 12:09 am
I think I'm starting to get to grips with this now (haha, famous last words!)

Running the VB straight from the .exe works MUCH better than within the IDE, and here's why...

To see what's going on behind the scenes Debug.Writeline is really handy, HOWEVER, dumping text into the immediate window really slows things down and seems to interfere with serial comms particularly badly, especially when there are lots of lines being returned in quick succession. The immediate window seems to insist on reporting everything as effectively as possible (which is fine in itself), but it seems to lend so many resources to printing and scrolling the outpouring of text that it will happily corrupt the transmission of serial comms and leave you wondering why something so simple often falls flat on its face.

I have now removed all of my Debug.Writeline command and now use StreamWriter to populate a text file with all of my event reports, and things are running so much better. I would like to say perfectly, but I'm still cautious (and the connection to my X-actuator has fatigued-away after performing over 140,000 transits over the last few days!)

Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 18, 2012, 01:26 pm
You know, I'm seriously considering abandoning VB for this application.

I've been running the Debug Build so far, and thought things might be better using the Release Build. Freezes after sending one command, while the Debug would fail after a few thousand. ]:)
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 19, 2012, 10:43 pm
This thread has become somewhat of a soliloquy, but no matter. It's still useful for me to keep a record of what I'm trying, and much neater than the ever-thickening stack of sticky notes accumulating on the edge of my machine.

Not sure I can quite blame VB/MS just yet. I did a rebuild of my VB app using .Net Framework 2.0 as there are many reports going 'round that 3.5 is bad news for serial comms. The machine still froze after that, so I added a Try/Catch around the serial sending sub in the VB. Okay, it froze again after about 11 hours, but something unexpected happened. I had coded the serial exception to throw out messagebox with the error, but there was no box when the machine froze!

May be the Arduino misbehaving after all, but just to be sure I have started another test job with a camera watching the Tx/Rx lights on the Arduino. Hopefully, when it freezes again I will be able to play back the footage and see if that little Tx flashed before the machine stalled.

Onward...
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 20, 2012, 11:55 am
Okay, for those of you still reading, I now have photographic evidence that this is NOT a VB error, but an Arduino one! Here we go...

Job Start:
(http://www.gdriveurl.com/?idl=613534085298&out=1)

Logfile Entries (camera clock was a few seconds out of sync):
Code: [Select]
Start of Matrix Output...
13:53:35 <- z-412
13:53:37 -> OK
13:53:37 <- x0y1
13:53:37 -> OK
13:53:37 <- x7058y0l3o0s1c7g19i262o0
13:53:59 -> OK


Job End: (moved camera and switched to a lower resolution)
(http://www.gdriveurl.com/?idl=513534086000&out=1)

Logfile:
Code: [Select]
02:05:45 <- x-7058y1
02:05:54 -> OK
02:05:54 <- x7058y0l3o14s1c7g19i261o15
02:06:16 -> OK
02:06:16 <- x-7058y1
02:06:26 -> OK
02:06:26 <- x7058y0l3o14s1c7g19i261o15


I'm now trying another test at only 9600bps to see if that helps. If not I might try and restart this thread under a new guise, after all it is a different problem to the one I thought I had originally!
Title: Re: VB Comms Failure During Long Jobs
Post by: PaulS on Nov 20, 2012, 12:46 pm
Quote
I now have photographic evidence that this is NOT a VB error, but an Arduino one!

Sounds like a conspiracy movie. I've never understood them because the photographic evidence that is supposed to prove something never does, to me.

Please explain what this photographic evidence is supposed to prove.
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 20, 2012, 01:15 pm
Hi Paul,

The shots were extracted from video of the UNO while my laser cutter was running. The serial transfer is a very simple polling scenario.

1) The VB app sends a command string, and waits for an 'OK' from the Arduino
2) Arduino catches the string and parses the variables <- RX flashes
3) Arduino carries out motor/laser commands
4) Arduino finishes and sends 'OK' back to the VB app <- TX flashes

And so on...

The photos show that the stalling is a fault with the Arduino or its code because the TX does not flash at the moment of stall (the last photo). Thus no 'OK' gets returned to VB. I had assumed for ages that VB/Windows was locking the port for some reason and not receiving the 'OK'.

Title: Re: VB Comms Failure During Long Jobs
Post by: PaulS on Nov 20, 2012, 01:28 pm
Quote
The photos show that the stalling is a fault with the Arduino or its code because the TX does not flash at the moment of stall (the last photo).

You can see from this picture that the Arduino code failed because of what isn't here. OK. Got it.

You've, of course, posted ALL of your Arduino code, and I just missed it. Right?

Code: [Select]
  inStr.reserve(40);          // easily enough for longest command (ie.x7000y7000z1404o13s0c19g6i270o14)
In spite of all the warnings about problems with the String class, you are still using it. Here's a gun. Shoot your self in the foot. Go ahead and do it again. There's plenty of bullets, and I'll reload when you run out.
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 20, 2012, 01:45 pm
Okay Paul, you've got my attention!

I had no idea that String class was problematic, or I would never have used it. It's quite hard to feel your way around a bug when it takes several hours to manifest.

Here's the Arduino code in FULL: I'll post the servo handler loop in the next post, as the full sketch exceeds the forum's character limit

Code: [Select]
// MMM_matrix_Plotter3 (pairs with same-named VB)
// tjn 16/10/2012
//
// Status: Interleaving X, Y1, Y2 and Z(B)
// Note: 78 Steps/mm using B servo in Full-wave mode, slack = 36

#include <Wire.h>
#include <iox.h>

// Setup pins (0 and 1 reserved for serial I/O)
byte xctrl1 = 2;                // X-Axis geartrain control 1
byte xctrl2 = 3;                // X-Axis geartrain control 2
byte yctrl1 = 4;                // South-Y geartrain control 1
byte yctrl2 = 5;                // South-Y geartrain control 2
byte y2ctrl1 = 7;               // North-Y geartrain control 1
byte y2ctrl2 = 8;               // North-Y geartrain control 2
byte xypower = 12;              // XY stepper supply
byte lpower = 13;               // Laser logic supply
byte xsensors = 15;             // X-buffer switches
byte ysensors = 14;             // Y-buffer switches
byte scaleFactor = 1;
byte offset1, offset2, space, cut, gap;
byte xStepIdx, y1StepIdx, y2StepIdx, zStepIdx;
int xSteps, y1Steps, y2Steps, zSteps, totalSteps, subSteps, bitIndex, laserTime, tMult;
int xStore, yStore, zStore, pixCount, iterations, dotCount, max1, max2, iTimeIdx = 0;
String inStr = "";              // Hold incoming data
boolean stringComplete = false; // Data complete flag
boolean xStop = false;
boolean yStop = false;
boolean xDir = false;           // TRUE = Clockwise
boolean yDir = false;
boolean zDir = false;
boolean oxDir = false;
boolean oyDir = false;
boolean ozDir = false;
boolean laserOn = false;
long MsDelay;
unsigned char twoWire[] = {
 B01,B11,B10,B00};             // 2-Wire sequence for X/Y steppers
word fullWaveB[] = {            // Full-wave Slave stepper motor sequence
 0x6000,0x2010,0x18,0x4008};
word lampState = 0x0000;
double m, mx, my1, my2, mz, x, y1, y2, z;

void setup() {
 Serial.begin(9600);         // was 38400, but froze
 inStr.reserve(40);          // easily enough for longest command (ie.x7000y7000z1404o13s0c19g6i270o14)
 pinMode(xctrl1, OUTPUT);    // X stepper pin1
 pinMode(xctrl2, OUTPUT);    // X stepper pin2
 pinMode(yctrl1, OUTPUT);    // Y1 stepper pin1
 pinMode(yctrl2, OUTPUT);    // Y1 stepper pin2
 pinMode(y2ctrl1, OUTPUT);   // Y2 stepper pin1
 pinMode(y2ctrl2, OUTPUT);   // Y2 stepper pin2
 pinMode(lpower, OUTPUT);    // Laser power
 pinMode(xypower, OUTPUT);   // XY stepper power
 pinMode(xsensors, INPUT);   // X-buffer switches
 pinMode(ysensors, INPUT);   // Y-buffer switches
 digitalWrite(xypower, LOW); // Power-down XY motors
 digitalWrite(lpower,LOW);   // Power-down laser
 Wire.begin();               // Start 2-wire communications (Arduino as master device)
 IOX.device(0x74, 16);       // 0x74 is address for Servo A (Pitch)
 IOX.write(0x0080, CFGPORT); // P07=INPUT Set ports LOW to make them OUTPUTS
 IOX.write(0x0000, INVPORT); // Set slave device invert ports to all NON-INVERT
 IOX.write(0x000, OUTPORT);  // Power-down Lamp/Fan
 Serial.println("OK?");
 Serial.flush();
 delay(100);
}

void loop() {
 if (stringComplete) {
   if(inStr.indexOf("x") >=0) xSteps = inStr.substring(inStr.indexOf("x")+1,inStr.indexOf("y")).toInt();
   else xSteps = 0;  // X Transit
   if(inStr.indexOf("y") >=0) {
     if(inStr.indexOf("z") >=0) y1Steps = inStr.substring(inStr.indexOf("y")+1,inStr.indexOf("z")).toInt();
     else y1Steps = inStr.substring(inStr.indexOf("y")+1).toInt(); // Y Transit
   }
   else y1Steps = 0;
   if(inStr.indexOf("z") >=0) {
     if(inStr.indexOf("l") >=0) zSteps = inStr.substring(inStr.indexOf("z")+1,inStr.indexOf("l")).toInt();
     else zSteps = inStr.substring(inStr.indexOf("z")+1).toInt(); // Y Transit
   }
   else zSteps = 0;
   if(inStr.indexOf("l") >=0) laserTime = inStr.substring(inStr.indexOf("l")+1).toInt();
   else laserTime = 0;  // Laser On/Off
   if(inStr.indexOf("o") >=0){
     laserTime = inStr.substring(inStr.indexOf("l")+1,inStr.indexOf("o")).toInt();      // Laser On Time
     offset1 = inStr.substring(inStr.indexOf("o")+1,inStr.indexOf("s")).toInt();        // Offset1
     space = inStr.substring(inStr.indexOf("s")+1,inStr.indexOf("c")).toInt();          // Space
     cut = inStr.substring(inStr.indexOf("c")+1,inStr.indexOf("g")).toInt();            // Cut
     gap = inStr.substring(inStr.indexOf("g")+1,inStr.indexOf("i")).toInt();            // Gap
     iterations = inStr.substring(inStr.indexOf("i")+1,inStr.lastIndexOf("o")).toInt(); // Iterations
     offset2 = inStr.substring(inStr.lastIndexOf("o")+1).toInt();                       // Offset2
   }
   else {
     offset1 = 0;
     space = 0;
     cut = 0;
     gap = 0;
     iterations = 0;
     offset2 = 0;
   }

   if (xSteps < 0) xDir = true;
   if (xSteps > 0) xDir = false;
   if (xSteps == 0) xDir = oxDir;
   if (y1Steps < 0) yDir = true;
   if (y1Steps > 0) yDir = false;
   if (y1Steps == 0) yDir = oyDir;
   if (zSteps < 0) zDir = false;
   if (zSteps > 0) zDir = true;
   if (zSteps == 0) zDir = ozDir;
   if (xStop = true && xDir != oxDir) xStop = false;
   if (yStop = true && yDir != oyDir) yStop = false;
   xSteps = abs(xSteps);
   y1Steps = abs(y1Steps);
   zSteps = abs(zSteps);
   y2Steps = y1Steps;

   if (zDir != ozDir) { // Vertical Slack Handler
     zSteps += 37;      // Z-Slack value (from laser deflection test)
   }

   totalSteps = max(xSteps, y1Steps);
   subSteps = min(xSteps, y1Steps);
   m = (double)subSteps/(double)totalSteps;

   if (m > 0.7) { // vector splitter/dog-legger to avoid bad harmonics between X&Y
     digitalWrite(lpower,LOW);
     if (xSteps > y1Steps) {
       xStore = xSteps;
       yStore = y1Steps;
       xSteps = xStore - y1Steps;
       y1Steps = 0;
       y2Steps = 0;
       digitalWrite(xypower, HIGH);
       xyzServos();
       xSteps = yStore;
       y1Steps = yStore;
       y2Steps = y1Steps;
     }
     if (xSteps < y1Steps) {
       xStore = xSteps;
       yStore = y1Steps;
       y1Steps = yStore - xSteps;
       xSteps = 0;
       digitalWrite(xypower, HIGH);
       xyzServos();
       xSteps = xStore;
       y1Steps = xStore;
       y2Steps = y1Steps;
     }
     // else not used (no adjustment needed when X & Y are equal!  
   }

   if (xSteps != 0 || y1Steps != 0 || zSteps != 0) {
     digitalWrite(xypower, HIGH);
     xyzServos(); // rem-out while testing
   }
   else {
     if (laserTime == 1) {
       digitalWrite(lpower, HIGH); // Laser ON
       IOX.write(0x0200, OUTPORT); // Lamp & Fan ON
     }
     else{
       digitalWrite(lpower,LOW);   // Laser OFF
       IOX.write(0x000, OUTPORT);  // Lamp & Fan OFF
     }
   }

   if (xSteps  == 0 && y1Steps == 0) { // switch OFF motors on end vector
     //digitalWrite(xypower, LOW); // Machine loses registration on power-down!
     if (laserTime == 0) IOX.write(0x0000, OUTPORT); // Turn lamp & fan OFF
   }

   if (xStop == true) Serial.println("X-buffer Hit");
   if (yStop == true) Serial.println("Y-buffer Hit");
   Serial.println("OK"); // Tell VB Arduino's ready to receive next command
   Serial.flush();
   inStr = "";           // Clear input string
   stringComplete = false;
   oxDir = xDir;
   oyDir = yDir;
   ozDir = zDir;
 }
 //else{
   //Serial.println("OK!"); // Tell VB Arduino's ready to receive next command from vb    
   //Serial.flush();
   //delay(1000);
 //}
}

void serialEvent() {
 while (Serial.available()) { // get new byte
   char inChar = (char)Serial.read();
   inStr += inChar;           // add to the inStr
   if (inChar == '\n') {      // Flag if char is vbcrlf
     stringComplete = true;
   }
 }
}


Any ideas/suggestions would be greatly appreciated.
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 20, 2012, 01:46 pm
Here's the servo handler, probably has no bearing on the problem, but you never know...

Code: [Select]
void xyzServos() {
  if (zSteps > 0 || (xSteps + y1Steps) < 500) tMult = 2000; // Change acceleration profile to suit Z(B)
  else tMult = 1000;            // stepper motor which stalls below 3ms
  max1 = max(xSteps, y1Steps);
  max2 = max(y1Steps, zSteps);
  totalSteps = max(max1, max2);
  mx = (double)xSteps/(double)totalSteps;
  my1 = (double)y1Steps/(double)totalSteps;
  my2 = (double)y2Steps/(double)totalSteps;
  mz = (double)zSteps/(double)totalSteps;
  x = mx;
  y1 = my1;
  y2 = my2;
  z = mz;
  laserOn = false;
  if (cut > 0 || laserTime > 0) {
    IOX.write(0x0200, OUTPORT); // Turn lamp & fan ON
    lampState = 0x0200;
  }
  if (cut == 0 && laserTime > 0) digitalWrite(lpower, HIGH);
  for (int i = 0; i < totalSteps; i++) {
    x += mx;
    if (x >= 1 && mx != 0 && xStop == false){ // X-stepper control
      x -= 1.0;
      if (xDir == true) {
        if (xStepIdx == 0) xStepIdx = 4;
        xStepIdx--;
      }
      else {
        xStepIdx++;
        if (xStepIdx > 3) xStepIdx = 0;
      }
      if(twoWire[xStepIdx] & 1<<1){
        digitalWrite(xctrl1,HIGH);
      }
      else {
        digitalWrite(xctrl1,LOW);
      }
      if(twoWire[xStepIdx] & 1<<0){
        digitalWrite(xctrl2,HIGH);
      }
      else {
        digitalWrite(xctrl2,LOW);
      }
    }
    y1 += my1;
    if (y1 >= 1 && my1 != 0 && yStop == false){ // Y1(South)-stepper control
      y1 -= 1.0;
      if (yDir == true) {
        if (y1StepIdx == 0) y1StepIdx = 4;
        y1StepIdx--;
      }
      else {
        y1StepIdx++;
        if (y1StepIdx > 3) y1StepIdx = 0;
      }
      if(twoWire[y1StepIdx] & 1<<1){
        digitalWrite(yctrl1,HIGH);
      }
      else {
        digitalWrite(yctrl1,LOW);
      }
      if(twoWire[y1StepIdx] & 1<<0){
        digitalWrite(yctrl2,HIGH);
      }
      else {
        digitalWrite(yctrl2,LOW);
      }
    }   
    y2 += my2;
    if (y2 >= 1 && my2 != 0 && yStop == false){ // Y2(North)-stepper control
      y2 -= 1.0;
      if (yDir == true) {
        if (y2StepIdx == 0) y2StepIdx = 4;
        y2StepIdx--;
      }
      else {
        y2StepIdx++;
        if (y2StepIdx > 3) y2StepIdx = 0;
      }
      if(twoWire[y2StepIdx] & 1<<1){
        digitalWrite(y2ctrl1,HIGH);
      }
      else {
        digitalWrite(y2ctrl1,LOW);
      }
      if(twoWire[y2StepIdx] & 1<<0){
        digitalWrite(y2ctrl2,HIGH);
      }
      else {
        digitalWrite(y2ctrl2,LOW);
      }
    }   
    z += mz;
    if (z >= 1 && mz != 0){ // Z(B)-stepper control
      z -= 1.0;
      if (zDir == true) {
        if (zStepIdx == 0) zStepIdx = 4;
        zStepIdx--;
      }
      else {
        zStepIdx++;
        if (zStepIdx > 3) zStepIdx = 0;
      }
      IOX.write(fullWaveB[zStepIdx] + lampState, OUTPORT);
    }
    if (cut > 0) { // Put lasing code here..
      bitIndex = (i - (offset1 + space)) % (space + cut + space + gap - 1); // - 1 makes interval agree with vb HorizSteps value!
      if (bitIndex == 0 && i < (totalSteps - offset2)) laserOn = true;
      if (bitIndex == cut) laserOn = false;
      if (laserOn == true) {
        digitalWrite(lpower, HIGH); //rem-out while testing
        delay(laserTime);
      }
      else {
        digitalWrite(lpower, LOW);
        delay(3); // fastest stable transit to next cutting point
      }
    }
    else {
      if (i < totalSteps / 2)
        iTimeIdx = i;
      else
        iTimeIdx = totalSteps - i;
      if (iTimeIdx > 180) iTimeIdx = 180;
      MsDelay = (tMult*(3-(sin((270+iTimeIdx)*PI/180)))) - 1000;
      if (laserTime == 0) delayMicroseconds(MsDelay);
      else delay(laserTime);
    }
    if (digitalRead(xsensors) == HIGH && i > 25) xStop = true;
    if (digitalRead(ysensors) == HIGH && i > 25) yStop = true;
    if (xStop == true || yStop == true) digitalWrite(lpower, LOW); // cut laser power if any limit reached
    if (xStop == true && yStop == true) i = totalSteps;            // bomb-out of loop if both limits reached
  }
  digitalWrite(lpower, LOW);
  //IOX.write(0x0000, OUTPORT); // Turn lamp & fan OFF
}
Title: Re: VB Comms Failure During Long Jobs
Post by: PaulS on Nov 20, 2012, 02:04 pm
Code: [Select]
String inStr = "";              // Hold incoming data
  inStr.reserve(40);          // easily enough for longest command (ie.x7000y7000z1404o13s0c19g6i270o14)

If you KNOW that maximum size, then a static char array is perfectly suited.

Code: [Select]
char inStr[40];
byte index = 0;


Code: [Select]
  Serial.begin(9600);         // was 38400, but froze
  Serial.println("OK?");
  Serial.flush();
  delay(100);

If you are using 1.0 or later, the flush() function blocks until the 5 bytes have been sent. Then, you sit on your thumbs for 10 times as long as it took to shift those 5 bytes out. Was blocking really useful?

If you are using 0023 or earlier, the flush function dumps random amounts of unread data. Is that useful?

99% of the time, Serial.flush() is used incorrectly. You code appears to not be a 1%-er.

Code: [Select]
void serialEvent() {
  while (Serial.available()) { // get new byte
    char inChar = (char)Serial.read();
    inStr += inChar;           // add to the inStr
    if (inChar == '\n') {      // Flag if char is vbcrlf
      stringComplete = true;
    }
  }
}

should be
Code: [Select]
void serialEvent()
{
  while (Serial.available())
  {
    char inChar = Serial.read();
    inStr[index++] = inChar;           // add to the inStr
    inStr[index] = '\0'; // NULL terminate the array
    if (inChar == '\n')
    {      // Flag if char is vbcrlf
      stringComplete = true;
    }
  }
}


That leaves only determining, in loop, what is in inStr. The strcspn() function will find a character, like 'x', in a string. It returns the position of the character in the string. The strchr() function is similar, except that it returns a pointer to the character. You can increment that pointer to point to the next character.

Pass that pointer to strncpy() to extract a substring into another char array. Null terminate that array, and pass it to atoi() to get an int.

Of course, if you have any control over the sender, sending something like "x=7000,y=7000,z=1404,o=13,s=0,c=19,g=6,i=270,o=14" instead of "x7000y7000z1404o13s0c19g6i270o14" would allow you to use strtok() in a while loop, with a series of if/else if statements to extract the numeric values and associate them with the correct variables.
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 20, 2012, 02:11 pm
Paul,

I will amend the code as you suggested and run another long test, probably reply in a day or so. In the meantime, thank you so much for taking the time to point out my mistakes!
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 21, 2012, 05:51 pm
Well,

That failed. Twice.

I did the second run at 9600 baud, but no improvement. I will give a fuller report later, bit pushed for time today.
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 24, 2012, 10:15 am
Well, after a few more days of tests I think it's time for me to move this issue onto a VB forum.

My TX/RX camera footage doesn't really prove anything. If VB closes the port and the Arduino sends serial data, TX WILL NOT FLASH. VB continues to randomly close the port, say the device connected is not functioning, or just tell me outright that the port doesn't even exist (even though the device manager may show everything's working fine).

Ciao for now...
Title: Re: VB Comms Failure During Long Jobs
Post by: PaulS on Nov 24, 2012, 02:34 pm
Quote
If VB closes the port and the Arduino sends serial data, TX WILL NOT FLASH. VB continues to randomly close the port, say the device connected is not functioning, or just tell me outright that the port doesn't even exist (even though the device manager may show everything's working fine).

I know that it might take a while, but what happens if you have the Serial Monitor application monitor the serial port, instead of the VB app? Does the PC continue to receive data (or for longer than the VB app does)?
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 24, 2012, 05:23 pm
As I mentioned earlier, I had most success from Device Monitoring Studio (most of the other monitor programs would just say "port is busy" and not even attempt to connect. The DMS output mirrored exactly what the VB IDE was reporting, byte for byte.

The more I search for info on VB's serial port, the more I find a trail of irate developers who swear that the VB serial implementation is rotten to the core (at least pre-Net Framework 4.0). I have stripped the SerialDataReceivedEventHandler out as I'm sure it's overkill, I already know when a command is coming from the Arduino, I don't need a thread to watch it.

I'm currently running a skeletal VB app that just prints command strings to the Arduino. Even this froze in a debug build! Once the release build has failed later today I will be compiling in 2010 with Net Framework 4.0.
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 25, 2012, 11:56 pm
Build under .Net Framework 4.0 also failed after nearly 9 hours.

Now testing with nothing (other than the laptop) connected to the Arduino!
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Nov 28, 2012, 11:19 am
Motor control code running on my bare Uno (nothing but USB connected) has been running continuously since my last post. Serial seems stable, so I need to reframe the problem and start a new thread. Looks like it might've been suffering some kind of brown-out with all the motors hooked up, but I'm not sure why as all my supplies are isolated. Could I be getting ripples on the 5v line, and why would it take hours to manifest?

[RESOLVED - insofar as the comms failure is now known to not be a software issue]

EDIT...

It WAS a serial/USB issue in the laptop/OS itself. I tried another laptop (also XP SP3) and the problem VANISHED!
Title: Re: VB Comms Failure During Long Jobs
Post by: Thomas_Newton on Aug 09, 2013, 11:20 am
As a very late addendum to this thread, I'd like to add that I have just tried a fairly new notebook (Acer Aspire One running Win 7) borrowed from a friend as a potential purchase, and it had exactly the same problem.

Even with updates, power-saving and USB SelectiveSleepSuspend disabled it still randomly locked the COM port!

What the hell is wrong with modern laptops!!!?

Thomas