Serial communication with PHP

Hello all,

I've been working with PHP on my home Apache server to make some web enabled Arduino projects. So far, I've got an Arduino sketch that utilizes a switch statement to toggle three LEDs on and off. This works perfectly when I upload the sketch and use the serial monitor to send the characters 'a', 'b' or 'c' (minus the single quotes).

Now I'm attempting to send the same characters to the USB serial port via PHP to do the same thing but I'm getting no love. Can anyone take a look at both my Arduino and PHP code and give me some pointers to make this a reality? I'd really appreciate the help!

My stolen and modified Sketch:

/*
Set 3 LEDs, (Red, Yellow, Green) on pins 2, 3 and 4
Open the serial monitor and send the characters a, b or c to toggle the
LEDs on or off
 */

void setup() {
  // initialize serial communication:
  Serial.begin(9600); 
  // initialize the LED pins:
  for (int thisPin = 2; thisPin < 5; thisPin++) {
    pinMode(thisPin, OUTPUT);
  } 
}
int redState=0;
int yellowState=0;
int greenState=0;
void loop() {
  // read the sensor:
  if (Serial.available() > 0) {
    int inByte = Serial.read();
    // do something different depending on the character received.  
    // The switch statement expects single number values for each case;
    // in this exmaple, though, you're using single quotes to tell
    // the controller to get the ASCII value for the character.  For 
    // example 'a' = 97, 'b' = 98, and so forth:

    switch (inByte) {
    case 'a':    
      if (redState==0){
        digitalWrite(2, HIGH);
        redState=1;
      }else{
        digitalWrite(2, LOW);
        redState=0;
      }
      break;
    case 'b':
    if (yellowState==0){
     digitalWrite(3, HIGH);
     yellowState=1; 
    }else{
      digitalWrite(3, LOW);
      yellowState=0;
    }
      break;
    case 'c':    
    if (greenState==0){
     digitalWrite(4, HIGH); 
     greenState=1;
    }else{
      digitalWrite(4, LOW);
      greenState=0;
    }
      break;
    default:
      // turn all the LEDs off:
      for (int thisPin = 2; thisPin < 5; thisPin++) {
        digitalWrite(thisPin, LOW);
      }
    } 
  }
}

And one of my PHP toggle scripts:

<?PHP

$fp =fopen("com7", "w");
fwrite($fp, chr(a));
fclose($fp);

?>

Anyone got any ideas?

When the Arduino IDE opens the Serial Monitor, the Arduino resets. When the Serial Monitor is closed, the Arduino resets.

It's possible that opening and closing the serial port using PHP causes the same thing to happen.

Try adding some code in setup that flashes all 3 LEDs three times.

Then, run the PHP script and see if the LEDs start flashing. Let us know what happens, please.

Well I did that by changing the switch statement in the code above to this:

