2019年12月16日

在Thingworx中绘制正态分布图


SPC分析中,正态分布图是使用较为频繁的图表。
本文介绍一下如何在Thingworx中绘制正态分布图。


如图所示,我们可以看到图表中包含:数据的分布情况(每个数据区间的数量),和参考正态分布曲线。

1.     绘图工具和注意项
我们可以用Label Chart工具来绘制图形。
注意不要选中“SingleDataSource”,这样我们可以引用两个数据源。
1个数据源引用自数据分布集,SeriesType1=Bar
2个数据源引用自正态分布集,SeriesType2=Line
两个数据集的X值应一致。
启用“YAxisAutoscale”,因为两个数据集的Y值是不一样的,自动缩放后数据会落到相同区间。

2.     数据分布计算
我们可以根据平均值和标准差来计算数据的分布。
标准差(σ)的计算可参考我的文章《Thingworx中的SPC计算工具》。
为了简化计算,我们选取常用的±3σ这个范围。
计算很简单,但是要注意一点:柱状图的X轴显示的是引用范围的起始值,但是我们在正态分布图中参考的是范围平均值,因此在最后,我们要把柱状图X轴加上0.5σ
下面是代码:
------------------------------------------------------------------------------
// To generate Histogram dataset for SPC
// Developed by Tallrain, Dec 2019
// Input
//    avg = Average
//    sd  = Standard Deviation
//    spcTable = SPC data, with field of SPC1 for data value
// Output
//    infoTable, with fields of value and count

var bar1 = avg-3*sd;
var bar2 = avg-2*sd;
var bar3 = avg-1*sd;
var bar4 = avg;
var bar5 = avg+1*sd;
var bar6 = avg+2*sd;
var bar7 = avg+3*sd;

var v1 = 0;
var v2 = 0;
var v3 = 0;
var v4 = 0;
var v5 = 0;
var v6 = 0;
//var v7 = 0;

