PHP serial port data return from Arduino
Asked Answered
C

3

15

I wonder if there is a way to accomplish reading my serial port via PHP - that works :-)

In practising my Arduino skills, I developed a simple LED ON/OFF sketch. It works by entering on or off in the serial monitor.

Next step, I put together a webpage to act as an GUI interface to click a link and perform the on and off function above. This webbased GUI works via PHP. I am using the PHP SERIAL class to interact with the serial port my Arduino is using.

The issue is I need to find a way of getting feedback from the serial port. Using the Arduino IDE serial monitor, I can see my printed messages in response to each of my serial input and I need to retrieve the same feedback in my PHP code.

The PHP Serial class offers a readPort() function but I does not return my data.

UPDATE[2]:

ARDUINO:

const int greenPin = 2;
const int bluePin = 3;
const int redPin = 4;

int currentPin = 0; //current pin to be faded
int brightness = 0; //current brightness level

void setup(){
  Serial.begin(9600);

  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  pinMode(redPin, OUTPUT);
}

void loop(){
  //if there's any serial data in the buffer, read a byte
  if( Serial.available() > 0 ){
    int inByte = Serial.read();

      //respond only to the values 'r', 'g', 'b', or '0' through '9'
      if(inByte == 'r')
        currentPin = redPin;

      if(inByte == 'g')
        currentPin = greenPin;

      if(inByte == 'b')
        currentPin = bluePin;

      if(inByte >= '0' && inByte <= '9'){
        //map the incoming byte value to the range of the analogRead() command
        brightness = map(inByte, '0', '9', 0, 255);
        //set the current pin to the current brightness:
        analogWrite(currentPin, brightness);
      }

      Serial.print("Current Pin : ");
      Serial.println(currentPin);

      Serial.print("Brightness : ");
      Serial.println(brightness);

  }//close serial check

}

PHP/HTML:

<?php
    require("php_serial.class.php");
// include("php_serial.class.php");

    // Let's start the class
    $serial = new phpSerial();

    // First we must specify the device. This works on both Linux and Windows (if
    // your Linux serial device is /dev/ttyS0 for COM1, etc.)
    $serial->deviceSet("/dev/ttyACM0");

    // Set for 9600-8-N-1 (no flow control)
    $serial->confBaudRate(9600); //Baud rate: 9600
    $serial->confParity("none");  //Parity (this is the "N" in "8-N-1")
    $serial->confCharacterLength(8); //Character length     (this is the "8" in "8-N-1")
    $serial->confStopBits(1);  //Stop bits (this is the "1" in "8-N-1")
    $serial->confFlowControl("none");

    // Then we need to open it
    $serial->deviceOpen();

    // Read data
    $read = $serial->readPort();
print "<pre>";
print_r($read);
print "</pre>";

    // Print out the data
    echo $read;
        // print exec("echo 'r9g9b9' > /dev/ttyACM0");
    print "RESPONSE(1): {$read}<br><br>";

    // If you want to change the configuration, the device must be closed.
    $serial->deviceClose();
?>

<?php
    if( isset($_REQUEST['LED']) )
        response();
?>

<form action='index.php' method='POST'>
    <select id='led' name='LED'>
        <option id='nil'>-</option>
        <option id='red'>RED</option>
        <option id='green'>GREEN</option>
        <option id='blue'>BLUE</option>
        <option id='all'>ALL</option>
    </select>
    <input type='submit' value='SET'>
</form>

<?php
    print "Hi, Earthlings!";

    function response(){
        $CMDString = "";
        $execute   = false;

        if( isset($_REQUEST['LED']) ){
                switch ($_REQUEST['LED']) {
                    case 'RED':
                        $CMDString = 'r9';
                        $execute = true;

        exec("echo 'r9g0b0' > /dev/ttyACM0");

                print "<br>FOUND: {$_REQUEST['LED']}";
                        break;
                    case 'GREEN':
                        $CMDString = 'g9';
                        $execute = true;
                print "<br>FOUND: {$_REQUEST['LED']}";
                        break;
                    case 'BLUE':
                        $CMDString = 'b9';
                        $execute = true;
                print "<br>FOUND: {$_REQUEST['LED']}";
                        break;
                    case 'ALL':
                        $CMDString = 'r9g9b9';
                        $execute = true;
                print "<br>FOUND: {$_REQUEST['LED']}";
                        break;
                    default:
                        print exec("echo 'r0g0b0' > /dev/ttyACM0");
                        $execute = false;
                        break;
                }

                if($execute){
                    print exec("echo '{$CMDString}' > /dev/ttyACM0");
                    print "<br><br>executing: {$CMDString}";
                }
        }
    }
?>
Cryptoanalysis answered 28/10, 2012 at 23:53 Comment(0)
T
14

I assume you work on linux.

First setup your serial port:

stty -F /dev/ttyACM0 cs8 9600 ignbrk -brkint -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts

Then you can use good old fashion fread/fwrite

$fp =fopen("/dev/ttyACM0", "w+");
if( !$fp) {
        echo "Error";die();
}

fwrite($fp, $_SERVER['argv'][1] . 0x00);
echo fread($fp, 10);

fclose($fp);

There is only one thing you have to remember. Arduino will restart on every connection. If you don't know that It will confuse you. For instance if you connect (fopen) and instantly send data Arduino will miss it because it's booting (which takes a sec or two). Experiment with sleep to give it some time. If you want to disable restarting use 10uF capacitor from GRD to RST.

Good luck

ps. you can troubleshoot with "screen"

screen /dev/ttyACM0 9600

Post about setting PHP with Arduino http://systemsarchitect.net/connecting-php-with-arduino-via-serial-port-on-linux/ and one more here http://systemsarchitect.net/arduino-and-php-serial-communication-with-a-protocol/.

