Controlling Arduino via USB using PHP

Error message

Notice: Undefined index: secondary-links in menu_block_view() (line 462 of /home/aproject/public_html/modules/menu/menu.module).

As stated before, I have rather good experience in PHP programming. I’ve done many different things using PHP, starting from simple web applications to huge social network applications with tens of thousands simultaneous online users. I’ve also done some PHP applications that are used as servers for other software and even some basic desktop applications. With all that in mind, today I wanted to play around with Arduino and PHP. This might sound sick, but if you’ve read the previous posts, then you already know that PHP is my language of choice. The reason for this is simple - PHP can do a lot more than simple web applications. And if I know PHP, why do I need to learn other languages? Besides that I believe there are other programmers just like me - learning Arduino and having PHP experience in background. Actually the following post will work with any other programming language that can access serial ports.

Ok, enough talking, let’s get to the task. Actually I would like to divide it into two separate tasks:

  1. Learn to communicate to Arduino using PHP
  2. Write some PHP code and Arduino program that works together

Tying together the Arduino and PHP

Normally you can’t access directly USB devices, like you were able to connect and directly write some data to printer or COM port. For most USB devices you need to have a special driver that does the dirty job for you. Fortunately the designers of Arduino have done the USB connection a bit different way. Actually Arduino is working via USB serial controller, which means that you can open the USB port and write data directly to Arduino just like you can do it with LPT, and COM ports. If we remember our task, it’s exactly what we need - directly write some data from PHP to Arduino and process them on the board without any driver usage.

The next thing is to get the PHP to write some data to the USB port. When you open up your Arduino development environment, you can see which “com” port the Arduino board is connected to. Check once more the number of the port used and look at the code below:

$fp =fopen("com3", "w");
fwrite($fp, chr(1));
flose($fp);

The communication with COM ports from PHP is straightforward. Just open a file pointer to “comX” where X is the number of COM port and write some data to that COM port. In the example above we connect to COM3 port and write integer number 1 to that port (notice the chr(x) function - we can’t just directly write the integer, we need to encode it into ASCII character and chr() does just that).

So far so good. Now we need to decide what we will send to Arduino board and what we will want the arduino board to do for us. I guess the most easy task to check our skills is just passing random integers to arduino board, using one diode, which will flash one or two times depending on the parity of number passed.

Ok, let’s build up some Arduino code:

int ledPin = 13;
int usbnumber = 0;
void setup() {
    pinMode(ledPin, OUTPUT);
    Serial.begin(9600);
}

void loop() {
    if (Serial.available() > 0) {
        usbnumber = Serial.read();
    }

    if (usbnumber > 0) {
        if (usbnumber % 2 == 0){
            digitalWrite(ledPin, HIGH);
            delay(300);
            digitalWrite(ledPin, LOW);
            delay(300);
        }else{
            digitalWrite(ledPin, HIGH);
            delay(300);
            digitalWrite(ledPin, LOW);
            delay(300);
            digitalWrite(ledPin, HIGH);
            delay(300);
            digitalWrite(ledPin, LOW);
            delay(300);
        }
        usbnumber = 0;
    }
}

Ok, let’s get through this step by step. Just before the setup function we define that we will use the 13th pin for output, besides that we initialize the variable that will hold the number read from USB. In the setup function we define that the ledPin will be used for output and we start up the USB connection. In the main loop we check whether there is any data available on the USB connection. If there is any data, we just read the data to our usbnumber variable. Later on the loop we check if the number read is greater than zero. If it is, we know that some data has been read. We check if the number can be divided by two. If the remainder is zero, we flash the LED one time. If the reminder is 1 (the number we have read can not be divided by two), we flash the led two times.

Ok, so far with the arduino code. Let’s build some more PHP code:

$fp =fopen("com3", "w");
while (true){
    $i = ($i + 1) % 10;
    echo "Wrote $i - the LED should flash (" . ($i % 2 == 0 ? ' 1 time ' : '2 times ') . ")\r\n";
    fwrite($fp, chr($i));
    sleep(3);
}
fclose($fp);

There’s not that much of new things to talk about. Just like in the previous PHP code exmaple, this one is also opening a COM3 connection. The new part is the infinite loop, which contains the number writing to COM3 port. The code is simple - just increase the variable $i by one and take the modulus of the number. Afterwards just log some debug information to console and write the data to USB. After writing the data, just sleep for 3 seconds and repeat the loop.

Ok, the last bits of this long writeup:

  1. we need to upload the arduino code to our board
  2. we need to run the PHP code