switch (inByte) {
    case 'a':    
    digitalWrite (2, HIGH);
    delay (1500);
    digitalWrite (2, LOW);
    delay (1500);
    digitalWrite (2, HIGH);
    delay (1500); 
    digitalWrite (2, LOW);
    delay (1500);
    digitalWrite (2, HIGH);
    delay (1500);
    digitalWrite (2, LOW);
    break;

Once again, when I use the serial monitor and I send 'a' (without the single quotes) the LED on pin 2 flashes on for 1.5 seconds and off again 3 times. Works exactly as expected. But when I use PHP to send the 'a' (using the code above, I can see the TX and RX LEDs on the board flash once, and the L LED flashes (because I'm assuming it flashes when it reads serial incoming data), but the LED on pin 2 stays unaffected. I also tried sending chr(97) using PHP because that's the ASCII representation for 'a'. I even tried sending raw 'a' and raw 97 (without the chr() function) and it still doesn't work. Surely this isn't that complicated! Help?!

Of course, I must make you aware that I am on a Windows XP pro OS, so I'm not sure if there are some jerky Windows issues included w/ this or not... Just trying to give you all as much info as I can.

Do you know for certain that your PHP script/PHP setup is working properly? Have you tried a null-modem or loopback to verify that something is coming out of the COM port? Have you checked your PHP logs for errors?

Hi,
I tried sending this via private message yesterday, but maybe I didn't send it correctly.

I don't know PHP, but shouldn't the character 'a' be in quotes in your PHP code?
Instead of this: fwrite($fp, chr(a));
try this: fwrite($fp, "a"));
or this: fwrite($fp, chr(97));

Good luck!

cr0sh2:

Yea, I'm pretty sure that PHP is sending data to the serial port. I wrote a simpler script to test if it was even sending data at all. It looks like this:

void setup(){
 
 Serial.begin(9600);
 pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
}
 void loop(){
  
  if (Serial.available() > 0) {
   digitalWrite(2, HIGH);
   delay(1500);
   digitalWrite(2,LOW);
   delay(1500);
   
    
  }else{
    digitalWrite(3, HIGH);
    delay(1500);
    digitalWrite(3, LOW);
    delay(1500);
    
  }
 }

Then I launch the same PHP script as in my initial post, and the LED starts blinking. So I know PHP is sending data. The problem exists that I don't know exactly what PHP is sending, and I don't know exactly how Arduino is interpreting what PHP is sending.

I've tried using the chr() function in PHP, I've tried omitting that function, I've used single quotes and double quotes, I've tried sending just the ASCII number for the corresponding Switch statements. I've pulled my hair out, and drank myself into a coma. No ideas yet. And unfortunately, scouring the web for "PHP to Arduino" doesn't seem to show me any people who've had similar difficulties. Everyone else seems to get this up and running with little to no difficulties. Anyone else have some ideas?

There is a free serial port monitoring application called PortMon out on the net that will show exactly what is being sent and received on the computer serial port (I use it fairly often). I'm new to this forum and am curious as to the apparent love affair with PHP. Seems it is not well suited for serial port operations.

PHP plays well with MySQL and Apache, all of which are free.

All of which were also first developed on Linux, and then ported to Windows.

The problem with PHP and serial port communication is with the underlying Microsoft code that is the real interface with the psuedo-serial port via USB that is used today.

And, of course, the limited ability to debug applications on the Arduino.

@soup

I wonder what happens if you send more than one character to the Arduino from PHP. Try sending it a long string. Make the LED blink when you've read a character, not just when there is data to read. Unless you remove the characters from the serial buffer, they will stay there, no matter how many times you call Serial.available().

For out going serial commands I just use apache and notepad made files. For bidirectional serial I've used a simple application made with freebasic. Seems PHP may be more suited to database applications than robotic control. I started out using qbasic to operate my servo pan/tilt cam in 2001 when I got a cable connection, switched to the notepad files in 2003, and still working (below). Simple, but does what I need.

http://web.comporium.net/~shb/wc2000-PT-script.htm

Thanks for all the advice. I feel like I'm close here, but not quite there yet.

So I took zoomkat's advice and downloaded/installed PortMon. I crank it up and use my little PHP snippet above with the following results:

0.04127871  Apache.exe      IRP_MJ_CREATE      VCP0      SUCCESS      Options: Overwrite       
0.00092796  Apache.exe      IRP_MJ_WRITE      VCP0      SUCCESS      Length 2: 97      
0.00000343  Apache.exe      IRP_MJ_CLEANUP      VCP0      SUCCESS            
0.11261471  Apache.exe      IRP_MJ_CLOSE      VCP0      SUCCESS

Now my challenge is deciphering what that exactly means. There are four lines of results there. the second line ends with '97' which is an ASCII 'a' (and that's what the PHP code above is sending). What do the other lines mean? Could it mean that Windows is sending more than just the ASCII 'a' that I want it to? Could it be that I'll have to analyze the incoming data on the Arduino byte by byte to parse out the unwanted bits?

I know I've already said it, but thanks for all of your help and advice. This might honestly be the best forum I've ever participated in, due largely to the members! Keep up the good work guys/gals!

Oh, and thanks for being patient w/ me as I learn.

The third column implies that the connection to the port was made, that some data was written to the port (probably using a buffer), that the buffer was flushed (the data was actually sent), and that the port was closed.

All that should have arrived at the Arduino was the letter 'a'.

IRP - I/O Request Packet; a request sent to an I/O driver
MJ - Major Function Code

CREATE - request to create a handle ("open" for us non-Microsoft / normal folks)
WRITE - fairly obvious
CLEANUP - ditto
CLOSE - close the handle

VCP0 - name of the device (Virtual COM Port 0); "COM7" is the DOS name

"Length 2: 97" - I'm not familiar with PortMon but I assume that to mean two bytes were written: the character "9" (0x39) followed by the character "7" (0x37).

Man I'm totally frustrated at this point. I really thank you all for your input, but I'm tapped out. I can't seem to wrap my head around this concept.

Here's my dream:

I recently purchased a crappy USB web cam and I have some servos on the way via mail.

I'd like to build a web enabled pan/tilt camera like zoomkat has with my Arduino, Apache server and some sort of client-side programming language. My first instinct is to use PHP because I have some experience with it, and it's fairly simple and free.

If I'm able to get the pan/tilt camera working, the next iteration will be a web-enabled Etch-a-Sketch. I know others have done it, but not me... Not yet at least :wink:

So, I'll get this working eventually, and when I do, I'll make sure to credit all of you in my blog post.

I just have to wonder, if my PortMon results show that I'm sending an 'a' to Arduino, why didn't my initial code work? It should have! Dang, I'm frustrated. Another round of beers my good man!

(p.s., if there are any Atlanta, GA folks here, I'll gladly meet you for a beer if you'll solve my issue, and I'll pay!)

Cheers

I have controlled a big led screen using PHP remotely. It is almost the same problem, the way I managed this task is launching a system monitor that is monitoring certain files for changes (in your case for example, angles to update the camera) and this monitor "eats" this files, so php knows if the last instruction is applied.

Problems:
-Apache must allow "interactive" process (apache configuration)
-The monitor should be singleton (just one instance to avoid port sharing issues)
-The monitor should "monitor" files in such an elegant way like the filesystemMonitor object in c# to keep polling out your system

The monitor resides in the www folder (php just 'exec' init_monitor.cmd then edit the bin/screen files):
http://screencast.com/t/Mjc3MTEzODk

The files generated by php contains a special format for each line of the lcd screen, also the delay to send the next one (I use .temp extension files to work first from php because data is extracted from db with some delays and I don't want the monitor opening my files until I copy the final file with .screen extension):
http://screencast.com/t/MDcxYzRh

And voilá, a cute monitor icon with a little eyecandy :wink: (it blinks a little while sending a new screen):

Have you tried opening the port in binary mode?

The fwrite documentation is rather specific on the topic...

Note: On systems which differentiate between binary and text files (i.e. Windows) the file must be opened with 'b' included in fopen() mode parameter.

I'd be very systamatic trouble shooting the problem.

1). Can you get the arduino to do what you want using hyperterminal (or similar terminal application talking to the serial port) and is the expected response from the arduino received by hyperterminal? If not, then the arduino and its programming might be an issue.

2). Is PHP opening the serial port at the appropriate baud rate for the arduino?

3). Test your PHP program by connecting together the tx/rx lines supplying the arduino, then send a string and see if the PHP program returns the string. If this doesn't work, then there is a PHP issue with sending/receiving data, and possibly an issue with its interaction with apache.

4). If the issues can't be readily solved, then go ahead and set your webcam up the ol timey cgi way and work on the current issues as time permits.

Thanks all for the advice. I'm at the office now, but when I get home this evening, I'll try out a few things and report back to you all with my findings. Also, once I do finally figure this out, I'll make a detailed blog post explaining all my pitfalls, to save others in the future!

Thanks again!

Pitfall number one might be "Using Windows".

I'm sorry - I just had to say; couldn't stop myself! ;D

I guess its because I've been using *nix for so long, I've just gotten used to having things work (well, most of the time!).

Anyhow - I just want to offer up something on that portmon output; likely the "2" you are seeing has to do with the character you are sending ("a") plus another character (newline? null?) - however, that doesn't explain your issue...

You might try going old-school with an old computer running DOS (ack!) and QBASIC (double-ack!), so you can get direct port access, just to test your code on the Arduino; once you know that is working correctly, then you can concentrate on your Windows box; alternatively, you could do the same in *nix, and write directly to the USB port in your PHP script via fopen(). At least, once you know what is working, then you know what isn't (profound, I know).

Well I set up another sketch (it's not really important what it looks like) to test if hyperterminal would work sending serial data to the Arduino, and was successful. I easily toggled my little LED on and off.

This leads me to believe that my PHP is funky. I saw an earlier comment in this thread that I should try opening the serial connection for binary communication which I will try. I'll also make sure to determine what baud rate PHP is sending data at so I can be sure that it's in synch w/ Arduino. Man, I'm so close now I can taste it!

Thanks again all.