【问题标题】:Raspberry PI/PHP + Arduino serial communication树莓派/PHP + Arduino 串行通信
【发布时间】:2018-09-20 21:53:13
【问题描述】:

我将尝试对项目进行简要总结,然后是当前的代码方法。

  • 我有一个安装了最新 Stretch OS 的 RPi。
  • 我已经安装了 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“成功”回调。

但是因为我以前从未这样做过.. 我有点怀疑这是否可行.. 或者这是否是正确的方法。

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

这是我目前用来处理串口发送和等待/监听的sn-p:

[代码]

<?
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 sn-p调用)

//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 表单的提交状态:

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';
    }   
}

【问题讨论】:

    标签: php jquery ajax arduino raspberry-pi


    【解决方案1】:

    不能发表评论以提出建议(没有声誉) 我对 Ajax、jquery、Raspberry Pi 或 PHP 一无所知,但是...

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

    不是答案,而是建议。

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

    想一想,树莓派不是有串口吗? 如果是这样,您不需要 USB 转换器。只需在 Arduino 上设置一个软件串行端口并使用它连接到 Pi。您可以使用 USB 端口将调试 com 发送到您的计算机。

    【讨论】:

    • 如果您使用硬件串行引脚,则使用 USB/TTL 编程器只能与串行监视器一起使用,我的理解是? (即:USB)(根据我的理解不能与softserial一起使用??)我正在使用一个运行在5v和RPi运行@ 3.3v的UNO ..所以我需要一个杠杆移位器......它更容易不幸的是,以这种方式连接。我什至不知道在哪里/如何连接到 RPi 的串口?这些是GPIO引脚还是什么?某处特别断开的连接/标题?我想现在我想专注于对外部 php 脚本的 AJAX 调用.. OP 更新
    • usb/ttl 设备只能在硬件端口上作为编程器工作。但是,它将在任何引脚上作为普通串行端口工作。换句话说,虽然您无法使用软件串行端口上的设备对 Arduino 进行编程/更新,但您将能够监控/接收发送到该端口的任何内容。这意味着您可以在计算机上使用终端应用程序。
    • 我尝试使用 USB-TTL 电缆.. 但结果更糟糕.. 使用 USB-TTL 电缆.. 我什至无法向 Arduino 发送数据......更不用说阅读任何串行响应。基于 CP2102(或其他)的 USB-TTL 适配器......所以我回到了 USB 电缆......我已经稍微更改了脚本,以使用相同的 AJAX 调用将我的数据发送到(外部 PHP 脚本)Arduino ...并且我只为 WRITE & READ 操作打开 1 个端口。上面的 OP 用新方法更新。也许我应该开始一个新的帖子?
    • 你是如何连接电缆的?你用过 SoftwareSerial 吗?
    • 如果您在此处发布您拥有的 精确 设备(指向产品页面的链接会有所帮助),我可以帮助您完成它。可能就像为产品安装正确的驱动程序一样简单
    【解决方案2】:

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

    你的 serial_listener 很简单:

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

    所以,整个案例:

    前端 --post(d)--> serial_listener::COM1::send(d) ... COM1::read('OK') -->回复'成功'

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

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

    【讨论】:

    • 我不认为你理解......(或者我没有正确解释)......当页面已经呈现时,我怎么能将其视为“数据库”? (即:页面提交......串行数据发送出去......页面呈现以显示“请等待”消息......然后需要“等待”(听)来自Arduino的串行响应)..所以页面已经呈现,因此服务器端的东西是完整的......你上面的建议有什么意义?另外..永远不要使用 timeout() 或 delay()... 这是一个糟糕的建议。
    • 为什么你的 AJAX sn-p 使用 POST?唯一需要工作的部分是页面提交之后的 READING...。 (并且页面已经被解析/显示)..
    • 为什么您的示例使用 POST?为什么要通过 AJAX 调用将数据传递给 php 脚本?谢谢
    • 这只是一个例子,向您展示如何分离前端和后端(串行通信)。 POST 用于发送数据和数据(示例中的 var 字符串)包含有关订单的信息(订购了哪种饮料)。作为回应,除了状态(成功/错误)之外,您还可以获得其他信息(例如,3 号饮料已售罄)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-12
    • 1970-01-01
    • 2021-08-27
    • 2018-03-05
    • 2013-02-08
    • 2017-05-03
    相关资源
    最近更新 更多