前言
相信很多PHP程序员都遇到一个棘手的问题,PHP如何与PLC进行通讯。
PHP作为一种非常流行的编程语言,里面涵盖了几乎所有Web服务的优势,但也由于他Web服务的偏向性,对于本地功能化的诉求和拓展相比就很弱。
当你使用PHP做工业控制系统,如WCS,MES的时候,更是发现这点,有时候一个简单的需求,基本会让你接近崩溃,譬如“如何与PLC进行通讯”就是一个很好的例子。
工业控制现场,有成百上千种PLC和PLC协议,而你在Github里面搜索相关关键字,你会发现,竟然没有一款针对PLC的PHP扩展,即便连OPCUA这种标准的扩展,都没有。
为PHP提供一个与PLC沟通的渠道,我认为是有必要的,由于我本人也是工业自动化系统的研发者,包括MES和WCS都使用了基于PHP+Workerman的架构,因此对这个需求更加是迫切。
解决方案
而LECPServer,可以成为PHP与PLC中间非常良好的沟通桥梁。
LECPServer 全称 Leanboard Equipment Communication Proxy Server 是一款基于 JLean 框架开发的高性能工业用组态服务软件,可以通过该组态软件,链接市面上90%的PLC,通过HTTP协议通联PLC的读写,使用户能够通过一个直观的用户界面来连接、管理、监视和控制不同的自动化设备和软件应用程序。
由于LECPServer也是基于Web服务的架构基础,因此只要能通过HTTP POST方式进行Request的客户端,就自然而然的能与PLC进行通讯了,其中当然包括PHP这种生为Web服务的语言平台。
安装和环境
首先,可以先到官网下载一个 LECPServer的最新版 http://www.lecpserver.com/downloads/LECPServer.zip
LECPServer是免安装的,直接放到文件夹内即可运行,运行需要下面的支持环境
- Microsoft .NET Framework 4.6.1或以上
- Visual C++ Redistributable Packages for Visual Studio 2013
下载连接我也放在下面
Microsoft .NET Framework 4.6.1 https://dotnet.microsoft.com/download/dotnet-framework/thank-you/net461-web-installer
Visual C++ Redistributable Packages for Visual Studio 2013 https://www.microsoft.com/zh-cn/download/details.aspx?id=40784
安装完成后,双击 LECPServer.exe 就可以启动程序了
使用样例
我们以连接 欧姆龙 CP1H 的PLC为例子,演示怎么通过LECPServer与欧姆龙CP1H进行通讯。
基础配置
我们通过以太网连接欧姆龙CP1H,PLC的IP设置为192.168.3.20,本机IP设置为192.168.3.202
通过LECPServer的配置界面,配置对应的参数,如图:
然后点击应用,当你看到设备栏的列表指示为绿色,则说明PLC已经正式连接成功了
这时候我们可以通过HTTP POST的调试工具,如POSTMAN,HTTP Debug来测试下是否能正常读写,我们这里选用LECPServer自带的HTTP调试器。
我们先发送 plc_read_node 命令查看D0000的值
{
"action": "plc_read_node",
"node": "NODES.CP1H.D0000"
}
// 返回
{
"errcode": 0,
"errmsg": "",
"rtval": [
0
]
}
代表节点D0000的长度是1,第一个值为0,我们通过命令 plc_write_node 尝试改变 D0000的值
{
"action": "plc_write_node",
"node": "NODES.CP1H.D0000",
"value": [
998
]
}
// 返回
{
"errcode": 0,
"errmsg": ""
}
返回没有错误,代表成功改变D0000的值,然后我们再通过 plc_read_node 命令验证下是否成功改变
{
"action": "plc_read_node",
"node": "NODES.CP1H.D0000"
}
// 返回
{
"errcode": 0,
"errmsg": "",
"rtval": [
998
]
}
到此,我们的准备工作都已经完成了,接下来就是PHP的编码阶段了。
PHP编码
这里的PHP样例,我们使用 PHP7.1 + Workerman 来完成,而通过FastCGI方式也与之基本类似。
直接上代码
<?php
use Workerman\Worker;
use Workerman\Mysql;
use \Workerman\Lib\Timer;
use \Workerman\Protocols\Http;
use \Workerman\Protocols\Http\Response;
use \Workerman\WebServer;
// 使用 curl 扩展的 http 客户端函数
function curl_http_request($url, $type, $data = ""){
$ch = curl_init();
$timeout = 1;
curl_setopt( $ch , CURLOPT_TIMEOUT, $timeout );
curl_setopt( $ch , CURLOPT_CONNECTTIMEOUT_MS, 200);
curl_setopt( $ch , CURLOPT_HEADER, false);
curl_setopt( $ch , CURLOPT_URL, $url);
curl_setopt( $ch , CURLOPT_RETURNTRANSFER, 1);
if($type == "POST"){
curl_setopt( $ch , CURLOPT_POST, 1);
curl_setopt($ch,CURLOPT_HTTPHEADER,array('Content-Type: application/json'));
curl_setopt( $ch , CURLOPT_POSTFIELDS, $data);
}else{
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1); // 从证书中检查SSL加密算法是否存在
curl_setopt($curl, CURLOPT_SSLVERSION, 3);
}
$output = curl_exec($ch);
curl_close($ch);
if($output!=""){
$val = json_decode($output,true);
return $val;
}else{
return null;
}
}
// 开启一个worker,并在里面启动定时器,每隔500ms对PLC点位D0000进行一次读写
$client_worker = new Worker();
$client_worker->name = "plc reader";
$client_worker->count = 1;
//服务启动
$client_worker->onWorkerStart = function($worker) {
// 将值从80开始计数,并递增
$count = 80;
Timer::add(0.5, function() use(&$count)
{
echo "开始读取PLC D0000的值 \r\n";
$rtval = curl_http_request("http://192.168.3.20:8088", "POST", '{"action":"plc_read_node", "node":"NODES.CP1H.D0000"}');
echo "PLC D0000读取成功 ";
echo json_encode($rtval) . "\r\n";
echo "开始写入PLC D0000的值 \r\n";
$rtval = curl_http_request("http://192.168.3.20:8088", "POST", '{"action":"plc_write_node", "node":"NODES.CP1H.D0000", "value":[' . $count . ']}');
echo "PLC D0000写入完成 ";
echo json_encode($rtval) . "\r\n";
$count ++ ;
});
};
// 如果不是在根目录启动,则运行runAll方法
if(!defined('GLOBAL_START')){
Worker::runAll();
}
?>
运行效果如下,可以看到,PLC被PHP程序正常的进行读写了。
附件:php_plc_reader 的源代码,源代码基于Workerman开发,具体配置可查阅Workerman相关文档,如果使用标注的Nginx+PHP,即使用上面代码段即可。
https://download.csdn.net/download/Xeden/15313318