var tableLength = spcTable.rows.length;
for (var x=0; x < tableLength; x++) {
    var row = spcTable.rows[x];
    var v = row.SPC1;
   if(v>=bar1 && v
   if(v>=bar2 && v
   if(v>=bar3 && v
   if(v>=bar4 && v
   if(v>=bar5 && v
   if(v>=bar6 && v  
}

bar1 = bar1 + sd*0.5;
bar2 = bar2 + sd*0.5;
bar3 = bar3 + sd*0.5;
bar4 = bar4 + sd*0.5;
bar5 = bar5 + sd*0.5;
bar6 = bar6 + sd*0.5;
bar7 = bar7 + sd*0.5;

// Output data
var params = {
    infoTableName : "InfoTable",
    dataShapeName : "DS_SPC_Histogram"
};

//CreateInfoTableFromDataShape(infoTableName:STRING("InfoTable"), dataShapeName:STRING):INFOTABLE(DS_SPC_CPK_OUT)
var spcOut = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape(params);
spcOut.AddRow({value:bar1, count:v1});
spcOut.AddRow({value:bar2, count:v2});
spcOut.AddRow({value:bar3, count:v3});
spcOut.AddRow({value:bar4, count:v4});
spcOut.AddRow({value:bar5, count:v5});
spcOut.AddRow({value:bar6, count:v6});
//spcOut.AddRow({value:bar7, count:0});

var result = spcOut;
------------------------------------------------------------------------------

3.     正态分布计算
算法可参考WIKI
在这里为了和柱状图契合,我们按照每0.5σ为基础单位进行计算。
要说明的是,正态分布公式的值并不是概率,X区间和曲线相交的面积才是概率。
具体的值和平均值、标准差相关,所以在绘制图表时要允许Y轴自动绽放,这样两个图才能匹配。
下面是代码:
------------------------------------------------------------------------------
// Generate SPC Normal Distribution
// Developed by Tallrain, Nov 2019
// Input
//    u = Average
//    sd = Standard Deviation
// Output
//    infoTable, with field of x and np

// Create temp InfoTable for output
var params = {
    infoTableName : "InfoTable",
    dataShapeName : "DS_Normal_Distrib"
};

// CreateInfoTableFromDataShape(infoTableName:STRING("InfoTable"), dataShapeName:STRING):INFOTABLE(DS_Normal_Distrib)
var tempInfoTable = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape(params);

// calculate normal distribution data
var e = Math.E; //2.71828182846;
var pi = Math.PI; // 3.14159265359;
for (var i=1; i <= 13; i++) {
    var x = (i-7)/2;
    x = u + x*sd;   
    var dividend = Math.pow(e, 0-((x-u)*(x-u)/(2*sd*sd)));
    var divisor = sd*Math.sqrt(2*pi);
    var np = dividend/divisor;
    //const dividend = Math.E ** -((value - this.mean) ** 2 / (2 * this.standardDeviation ** 2));
    //const divisor = this.standardDeviation * Math.sqrt(2 * Math.PI);
    //var np = 0-(x-u)*(x-u)/(2*sd*sd);
    //logger.info('np='+np);
    //np = Math.pow(e,np);
    //var np2 = sd*Math.sqrt(2*pi);
    //np = np/np2;
    //logger.info('np='+np);
    tempInfoTable.AddRow({x:x, np:np});   
}

var result = tempInfoTable;
//var result = Math.pow(3,2);
------------------------------------------------------------------------------


2019年12月9日

Thingworx的非官方扩展


我们知道PTC提供了官方商城: https://marketplace.ptc.com/
我们从官方商城可以下载很多常用的扩展,如JDBC Connector Extension、PTC ThingWorx-to-Windchill Connector、QRCode等。
这些扩展通常由PTC官方提供,也有一些是第三方的应用或解决方案如Callisto Digital Work Instructions。
但是官方商城的扩展很少。
PTC技术人员在论坛上推荐了另一个非官方扩展下载地址: https://github.com/ptc-iot-sharing
这是发布在github上的,大部分是开源包,基于Java或JavaScript开发,如有很多基于D3引擎开发的图形化数据展示工具。
大家可以尝试一下,当然稳定性方面可能和官方扩展有所差距。

2019年11月13日

Thingworx中的SPC计算工具


Thingworx提供了两个SPC计算工具: StatisticalCalculationThingShape,和StatisticalMonitoringThingShape,但前提条件是需要DescriptiveAnalytics平台。
大致步骤是:
1. 购买安装DescriptiveAnalytics。
2. 建立Thing,配置Data Shape和Value Stream,设置数值属性logged。
3. 调用StatisticalCalculationThingShape.QueryTimedValuesForProperty生成TimedValues类型的InfoTable。
4. 调用StatisticalCalculationThingShape.CalculateMeanValue等函数生成具体的SPC数值。
这种方式适用于工艺参数采集,即Thing和Property均已事先定义的情况下。

如果不采用DescriptiveAnalytics平台,或者说数据不适合用Value Stream记录(比如直接从拧紧枪数据库查询数据),那么就需要自己计算SPC了。
具体步骤为:
1. 经由数据库查询等方式生成InfoTable类型的数据集。
2. 调用infotable for loop方法,逐行读取并分析数据,计算最大值、最小值、平均值。
3. 利用数组暂存数据,然后读取数组,计算标准方差。不用数组的话,也可以将InfoTable重新读取一次。
4. 输出InfoTable类型的数据集。
以下是参考代码:
------------------------------------------------
// Get USL&LSL
var USL = spcTable.rows[0].USL;
var LSL = spcTable.rows[0].LSL;
//logger.info("USL="+USL);
//logger.info("LSL="+LSL);

// Get Sum
var sum = 0.0;
var spc1 = []; // array of spc1
var tableLength = spcTable.rows.length;
//logger.info("tableLength="+tableLength);
for (var x=0; x < tableLength; x++) {
    var row = spcTable.rows[x];
    spc1[x] = row.SPC1;
    //logger.info("spc1="+row.SPC1);
    sum = sum + row.SPC1;
}
//logger.info("x="+x);
//logger.info("sum="+sum);
//var result = sum;

// Get Average
var u = sum / tableLength;
//logger.info("u="+u);

// Get SD
var sd = 0;
for (x=0; x < tableLength; x++) {
    sd = sd + (spc1[x]-u) * (spc1[x]-u);
}
sd = sd/(tableLength-1);
sd = Math.sqrt(sd);
//logger.info("sd="+sd);

// Get CPU
var cpu = (USL-u)/(3*sd);
//logger.info("cpu="+cpu);

// Get CPL
var cpl = (u-LSL)/(3*sd);
//logger.info("cpl="+cpl);

// Get CPK
var cpk = 0;
if(cpu < cpl) {
cpk = cpu;
} else {
cpk = cpl;
}
//logger.info("cpk="+cpk);

// Output data
var params = {
    infoTableName : "InfoTable",
    dataShapeName : "DS_SPC_CPK_OUT"
};

// CreateInfoTableFromDataShape(infoTableName:STRING("InfoTable"), dataShapeName:STRING):INFOTABLE(DS_SPC_CPK_OUT)
var spcOut = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape(params);
spcOut.AddRow({Sum:sum, Avg:u, SD:sd, USL:USL, LSL:LSL, CPU:cpu, CPL:cpl, CPK:cpk, Qty:tableLength});

var result = spcOut;
------------------------------------------------

2019年11月4日

关于SQL SERVER的两个备忘



最近在用SQL SERVER做数据的后台自动处理,然后利用Thingworx展现。
这其中碰到两个问题,觉得较有代表性,在此做个备忘。

1. 关于游标内调用其它游标
我之前做过很多项目采用ORACLE数据库,其动态游标、物化视图、数组的功能非常NB,给我留下了深刻的印象。
但是我没想到在使用SQL SERVER游标时却踩到了坑。
SQL SERVER有一个全局变量@@FETCH_STATUS用来表示游标的状态,0表示尚未结束,-1表示已结束。
但是关键@@FETCH_STATUS是全局变量,这就意味着当第一个游标尚未结束时,当第二个游标的状态=-1时,也会将第一个游标强行结束。
解决的办法是用一个本地的变量,把@@FETCH_STATUS的值赋给此变量后再进行检查。
但是此办法逻辑上并不完备,如果有大量的并发,则可能会造成冲突。
因此如果需要配置后台任务,应该尽可能在时间上分散开来,以避免并发。
下面是相关的参考代码:

---------------------------------------------------------------------------
-- Normally, we use system variable @@FETCH_STATUS to check Cursor loop
DECLARE myCursor CURSOR FOR
SELECT fields FROM Table;
OPEN myCursor;
FETCH NEXT FROM myCursor INTO @myVar;
WHILE @@FETCH_STATUS = 0
BEGIN
  --DO somthing;
END
CLOSE myCursor;
DEALLOCATE myCursor;
 
-- But @@FETCH_STATUS is global variable
-- So if we use another Cursor within the loop, when inner loop is completed, @@FETCH_STATUS = -1, so the outer loop will also be closed.
-- Fixing method is to use local variable instead of @@FETCH_STATUS
DECLARE myCursor CURSOR FOR
SELECT fields FROM Table;
OPEN myCursor;
FETCH NEXT FROM myCursor INTO @myVar;
SET @Outer_loop = @@FETCH_STATUS;
WHILE @Outer_loop = 0
BEGIN
  --inner loop here
  DECLARE myCursor2 CURSOR FOR
  SELECT fields FROM Table2;
  OPEN myCursor2;
  FETCH NEXT FROM myCursor2 INTO @myVar2;
  SET @Inner_loop = @@FETCH_STATUS;
  WHILE @Inner_loop = 0
  BEGIN
    --Inner loop function
FETCH NEXT FROM myCursor2 INTO @myVar2;
    SET @Inner_loop = @@FETCH_STATUS;
  END
  CLOSE myCursor2;
  DEALLOCATE myCursor2;
  FETCH NEXT FROM myCursor INTO @myVar;
  SET @Outer_loop = @@FETCH_STATUS; 
END
CLOSE myCursor;
DEALLOCATE myCursor;
---------------------------------------------------------------------------

2. 关于关联字符集
由于数据库权限方面的限制,我在一个项目中需要对两个数据库中的表进行关联查询,然后碰到了字符集不匹配的报错。
具体的情况是这样的: 数据库DB1采用了GB字符集,数据库DB2采用了LATIN字符集,两个库的表T1和T2通过step_id进行JOIN,而step_id的数据类型是NVARCHAR,因此JOIN失败。
这是因为对于字符串类对象,虽然表示同样的值,当采用不同的字符集时,其存储时的值是不同的。
这个CASE给我的启示是,任何可能用于JOIN或外部引用的对象,要尽可能采用整型数据类型。
事实上,对于数据库来说,整型和日期型数据的检索速度是最快的,当有JOIN、分组查询、外部引用时,要尽可能使用整型数据。

2019年10月15日

Thingworx中跑马灯和自动换页效果的实现

我们知道,在传统SCADA中,跑马灯和自动换页都是常用的功能。
跑马灯可以显示长的消息,还可以起到醒目的效果。
自动换页可以轮流显示不同区域的画面,也可以在正常和异常画面之间进行切换。
但是在Thingworx中并没有对应的widget,但是我们可以通过变通的方式实现,下面讲讲具体方法。

1. 跑马灯
从8.4版本开始,Thingworx Mashup支持keyframes效果,如以下Custom CSS代码:
-----------------------------------------------
@keyframes marquee {
0% { left: 0; }
100% { left: -100%; }
}

#root_label-3 {
    animation: marquee 5s linear infinite;
    background-color: #eee;
    color: red;
}

#root_valuedisplay-4 {
    animation: marquee 10s linear infinite;
    background-color: #eee;
    color: red;
}
-----------------------------------------------
上述代码表示Label-3及Valuedisplay-4 widget的跑马灯效果,包括时间、颜色等设置。
需要说明的是,时间长度指的是所有字符显示的长度。
Label及Valuedisplay均支持背景色定义。
Label的前景色定义无效,而Valuedisplay的前景色定义有效。

2. 自动换页
Tabs widget支持在不同Tab上显示不同的内容,我们可以利用此特性实现自动换页。
SelectedTabValue和SelectedTabName这两个属性都可以用来操作Tab的选择。
我们可以编写一个计数器(自加1及重置),并配合Auto Refresh widget来得到TabValue。
简要的步骤为:
1) 编写计数器Service。
2) 用Auto Refresh触发计数器。
3) 把计数器的值绑定给SelectedTabValue。
此外,针对正常/异常画面切换,我们可以通过编写Service或Expression的方法来给SelectedTabValue赋值。

2019年10月12日

使用Thingworx监控Kepware OPC和PLC连接状态

PTC Thingworx是当前流行的IoT平台,可以很方便地建立和Kepware OPC Server的通信,在绑定Tag后,也很容易对PLC进行读写。
Manufacturing Apps工具包自带的Controls Advisor,能够监控OPC的实时状态,但遗憾的是,不能监控Device(如PLC)级别的状态。
但是我们可以利用Thingworx平台已有的功能,通过自建Thing和Mashup进行监控,下面进行简单的说明。

1. 监控Kepware OPC Server:
1) 在Controls Advisor中,新建Gateway Server。
2) Thingworx将自动创建同名的Industrial Thing,template = PTC.Factory.KepServerThingTemplate。
3) Thingworx也将自动创建Industrial Connection,文件名后缀增加-GW, template = IndustrialGateway。
4) 我们可以利用这两个Thing的isConnected属性来监控Kepware。

