2
votes

I'll try to give a brief summary of the project and then the current code approach.

  • I have a RPi all set up with the latest Stretch OS.
  • I have installed MySQL, PHP, APahce and PhpMyAdmin and it working correctly.
  • I have it booting up to the default (locally hosted) webpage and in full screen (KIOSK) mode.
  • DB created, tables populated, queries in place.. and the webpage (drink menu) is displaying correctly as expected.

  • I have my Arduino UNO connected to the RPI via USB
  • The webpage displays a bunch of menu options.. each with its own 'order' button.
  • When any order button is clicked.. I save this button data to a hidden field, and use jQuery to submit/post the form (to itself)
  • Upon $_POST I grab this submitted data, and send it out via PHP over serial comm 1.

And here is where I am currently.

  • Since my Arduino is connected via USB to the RPi. I can not use the serial monitor to debug things.... do I have any other options here?

  • When I submit the webpage.. I -do- see the RX/TX lights on the Arduino blinking (leading me to believe it is receiving the serial data).. I can/will check if it is correct tonight by hooking up the stepper motor again and see if ti moves to the correct position(s)...

Here is where I am stuck/stumped a bit.. and could use some discussion to get me on the right path.

So after the Arduino 'does its magic'.. it is supposed to send a confirmation message back to the RPi.. saying the drink is complete.. and I can go back to the main drink menu awaiting another order

Because the webpage has already $_POSTed..and the serial data sent to the connected Arduino.. .. I then leave the page displaying a 'please wait' message... but because the page is already parse on the server side of things, I am left with the need on how to 'listen' to the serial posrt via PHP now.

I figured.. I could use some AJAX to call/load an external php script.. that will just wait/listen to the serial port.. and return the data to the AJAX 'success' callback.

But as I have never done this before.. I'm kind of leery if this will work.. or if this is even the correct way to do so.

Also random questions about the best place(s) to open and close the port.. especially if there is 2 separate scripts? (ie: can I open the port in one script.. and still access it in another? or does that file accessing it.. need to be the one that opens it?)

Here is my current snippet to handle the sending and waiting/listening of the serial port:

[code]

<?
if ($mode == 'submit') {

    //grab posted data (save to var)
    $drinkRecipe = $_POST['selectedDrink'];

    //set-up com port    
    exec("mode /dev/ttyACM0 BAUD=9600 PARITY=N data=8 stop=1 xon=off");
    //saw this on several RPi posts?  (but not sure of the difference? or why one would be used over the other?)
    //stty -F /dev/ttyACM0 cs8 9600 ignbrk -brkint -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts

    //open serial port
    $fp = fopen("/dev/ttyACM0", "w+"); //w = write w+ = read/write

    //check if open
    if (!$fp) {
        echo "Not open";
        //die();
    } else {
        //if open send data (via PHP) to connected Arduino on serial comm port 1 (ttyACM0)
        fwrite($fp, '<' . $drinkRecipe . '>');


        //arduino takes serial data, parsed it.. does it duty, 
        //and is supposed to reply back via serial to the awaiting (listening) 
        //PHP script executed via AJAX, since the front end needs to display 
        //a 'waiting' type message.. and the callback 'success' will 
        //re-direct back to menu/initial state
        ?>
        <script type="text/JavaScript" language="JavaScript">
            $.ajax({
                //async: false,
                //type: "POST",
                url: "serial_listener.php",

                //define success handler actions
                success: function(response) {
                    //alert("PHP RETURN CHECK: "+response);
                    if($.trim(response) == 'complete'){
                        alert("Drink making is complete... return to main menu");
                        //do redirect here
                    }else{
                        alert("Some value other than 'complete' was returned... look into it!");
                        //not sure what to do? (back to main menu anyways?)
                    }
                },
                //define error handler actions
                error: function(response) {
                    alert("PHP SERIAL READ FAIL: "+ 'Ready State: '+ response.readyState + ' Status: ' + response.status);

                }
            }); 
        </script>       
        <?              

        //close connection
        fclose($fp); //needed? //should this go in the external php script instead now?

    }    

}

Not even sure what should go into the: serial_listener.php script yet... just a while loop or something? Waiting for data? or end of file or something? (not sure how that works using fread() on serial port?)

Any suggestions to try and wrap my head around this is appreciated.

Update: I'm not sure if I am not explaining things correctly/clearly?

But when the page submits (to itself).. that is when the OUTGOING serial data is sent to the connected (via USB to the RPi) Arduino....

When the page 'posts' it sends the above data OUT.. and then displays a 'please wait' type of message.

At this point (as far as I understand it).. the server side script/parse is now COMPLETE... and I am left with a page saying 'please wait'...

There is no more parsing/server side ANYTHING going at this point..

That is why I thought/brought up the use an AJAX call to an external script that can sit and 'wait' (listen) to the serial port (un-clear as to how best going about this... a while() loop or something?)...

and then when the data eventually comes back...

*

(which there is no telling how long it will take for this 'serial feedback' from the Arduino.. as each drink takes different amounts of time to create).........

*

it will use the AJAX 'success' callback function to then update the page.. and ultimately just re-direct it back to the main drink menu page again.. to start all over.

I dont feel the use of timeout() or delay() on the Arduino is not only bad advice (ie: never use delay() if can help it)..... but I dont even see where/why that makes any sense?


Update:

And the contents of the serial_listener.php script: (script the AJAX snippet calls)

//set-up com port    
exec("mode /dev/ttyACM0 BAUD=9600 PARITY=N data=8 stop=1 xon=off");

//open serial port
$fp = fopen("/dev/ttyACM0", "w+"); //w = write w+ = read/write

//check if open
if (!$fp) {
    echo "Not open";
    //die();

} else {

    while(!feof($fp)){
        $response = fread($fp, 10);
    }
    echo $response;
    fclose($fp);

}

