Raspberry PI / PHP + Arduino串行通信

时间:2018-09-20 21:53:13

标签: php jquery ajax arduino raspberry-pi

我将尝试简要介绍该项目,然后介绍当前的代码方法。

  • 我所有的RPi都安装了最新的Stretch OS。
  • 我已经安装了MySQL,PHP,APahce和PhpMyAdmin,并且可以正常工作。
  • 我让它启动到默认的(本地托管)网页,并以全屏(KIOSK)模式启动。
  • 创建数据库,填充表格,查询到位..并且网页(饮料菜单)按预期正确显示。

  • 我的Arduino UNO通过USB连接到RPI
  • 网页上显示了一堆菜单选项。每个菜单选项都有自己的“订单”按钮。
  • 单击任何订单按钮时​​。我将此按钮数据保存到一个隐藏字段中,并使用jQuery提交/发布表单(自身)
  • 在$ _POST上,我抓取此提交的数据,并通过PHP通过串行通信1发送出去。

这是我目前的位置。

  • 因为我的Arduino通过USB连接到RPi。我无法使用串行监视器调试内容。...我在这里还有其他选择吗?

  • 提交网页时。.–我看到Arduino上的RX / TX指示灯闪烁(使我相信它正在接收串行数据)。.我可以/将检查它是否正确。今晚再次挂上步进电机,看看ti是否移到正确的位置...

这是我被困/绊倒的地方..可以通过一些讨论使我走上正确的道路。

因此,在Arduino“完成其魔力”之后..应该将确认消息发送回RPi ..说饮料已经完成..我可以返回主饮料菜单等待下一个订单

因为该网页已经$ _POSTed ..并且串行数据已发送到连接的Arduino .. ..然后我离开该页面,显示“请稍候”消息...但是因为该页面已经在服务器上解析事情的另一面,我现在需要如何通过PHP“监听”串行posrt。

我想..我可以使用一些AJAX来调用/加载一个外部php脚本..该脚本将等待/侦听串行端口..并将数据返回给AJAX'success'回调。

但是,因为我以前从未做过..如果这行得通..或者这甚至是正确的方法,我会有点怀疑。

还随机询问打开和关闭端口的最佳位置。特别是如果有2个单独的脚本? (即:我可以在一个脚本中打开该端口..仍然在另一个脚本中访问它吗?还是该文件正在访问它..需要成为打开它的那个文件?)

这是我当前的代码片段,用于处理串行端口的发送和等待/监听:

[代码]

<?
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?

    }    

}

甚至不知道应该在以下内容中输入什么:serial_listener.php脚本...只是一个while循环之类的东西?等待数据?或文件结尾或其他内容? (不确定在串行端口上使用fread()如何工作吗?)

任何建议可以帮助我解决这个问题。

更新:我不确定我是否正确/清楚地解释了事情?

但是,当页面提交(向自身提交)..就是将输出串行数据发送到连接的(通过USB到RPi的)Arduino。...

页面“发布”时,它会将上述数据发送出去..然后显示“请稍候”类型的消息。

在这一点上(据我所知)..服务器端脚本/解析现在已完成...,剩下的页面是“请稍候” ...

此时,解析/服务器端不再有任何操作。

这就是为什么我认为/开始对外部脚本进行AJAX调用的原因,该脚本可以坐在并“等待”(监听)串行端口(不清楚如何进行此操作……一段时间) ()循环或其他内容?)...

然后当数据最终返回时...

*

  

(没有告诉您此“序列号”需要多长时间   来自Arduino的反馈”。因为每种饮料的摄入量各不相同   时间来创建).........

*

它将使用AJAX'success'回调函数来更新页面..最终只需将其再次重定向回饮料主菜单页面..重新开始。

我不认为在Arduino上使用timeout()或delay()不仅是个坏建议(即:如果有帮助,请不要使用delay()).....但是我什至都看不到在哪里/为什么有道理吗?


更新:

和serial_listener.php脚本的内容:(脚本AJAX代码段调用)

//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);

}

最终更新:

我重新编写了一些东西,以便使用AJAX调用发送我的数据..并且还等待响应。 AJAX调用执行的外部php脚本是端口现在打开的唯一位置(我没有关闭它)

这是具有AJAX调用的PHP表单的SUBMIT状态:

数据发送在100%的时间内都有效。.但是我看不到我的回复。

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>
    <?             
}

以下是AJAX调用执行的serial_listener.php脚本的内容:

//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 个答案:

答案 0 :(得分:0)

无法发表评论(无声誉) 我对Ajax,jquery,Raspberry Pi或PHP不了解,但是...

如果您拥有this之类的USB串行转TTL设备,则可以使用SoftwareSerial库。在arduino上几个未使用的数字引脚上设置SoftwareSerial,并在那里发送调试信息。

不是答案,而是建议。

*********编辑***********

请考虑一下,Raspberry Pi是否没有串行端口? 如果是这样,则不需要USB转换器。只需在Arduino上设置softwareSerial端口,然后使用该端口连接到Pi。您可以使用USB端口的另一种方式将调试com发送到计算机。

答案 1 :(得分:-1)

首先,我没有Raspberry和Arduino的经验,但过去确实玩过串行通信。 您使事情变得太复杂了。串行通信不是历史通道中的奇特动物-将其作为数据层。您会轻松地创建所需的前端和后端IF数据是否来自/进入数据库?现在,以完全相同的方式实现您的系统,而不是使用串行通信来代替数据库连接。

您的serial_listener很简单:

  • 创建/配置端口
  • 发送数据
  • 读取数据
  • 关闭端口

因此,整个案例:

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

PS。 那些小型控制器... timeout()是您真正的朋友;)

对于串行通信,我建议使用一些库(例如php_serial.class)


我尝试用代码进行澄清。我试图使其保持简单,只是为了说明整个系统。

前端,纯js / html和AJAX请求:

<!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>

服务器端:

<?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);
?>

这样,您可以在屏幕上显示“正在加载...”图像,直到响应为止。最初呈现的页面一直存在。当然,当串行等没有响应时,您需要进行很多(错误)检查,解决方案等。但是基本系统不是“火箭科学”。