Teeny answered 26/1, 2013 at 19:53 Comment(8)
Thank you for your very helpful comments. I have successfully applied a 10uF capacitor to my setup. So I no longer need to have the Arduino serial monitor open. I can now just use a web interface to control my RGB-LED experiment. The only issue is I still do not get any return statements from my Aduino code I:E in the serial monitor I have confirmation statements like "RED ON". In my web interface I an not getting this very important data. I executed your stty command successfully but it made no difference. Can you please give me some more help?Cryptoanalysis
Could you paste your code for Arduino and PHP? Ot's hard to tell without it.Teeny
Hi Lukasz, I have updated my question with the latest PHP/HTML code and included my Arduino sketch. The PHP includes the PHP_Serial class downloadable from the link in my question.Cryptoanalysis
I see you only ready Arduino output on the beginning of your script. Is there anything in $read variable? From Arduino code I can understand you have to send 2 bytes first to get any output. I don't know the library you are using. You can use simple fopen(), read() and wrtie().Teeny
Hi Lukasz, your ongoing help has been invaluable and is very appreciated. I am marking your answer correct but I will appreciate more help with yet more complications I am experiencing. Your strategy of opening and reading the port works but only intermittently i.e : it works sometimes but the majority of the time, I get no output. When I do get output, it's everything in the serial port rather than the most recent. Can you offer more advise on this, please? PLUS, can you explain what the "stty ..." command code does? It doesn't seem to help my situation.Cryptoanalysis
The stty command just makes sure the device will be Arduino friendly (for example it sets transition speed to 9600bps). /dev/ttyACM0 is just a pipe. It doesn't have any intelligence to serve you data in convenient packages. You read N amount of bytes and if something is there then you get it. It's good to know how much data you want to read. Look at this example I created for inter process communication (github.com/lukaszkujawa/php-multithreaded-socket-server/blob/…) handleProcess() and broadcast().Teeny
...First 4 bytes of data I send to pipe is an integer so later when I read from the pipe I read only 4 bytes to find out how many bytes I have to read. Experiment with pipes outside from the Arduino to get a good understanding of what are you doing.Teeny
In case you still have some problems with serial communication I created a small library for Arduino (github.com/lukaszkujawa/arduino-serial-helper). I also described idea behind it here systemsarchitect.net/…. Hopefully that will help.Teeny
P
3

/dev/ttyUSB0 running with user root, if your using apache try chown /dev/ttyUSB0 to apache or user is logged in.

$ sudo chown apache2:apache2 /dev/ttyACM0
OR
$ sudo chown yourusername:yourusername /dev/ttyACM0

and then try again, or try logout from ubuntu and login as root user.

Partisan answered 24/12, 2012 at 0:26 Comment(2)
symfony.com/doc/current/reference/constraints/…Alveolate
You should probably add the Apache user to dialout group instead of changing the owner or permissions of the device.Honeyman
D
2

You are probably trying to read when is no data on the serial port. You need to implement JavaScript code to call PHP code that can read at regular intervals.

When you have got data, you should process it.

readPort() has worked fine for me. If the baud rate, parity, etc. is adjusted properly, then you should not have any problem reading the serial port.

Here is a sample of using the library for Arduino. It worked for me some time ago:

<?php
    include "php_serial.class.php";

    // Let's start the class
    $serial = new phpSerial();

    // First we must specify the device. This works on both Linux and Windows (if
    // your Linux serial device is /dev/ttyS0 for COM1, etc.)
    $serial->deviceSet("/dev/ttyUSB0");

    // Set for 9600-8-N-1 (no flow control)
    $serial->confBaudRate(9600); //Baud rate: 9600
    $serial->confParity("none");  //Parity (this is the "N" in "8-N-1")
    $serial->confCharacterLength(8); //Character length     (this is the "8" in "8-N-1")
    $serial->confStopBits(1);  //Stop bits (this is the "1" in "8-N-1")
    $serial->confFlowControl("none");

    // Then we need to open it
    $serial->deviceOpen();

    // Read data
    $read = $serial->readPort();

    // Print out the data
    echo $read;

    // If you want to change the configuration, the device must be closed.
    $serial->deviceClose();
?>
Duff answered 29/10, 2012 at 9:11 Comment(8)
I know what the baud rate is but do you mind telling me what parity is and how to correctly configure it in this context?Cryptoanalysis
@Cryptoanalysis i have edited my answer with an example of using this library.Hope you will find it usefulDuff
thanks for your answers and code example. I updated my code with extracts of your but I still have no feedback. I updated my original question with my PHP/HTML script. I should be getting some feedback in 3 places but nothing is coming through. I should point out that my port (/dev/ttyACM0) is set to chmod 777 and I am actually calling Serial.println in my Arduino sketch which is why I am expecting some data to be returned in PHP. Infact, each time I use my web interface my LEDs successfully respond and my Arduino serial monitor prints my message(s)Cryptoanalysis
what operating system do you have witch apache version / php do you use ?Duff
The operating system is Linux Ubuntu-12, PHP is Version 5.3.10 and Apache is Apache/2.2.22Cryptoanalysis
@Cryptoanalysis can you see the serial output in Arduino IDE (SerialMon ) ?Duff
btw maybe apache hasn't rights to access the serial port. I don't think is a code issueDuff
Yes, I can see serial output in the Arduino IDE. Even when I use my PHP web interface output occurs in the IDE. I don't know how Apache might be interfering with PHP return data from my port but I will start googling. Can you offer any suggestions?Cryptoanalysis

© 2022 - 2024 — McMap. All rights reserved.