2. 监控设备Device(PLC):
1) 在Controls Advisor,点击"Discover Devices",完成以后,Thingworx将为每个设备自动创建一个Thing,
  名称 = Gateway名称 + "_" + Channel名称 + "." + Device名称,
  template = PTC.Factory.DeviceThingTemplate,
  IndustrialThing属性 = Thingworx自动创建的Industrial Connection,
  OPCDAThingName属性 = Controls Advisor中创建的Gateway Server
  (IndustrialThing只能绑定用户创建的Tag, OPCDAThingName能够绑定系统Tag)
2) Enabled属性表示设备已启用,ErrorState属性表示设备出错,
  Enabled = device._System._Enabled
  ErrorState = device._System._Error
 

2019年7月30日

ThingWorx Service: InfoTable2CSV

编写了一个通用程序,能够将InfoTable转换成CSV格式,用于Dygraph展示数据。

----------------------------------------------------------------------
// InfoTable2CSV: Service to convert InfoTable to CSV, to display data into Dygraph widget
// Input: myInfoTable:InfoTable without DataShape
// Output: TEXT
// Note 1: The name of Datetime field is always 'TIME', which is 1st field for Dygraph
// Note 2: TIME values will be converted into dateFormatISO to match Dygraph requirement

var iLF;
var tmp = 'TIME';
var i = 0;
var fd = []; // array to store Fields
fd[0] = 'TIME';

