Problem with Arduino and Perl communicating via serial...

I am trying to get perl and arduino talking via serial, but I am running into an issue.

If I disconnect the USB cable (going to the arduino) after the Perl script has successfully connected to the arduino, I am unable to re-establish a serial connection to the arduino via the Perl script. I can connect using the Serial Monitor though. The only way I am able to get the Perl script to talk to the arduino again is to re-upload the sketch to the arduino. I'm not sure if I need to change the sketch or the Perl script to account for this issue.

Here is a sample of the arduino sketch:

//Receive a 16 character string via serial, then print it back 
#define baudrate 57600
char inData[15]; // Allocate space for incoming serial data
char *IRCode[3];
char inByte; // Incoming serial character 
byte index = 0; // Index into array; where to store the character

void setup(){
  Serial.begin(baudrate);
}

void loop() {
  while (Serial.available() > 0){
    inByte = Serial.read ();
    inData[index] = inByte;
    index++;
    if (index > 15 || inByte == 10 || inByte == 13){
      inData[index] = '\0'; //Null terminate the string
      Serial.println(inData);
      index = 0;
    }
  }
}

**And here is the perl script (Windows). ** I tried to add a mechanism to retry opening the port, but the only thing I could figure out to make it reconnect was to re upload the sketch.

use warnings;
use strict;
use Time::HiRes;
use Win32::Serialport;

my $debug = 1;
my $SerialPortObj = detectArduinoBoard('COM9');
my $serialDiscoveryAttempts = 0;

sub detectArduinoBoard{
	if ($serialDiscoveryAttempts++ == 10){
		die "Giving up after 10 connection attempts\n";
	}
	my @ports = shift;
	my $sPort;
	my $iteration = 1;
	foreach (@ports){
		die "No Arduino detected\n" unless $_;
		print "Attempting handshake with $_\n";
		#determine which port Arduino is attached to
		$sPort = Win32::SerialPort->new($_);
		Time::HiRes::usleep(250);				
		if ($sPort){
			print "\tConnecting to $_\n";
			$sPort->databits(8);
			$sPort->baudrate(57600);
			$sPort->parity("none");
			$sPort->stopbits(1);
			my ($BlockingFlags, $InBytes, $OutBytes, $LatchErrorFlags) = $sPort->status || print "could not get port status\n";
			$sPort->lookclear; #empty buffer
			Time::HiRes::usleep(250);
			$sPort->write('XXX:XXXXXXXX:XXX');
			Time::HiRes::usleep(250);
			my $incoming = '';
			while (length($incoming) < 16){
				$incoming = $sPort->lookfor();
				#print "|$incoming|\n";
				Time::HiRes::usleep(1000);
				$iteration++;
				if ($iteration > 20){
					print "\t$incoming\n";
					print "\tTimed out.  Retrying\n";
					$sPort->restart();
					$sPort->close();
					detectArduinoBoard(@ports);
				}
			}
			if ($incoming){
				$incoming =~ /([A-Z0-9]{3}):([A-Z0-9]{8}):([A-Z0-9]{3})/;
				$incoming = $1 . ':' . $2 . ':' . $3;
			}
			if ( $incoming eq 'XXX:XXXXXXXX:XXX'){
				print "\tHandshake with $_ successful\n" if $debug;
				print "\tReceived: $incoming from Arduino\n"; 
				print "\tdetectArduinoBoard() complete\n" if $debug;
				$serialDiscoveryAttempts = 0;
				return $sPort;		
			} else {
				print "\tHandshake with $_ failed\n" if $debug;
				return undef;
			}
		}
	}
}

Re-uploading the sketch re-initializes all aspects of the serial port. I suspect that there is something that the Arduino IDE/Serial Monitor does when initializing the serial port that your Perl sketch is not doing. Exactly what that is, I am not sure.

250 microseconds after opening the serial port may not be enough for the Arduino to get ready to talk to the serial port, depending on which Arduino and which bootloader you have.

I am testing this on a Duemilanove.

I tried changing the delay from 250 microseconds to 1 second, but that didn't help.

I stumbled on the following post http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1226781023/17 which seems to be very similar to my issue.

Based on what I saw in that post I have modified the perl code, adding $sPort->write_settings(); and changing the delay to 5 seconds. This seems to resolve the issue.

Here is the perl code:

use warnings;
use strict;
use Time::HiRes;
use Win32::Serialport;

my $debug = 1;
my $SerialPortObj = detectArduinoBoard('COM9');
my $serialDiscoveryAttempts = 0;

sub detectArduinoBoard{
	if ($serialDiscoveryAttempts++ == 10){
		die "Giving up after 10 connection attempts\n";
	}
	my @ports = shift;
	my $sPort;
	my $iteration = 1;
	foreach (@ports){
		die "No Arduino detected\n" unless $_;
		print "Attempting handshake with $_\n";
		#determine which port Arduino is attached to
		$sPort = Win32::SerialPort->new($_);
		if ($sPort){
			print "\tConnecting to $_\n";
			$sPort->databits(8);
			$sPort->baudrate(57600);
			$sPort->parity("none");
			$sPort->stopbits(1);
			$sPort->write_settings();
			sleep 5;
			my ($BlockingFlags, $InBytes, $OutBytes, $LatchErrorFlags) = $sPort->status || print "could not get port status\n";
			$sPort->lookclear; #empty buffer
			$sPort->write('XXX:XXXXXXXX:XXX');
			my $incoming = '';
			while (length($incoming) < 16){
				$incoming = $sPort->lookfor();
				#print "|$incoming|\n";
				sleep 1;
				$iteration++;
				if ($iteration > 20){
					print "\t$incoming\n";
					print "\tTimed out.  Retrying\n";
					$sPort->restart();
					$sPort->close();
					detectArduinoBoard(@ports);
				}
			}
			if ($incoming){
				$incoming =~ /([A-Z0-9]{3}):([A-Z0-9]{8}):([A-Z0-9]{3})/;
				$incoming = $1 . ':' . $2 . ':' . $3;
			}
			if ( $incoming eq 'XXX:XXXXXXXX:XXX'){
				print "\tHandshake with $_ successful\n" if $debug;
				print "\tReceived: $incoming from Arduino\n";
				print "\tdetectArduinoBoard() complete\n" if $debug;
				$serialDiscoveryAttempts = 0;
				return $sPort;
			} else {
				print "\tHandshake with $_ failed\n" if $debug;
				return undef;
			}
		}
	}
}

Thanks for you help!