Final update:

I re-wrote things to use the AJAX call to SEND my data.. and also wait for the response. The external php script the AJAX call executes is the ONLY place the port gets opened now (and I am not closing it)

Here is the SUBMIT state of the PHP form that has the AJAX call:

The sending of data works 100% of the time.. but I can NOT read my response.

if ($mode == 'submit') {

    //grab posted data (save to var)
    $drinkRecipe = $_POST['selectedDrink'];

    ?>  
    <div id="waitingContainer">
        <p>Please wait, your brink is being made.</p>
    </div>

    <script type="text/JavaScript" language="JavaScript">
        console.log("ajax routine hit");

        //var drinkRecipe = "<?php echo $drinkRecipe ?>";
        var drinkRecipe = "<?=$drinkRecipe?>";

        var xhr = $.ajax({
            //async: false,
            type: "POST",
            url: "serial_listener.php",
            //datatype: "html",
            datatype: "text",
            data:({"drinkData":drinkRecipe}),
            //define success handler actions
            success:function(response) {
                //alert("PHP RETURN CHECK: "+response);
                if($.trim(response) == 'complete'){
                    console.log("Drink making is complete... return to main menu");
                    //do redirect here
                }else{
                    console.log("Some value other than 'complete' was returned... look into it!");
                    console.log("RESPONSE SENT WAS: " + response);
                    //not sure what to do? (back to main menu anyways?)
                }
                //kill the request
                xhr.abort();
            },
            //define error handler actions
            error: function(response) {
                console.log("PHP SERIAL READ FAIL: "+ 'Ready State: '+ response.readyState + ' Status: ' + response.status);
                //kill the request
                xhr.abort();
            }
        });     
    </script>
    <?             
}

Here are the contents of the serial_listener.php script the AJAX call executes:

//data sent from AJAX call (works)
$drinkData = $_POST['drinkData'];

//open serial port
$fp = fopen("/dev/ttyACM0", "w+"); //w = write w+ = read/write  (works)
//$fp = fopen("/dev/ttyUSB0", "w+"); //w = write w+ = read/write  //tried with USB-TTL cable too.. couldnt even send data)

//check if open
if (!$fp) {
    echo "Not open";
    //die();    
} else {

    if($drinkData != ''){   
        //send drink data
        fwrite($fp, '<' . $drinkData . '>');

        //wait for response
        $chars = "";
        do{
            $char = fread($fp, 1);
            $chars .= $char;
        }while(strlen($char) < 1);
        echo $char;
    }else{
        echo 'drink recipe is empty';
    }   
}
2

2 Answers

0
votes

Can't comment to make a suggestion (no reputation) I have no knowledge on Ajax , jquery, Raspberry Pi or PHP but...

If you have a Serial to USB TTL device like this you can use the SoftwareSerial library. Set up SoftwareSerial on a couple of unused digital pins on the arduino and send debugging info out there.

Not an answer, but a suggestion.

*********Edit***********

Come to think of it, doesn't the Raspberry Pi have a serial port? If so you don't need the USB converter. Just set up a softwareSerial port on the Arduino and use that to connect to the Pi. Taht way you can use the USB port to send debug coms to your computer.

-1
votes

First, I dont have expirience with Raspberry nor Arduino, but do have played with serial communication in the past. You are making things waay too complicated. Serial communication is not some strange animal from history channel - take it as a data layer. You would easely create needed front- and backend IF data would come from/go to database? Now, implement your system exactly same way, just instead of database connection use Serial communication.

Your serial_listener is simple:

  • create/configure port
  • send data
  • read data
  • close port

So, whole case:

frontend --post(d)--> serial_listener::COM1::send(d) ... COM1::read('OK') -->reply 'success'

PS. with those small controllers... timeout() is your real friend ;)

And for serial communication I would suggest to use some library (e.g. php_serial.class)


I try to clarify with a code. I try to keep it as simple, just to illustrate the system as a whole.

Frontend, pure js/html and AJAX request:

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body onLoad="$('#loading-image').hide();">


<div width="100%" style="text-align: center;">
    <div id="demo">
        <h2>Content: forms/scripts/...</h2>
    </div>
    <div>
        <button type="button"
            onclick="makeSerialCall('serial.php')">order (send AJAX call to php script)
        </button>
    </div>
</div>
<img id='loading-image' src='https://media.tenor.com/images/011ebf9c192d1c9b26f242d526ee24bb/tenor.gif'></img>


<script>
var string = 'data which is collected from content above';

function makeSerialCall(url) {
        $('#loading-image').show();
        $.ajax({
            type: "POST",
            url: url,
            data: string,
            cache: false,
            success: function(response){
                $('#loading-image').hide();
                console.log(JSON.stringify(response['info']));
                //and whatever else you want to do afterwards...
            }
        });
}
</script>
</body>

Serverside:

<?php
if(!empty($_POST))
  $data = $_POST["data"];

include "php_serial.class.php";

$serial = new phpSerial();
$serial->deviceSet("/dev/ttyUSB0");
$serial->confBaudRate(9600);
$serial->confParity("none");
$serial->confCharacterLength(8);
$serial->confStopBits(1);
$serial->confFlowControl("none");

$serial->deviceOpen();
$serial->sendMessage($data);
$read = $serial->readPort();
$serial->deviceClose();

header('Content-type: application/json');
$response_array['status'] = 'success'; 
$response_array['info'] = 'some additional info:'.$read;   
echo json_encode($response_array);
?>

This way you have "loading.." image on the screen until response. Initial rendered page is there all the time. Ofcourse, you need alot of (error)checking, solution when there's no response from serial etc.etc. But basic system is not "rocket science".