// Get CSV Header
if ((myInfoTable.dataShape===null)||(myInfoTable.dataShape===undefined)) {
   iLF = myInfoTable.ToJSON().dataShape.fieldDefinitions;
 } else {
   iLF = myInfoTable.dataShape.fields;
 }
for (var key in iLF) {
if(key != 'TIME') {
        i = i + 1;        
        fd[i] = key; // Store field sequence
        tmp = tmp + ',' + key;
}
    //Logger.info("Field Name "+key+" baseType: "+iLF[key].baseType);
}
tmp = tmp + ' \n';

// Get CSV Data
var tableLength = myInfoTable.rows.length;
for (var x=0; x < tableLength; x++) {
    var row = myInfoTable.rows[x];
    tmp = tmp + dateFormatISO(row.TIME);  // Get TIME Value 

    var fd2 = []; // To output data in sequence
    for (var property in row) {
    tmp2 = property; //row property
        tmp3 = row[property]; //row value
        var j = fd.indexOf(tmp2);
        fd2[j] = tmp3;
    }
    
    for (var k=1; k
        tmp = tmp + ',' + fd2[k];
    }    
    tmp = tmp + ' \n';
}

var result = tmp;
----------------------------------------------------------------------

2019年7月26日

ThingWorx Dygraph研究