The first one should be straightforward for everyone, just hit the appropriate button on the arduino development environment toolbar. The second one could be tricky for some people. But I’ll try to explain how I do it. Let’s pretend I’ve downloaded the Windows binary installation of PHP 5.2 and unzipped it to c:/php/. I enter the windows command line, change the directory to c:/php and type php c:/path/to/usb/php/script.php. Done! Watch the LED on the Arduino board and track the debug info on the commandline window.

Summary

I’ve learned some new things:

  • Basic controlling of Arduino board from PHP
  • The only pin that you can use without resistors is the 13th pin. To use leds directly with other pins you should use resistors. As you might imagine I don’t have any at the moment, so I’m just sticking to using just the 13th pin. I guess I’ll need to get more into the electronics stuff to achieve something more.

Well, that’s it for now. If there are any questions/comments - the comment form is below. I guess I’ll try to check out the Serial interface a bit deeper to find out what exactly you can do with the USB port. And one of the next things to find out will be the option to write functions to do common things. The arduino part of this example is begging for some refactoring.

Hold on and wait for the next posts. By the way, you can use the RSS feed to read the latest posts of this blog automatically.

Comments

hey! great blog, but i've got a little question
about launching the php code:
i have my own localhost (on a mac) but i really don't know wich directory i should launch the script?
you can reach me here

Not sure the script depends on a directory. I guess you can simply run it in terminal wherever it's located.

I have been looking and looking for some way to directly communicate to a usb port via web server side script! Question - In theory this could work in real time with, say, mouse coordinates from a remote site visitor *web user goes to site and controls input on the server usb to the adrino* - send the coordinates to the adrino all with some php coding?! Either this is a rare request of use of the usb as most PIC programmers use s232, or not many people have had a need to do such a thing. Another thing! Is adrino the only drivers that make it so simple to call the usb as a com? _ i will keep looking but ill be back _ :D

Do you have any experience with I2C ? I've basically done the same as you did, using the I2C device (on a linux system) - do you have any idea on how to check if a line (example data line) is "high" or "low" with php?

thanks,

tobi

Hi, i see your code to communicate the PC (with PHP) to the Arduino throw the serial port work very well, but did you find out how to make the arduino to comunicate to the PC using PHP throw the serial port?

Regards
Mauricio

PHP can't do bi-directional natively on a windows box, but with an extension you can. http://www.easyvitools.com/phpserial/index.html - it's $39 USD. Linux you can do it natively.

The other possible work around would be have a program you can read and write to a comport and make a stream of exec/system command.. Never have done that thou.

There are some issues between Arduino Diecimila and PC.

Everytime Arduino 10k receive an incoming serial stream it thinks that is getting a new code to boot so force a reset (DTR line).

This is a big issue: if you are using Arduino for sample temperature you lost the first samples.

Sorry I don't speak english only little.
I try this codes and many other.

Example:
<?php
require("php_serial.class.php");
$serial = new phpSerial();
$serial->deviceSet("COM9");
$serial->confBaudRate(9600); //Baud rate: 9600
$serial->confParity("none"); //Parity (this is the "N" in "8-N-1")
$serial->confCharacterLength(8); //Character length
$serial->confStopBits(1); //Stop bits (this is the "1" in "8-N-1")
$serial->confFlowControl("none");
$serial->deviceOpen();
$serial->sendMessage('2\r');
?>

int in = 0;
int ledPin = 13;
int st=LOW;

void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
pinMode(ledPin,OUTPUT);
}

void loop() {

// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
in = Serial.read();
if(in==49){
st=LOW;
}
if(in==50){
st=HIGH;
}

// say what you got:
// Serial.print("I received: ");
// Serial.println(incomingByte, DEC);
}
digitalWrite(ledPin,st);
}

I am running the hiperterminal and every OK. I push 2 button the led on if i push 1 button led off.
I am running the PHP program the LED on 1 second and OFF.

Hi, i've tried everything i could find on google, but nothing seems to work very well.

Then i found your page, and i had a good feeling about it cause you've explained it pretty clear..

well i tried it but it doesn't seem to work at all.

I use a
MacBookPro
Duemilanove ATmega 328
MAMP (server to run PHP)

I corrected the "COM3" port to "/dev/tty.usbserial-A6008i1S"

have you any idea what i could be doing wrong? I'd like to hear from you, anywayz

Greets Job

You can reach me at infoATthepaintjobDOTnl

I did something very similar using shell scripts under linux. I see you're using PHP under Windows. Perhaps you could use my code as a model. You'll need a background/helper process. See http://user.cavenet.com/rolandl for SMS1.tgz, a tarfile.

Hello, I've een your solution...but can you do a function to work with buttons?

php button who control the led 13, can you do that?
BECAUSE I have learned about your solution and I've maked a web server who controls the pin 13...but I have no functions is only serial comunication....

with a while loop on php....

:( help please