ThingWorx Manufacturing Appstrending and troubleshooting功能提供了趋势分析工具,能够将根据时间序列存储的数据予以动态展示。
此功能在Mashup中对应的WidgetDygraph Widget,是基于开源的dygraphs实现的。
下面说一下在ThingWorx中应用Dygraph的注意事项。
1.     Dygraph的数据源即JSONData
此属性有一定的误导性,说是JSONData,但其实是csv格式的长字符串。
Csv格式就是带分隔符的文本文件,通常用“,”或”;”分隔;第一行定义表头,从第二行开始定义数据。
一些注意事项:
1)     表头的字段之间用”,”分隔,以“\n”换行;
2)     第一个字段必须是时间,对应于Dygraph的横坐标;
3)     其它的字段对应DataLabel1~DataLebel6
4)     从第二行开始,即数据存储区,字段之间以“,”分隔,最后以”\n”换行。

2.     如果数据的原始格式是InfoTable,则必须先转换成csv
比如我们想从外部的实时数据库抽取数据,则必须在查询后进行转换才能使用。
通常在ThingWorx中,查询输出的格式是InfoTable,而InfoTable的实际格式是JSON
对于此类数据,则必须自己编写Service进行转换,之后才能bindDygraph使用。
在编写Service时,注意Output类型是TEXT
转换代码示例:
------------------------------------------------------
var tmp = 'TIME,OEE \n';            //表头
var tmp1 = '';                             //存储第1个字段
var tmp2 = '';                             //存储第2个字段
var tableLength = IT1.rows.length;           //IT1是输入的InfoTable
for (var x=0; x < tableLength; x++) {         //InfoTable中逐行取值
    var row = IT1.rows[x];
    tmp1 = dateFormatISO(row.TIME);    //转换时间格式,这里TIME是第1个字段名称
    tmp2 = row.OEE;                              //这里OEE是第2个字段名称
    tmp = tmp + tmp1 + ',' + tmp2 + ' \n';     //生成一行数据记录
}

var result = tmp;
------------------------------------------------------

3.     时间序列的类型必须是ISO TIME
ISO TIME包含了日期、时间、时区的信息,如2019-07-26T01:30:00.000+08:00
我们可以利用dateFormatISO函数将DateTime类型转换成String类型。

4.     关于取值范围
如果从数据库中查询,然后转换成CSV使用,则要在Service Info中配置Max Rows,即返回的查询结果记录数,对应于SQL中的TOP/LIMIT条件,默认值是500

5.     更多Dygraph信息参考
可参考ThingWorx Apps自定义指南的第21-Dygraph小组件。



2019年7月10日

ThingWorx的大数据分析工具


ThingWorx是目前较为流行的工业物联网数据集成、分析、开发平台。
在业务方面,工艺实时数据有较大的分析价值,也符合大数据的分析特点。
本文介绍一下其大数据分析工具。
1.     数据存储
要对实时数据进行大数据分析,需要在创建Thing的时候满足以下条件:
1)     Thing指定Value Stream
Value Stream是存储数据的实体,其配置的Persistence Provider对应物理数据库,可以是内置的ProgreSQL数据库,也可以是支持ODBC的其它主流数据库。
2)     对于要追踪的属性打勾Logged选项
此选项在属性的值发生变化时,自动向Value Stream插入记录。

PostgreSQL中使用以下SQL可以查询数据:
---------------------------------------------------------------------
SELECT * FROM value_stream
WHERE ENTITY_ID = 'ValueString_KBSZ_MM'             -- Value Stream Name
AND source_id = 'KBSZ_DEMO_MM21_THING'           -- Thing Name
AND PROPERTY_NAME = 'Main_Speed'              -- Property Name
AND TIME > to_timestamp(EXTRACT(EPOCH FROM NOW())- 2*24*3600)  -- 2 days earlier till now
ORDER BY time --DESC
---------------------------------------------------------------------

2.     数据分析工具之Time Series Chart
要将ThingProperty数值传递给Mashup,通常通过这2ServiceGetPropertiesQueryPropertyHistory,前者传递当前值,后者传递历史数据。
QueryPropertyHistory有以下几个输入参数:
-       startDate,起始时间
-       endDate,结束时间
-       maxItems,记录数,相当于SQL中的TOP/LIMIT
-       oldestFirst,排序方式,相当于ORDER BY TIME ASC
-       query,过滤条件,相当于追加WHERE语句
然后把输出条件中的All Data绑定到Time Series ChartDataSource,然后设定:
-       NumberOfSeries,参数个数
-       DataSourceX.DataFieldX,纵坐标,选择对应的Property
-       DataSourceX.XAxisFieldX,横坐标,选择timestamp
需要说明的是,QueryPropertyHistory返回的是符合条件的查询结果数据集,因此结果集越大,查询越慢。
此外,Time Series Chart加载了QueryPropertyHistory结果集的所有数据,因此结果集越大,显示越慢。
因此,要慎重设定查询参数,特别是startDate/endDate/maxItems


3.     数据分析工具之Dygraph Chart
PTC ThingWorx Manufacturing Apps提供了PTC.Factory.TrendManagementUtils,其GetJSONStringTrendHistory方法可以将属性的历史值转换成JSON格式。
然后配合Dygraph Chart,可以实现数据的动态加载。
具体实现方式为:
1)     Manufacturing Apptrending and troubleshooting设定追踪项,记录Trend Name
2)     Mashup中加载GetJSONStringTrendHistory方法,将displayId设为步骤1Trend Name。并设置startDate/endDate等其它参数。
3)     Mashup中将GetJSONStringTrendHistory绑定到dygraphchartwidget,将Data映射为JSONData,将TrendNameX映射为DataLabelX
我们注意到,在GetJSONStringTrendHistory方法中并没有maxItems参数,在dygraphchartwidget中也不可设置时间。
这是因为GetJSONStringTrendHistory查询得到了所有符合条件的数据集,此数据集以JSON字符串的形式予以输出。
dygraphchartwidget得到JSON数据后,根据数据的特点动态地予以展示,因此数据集的大小不会影响显示的时间。
我们从PTC的文档可以看到,Dygraph Chart采用了开源的JavaScriptdygraphs,具体使用可参考ThingWorx Apps自定义指南的第21章。



2019年7月2日

谈谈840D机床的联网


SINUMERIK 840D(SL)是西门子广受好评的CNC自动化控制系统,它和SINAMICS S120内置式变频器组合,广泛应用于高端机床和加工中心。
近几年来,随着工业互联网和工业4.0的发展,对机床联网以实现监控和数采的需求也越来越多。
本文试谈谈840D机床的联网。

一、硬件
840D(SL)的控制单元(Control Unit)包括:NCUPCUTCU
NCUNumeric Control Unit(数控单元),是控制系统的核心。
NCU又包含了Linux内核、PLC CPUPLC通信卡(840D SL)等模块。
其中Linux内核从CF卡加载,PLC CPU采用S7-300标准PLCPLC通信卡即CP343-1系列通信模块。
PCUPC Client Unit(PC客户端),采用工业PC,内置WindowsLinux操作系统。
TCUThin Client Unit(瘦客户端),通过VNC软件远程运行Linux内核程序。


二、联网
840D包含了MPIProfiBus等接口。其中ProfiBus又包括DP IntegratedDP Master接口。DP Integrated是内核与SINAMICS S120通信的专用接口,DP Master用于连接外围设备如PCUTCU、远程I/O等。MPI是编程专用接口。
除了以上接口外,840D SL还增加了ProfiNet(X150)EtherNet(X120/X127/X130)接口。
ProfiNet可连接工业交换机、远程I/O等,其默认IP地址是192.168.0.1
X120用于连接PCUTCU,其默认IP地址是192.168.214.1
X127用于连接工程师电脑,来进行PLC组态及下载,其默认IP地址是192.168.215.1
X130用于连接工厂网络(IT网络),通常接到IT交换机上,由IT交换机分配IP地址。
因此对于840D SL,我们可以直接将X130接入IT网络,以实现机床的联网。
840D NCU并没有提供以太网口,要联网可以采用以下两种方式。
方式1:增加CP343-1通信模块。
CP343-1S7-300系列PLC的以太网通信模块,在组态后,可以为PLC CPU分配一个以太网IP地址。此模块性能好非常稳定,但是需要组态及下载PLC,价格也较高,单价1万多。
方式2:增加MPI-EtherNet转换头。
德国Hilscher公司提供了NetLink商标的MPI-EtherNet转换头,能够将MPI协议转换成S7 TCP/IP协议,且无须组态,价格约4000元。NetLink提供了一个网页服务器,用于配置MPI参数和IP地址。替代产品有德国DeltalogicNetLink和国内大连德嘉的ETH-MPI(DP)



三、应用
840D(SL)的硬件我们可以看出,机床的控制分为文件控制和逻辑控制两大块,文件控制通过Windows/Linux操作系统实现,逻辑控制通过PLC实现。
因此,IT系统在与机床联网时,可以进行针对性的设计。
如果我们要向机床传加工程序,或者采集加工日志,则可以通过操作系统实现,比如文件共享、FTP、串口连接等。
如果我们要采集机床的状态、故障、工艺参数,则可以通过PLC实现,比如通过Kepware连接NCU PLC,或者通过OPC Client连接机床内置的OPC-UA服务器。




2019年3月7日

ThingWorx开发小结


最近一段时间尝试了下用ThingWorx做开发,下面是一些心得和小结。

1、ThingWorx作为IoT平台(Connectivity+Thing)
ThingWorx整合了Kepware,作为ThingWorx Connectivity部署。
Kepware的PLC驱动可以快速配置,实现和主流PlC的双向通信。
Kepare的IoT Gateway提供了Rest Server/Rest Client/MQTT Client这3种代理,实现和IT系统的通信。
ThingWorx内置了一个OPC Client,叫做Industrial Connection,可以通过Discover工具实现对OPC目录和TAG的浏览和绑定,非常方便。
由于Kepware同是PTC的产品,因此和ThingWorx的整合是相当深入的,只需要在Kepware中做一些简单的配置,就可以在ThingWorx中调用OPC,这一点比起其它SCADA产品方便得多。
最大的缺点是不支持对OPC TAG的动态名称调用。
我们知道OPC TAG是一个字符串形式的内存变量,可以通过拼接的形式得到完整的TAG名称,象GE Cimplicity和Ignition都支持对OPC TAG的动态读写,这样可以通过编写服务来重复调用、简化代码。
而ThingWorx的核心是Thing这个对象,OPC TAG是作为一个绑定的远程变量附加到某一个属性上的,因此每一个TAG都是独立管理的。
从PTC ThingWorx Manufacturing Apps的代码(Controller.UpdateProperty)我们也可以看出,ThingWorx是作为REST Client来实现动态回写OPC的(与Kepware的Rest Server通信)。

2、ThingWorx作为数据展示平台(Mashup)
展示方面,ThingWorx提供了Mashup、Gadgets、Style、State等工具。
其优点是美观、现代化,IT工程师开发起来顺手。
相比较而言,ThingWorx适用IT工程师开发,而传统SCADA适合控制工程师开发。
为什么这么说呢?
一个重要的原因是,ThingWorx是基于JAVA开发的,因此有大量的配置、继承。
比如Menu菜单、Media图片、Style样式、State数据规划,这些都是独立的对象,Mashup只能引用。
举个简单的例子,你想要把字体放大一号,你必须新建一个Style,然后在Mashup中引用。
这些对于JAVA工程师来说不以为怪,但是对于工控工程师来说就很头大了。
此外,ThingWorx自带的一些Widgets也不是很成熟,如:Label的字体最小号是9px,饼图不能显示数值和百分比,柱状图的文字长度受限等。

3、ThingWorx作为客户端(Mashup)
ThingWorx是B/S架构的,因此其客户端相当于运行一个Mashup实例。
但是Mashup本身不具备任何的逻辑处理能力,只有基本的复位数据等固定功能。
在ThingWorx中,只有Thing是真正的逻辑实体,所有业务逻辑都是通过Service传递给Mashup的。
因此,任何客户端的业务逻辑,都必须绑定远程的Thing.Service来予以实现。
举个简单的例子,客户端采集到条码后要进行有效性校验,但是客户端不能执行校验逻辑,必须调用服务端的逻辑实现,其路径是:JavaScript/Query --> Service --> Thing --> Mashup.
目前JAVA和B/S能在互联网大行其道,一个重要原因是允许客户端JavaScript的执行,甚至衍生出了前端程序员这个工种。
但是ThingWorx不支持客户端JavaScript调用,是其一个较大的局限。

4、ThingWorx作为集成开发环境(Platform)
我们可以把ThingWorx作为一个简化的集成开发环境,它对JavaScript/SQL的支持非常好,开发也非常方便。
下面谈几点短板。
我们知道,和JAVA相比,.Net是一个半C/S、半B/S的架构,因为.Net客户端可以通过.Net Framework来调用系统dll,从而得到OS操作权限及实现分布式架构。
比如,.Net客户端可以调用本地opc client直接和opc server通信,这样通信的链路就分散开来,减少了服务端专用opc client的阻塞和性能需求。
而ThingWorx基于Java开发,是典型的B/S架构。而JAVA基于安全的考虑,服务器是不具备操作系统权限的。
以文件操作为例,ThingWorx定义了一个文件存储的根目录,所有ThingWorx管理的文件必须在此目录下。因此,ThingWorx不能处理服务器上其它目录的文件,也不能处理局域网内通过文件夹共享的文件。
因此,我们必须通过MQTT、FTP等方式来处理远程文件。
ThingWorx提供了一个FTP Client扩展,但是坑爹的是只提供文件读、写功能,不能执行删除操作。
那么假设我们需要从某台设备PC采集文件数据,怎么操作比较方便呢?我们需要在ThingWorx上建立一个FTP SERVER,然后把ThingWorx文件子系统映射成FTP虚拟子目录,然后在设备PC上通过FTP CLIENT上传数据; 然后在ThingWorx文件子系统进行文件的读写。
ThingWorx还有一个缺点是对项目的管理不是很完善。比如说,我们有很多Media/Style/State,会需要在许多项目中使用,但是这些对象只能绑定到一个Project,这就不是很合理了。
此外,Service的调试是不支持中断的,要调试代码,必须自己写LOG,然后在Monitoring中查看日志。