Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/hilch/TrakDiag
Automation Studio Library for ACOPOStrak diagnosis
https://github.com/hilch/TrakDiag
Last synced: about 2 months ago
JSON representation
Automation Studio Library for ACOPOStrak diagnosis
- Host: GitHub
- URL: https://github.com/hilch/TrakDiag
- Owner: hilch
- License: mit
- Created: 2023-04-13T17:13:14.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-03-11T12:28:41.000Z (10 months ago)
- Last Synced: 2024-03-11T13:53:36.471Z (10 months ago)
- Language: C
- Size: 7.07 MB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGES.md
- License: LICENSE
Awesome Lists containing this project
- awesome-B-R - TrakDiag - Library for ACOPOStrak diagnosis (Motion / based on mapp Motion)
README
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Made For B&R](https://github.com/hilch/BandR-badges/blob/main/Made-For-BrAutomation.svg)](https://www.br-automation.com)# TrakDiag
Library for ACOPOStrak diagnosis.
Included are some function blocks that can be used to easily make entries in application specific loggers.
In the event of an error, internal states (state machines, internal statuses, shuttle user data) can thus be brought into connection with the 'Motion' logger.As a further aid, a 'flight recorder' is available, which graphically displays the last seconds before an error.
Finally, a web-based diagnostic interface can be generated with this library, which continuously displays the shuttle positions.
## Dependencies / Preconditions
- ArEventLog
- astime
- DataObj
- McAcpTrak >= 5.27.1 (>= 5.21.1 for V2.x)
- standard
- McBase
- sys_lib
- brsystem
- FileIO
- AsHttp
- AsArSdmGCC >= V6.3.0
# Functions / function blocks
## Helper functions for generating strings with timestamps.
### TD_ascDT
Returns ASCII timestring for DATE_AND_TIME
usage:
```
TD_ascDT( entry.LocalTime, ADR(strAsctime), SIZEOF(strAsctime) ); (* convert time stamp to readable string *)
```
The output will be a string like `'Thu Aug 23 14:55:20'`.### TD_filenameDT
Returns a valid filename with given prefix and IEC like timestamp included.
This function block is used for generating filenames within TD_Recorder and can be also useful for
generating filenames in combination with library AsArSdm.usage:
```
TD_filenameDT( ADR('SystemDump_'), ADR(filename), SIZEOF(filename) );
```
The output will be a string like `'SystemDump_2023-01-15T14_55_20'`.## Function blocks for logging
These are just convinience function around ArEventLog. If logger does not exist it will be created.
(Older Automation Runtime seem to have problems generating logbooks in tasks with short cycle times.
This can be avoided if these functions are called once in _INIT.)
Set 'EventID' according to ArEventLog to decide if message is error, warning, info etc.
Every write command is executed within 1 cycle.### TD_LogWatchBOOL
Write status of BOOL variable into logger on variable change.
usage:
```
PROGRAM _INIT
TD_LogWatchBOOL_0( Enable := FALSE, LogName := 'mylog', SignalName := 'barrier status', EventID := BASIC_INFO_ID );
TD_LogWatchBOOL_0.Enable := TRUE;
END_PROGRAMPROGRAM _CYCLIC
(* wait for signal change *)
TD_LogWatchBOOL_0 Signal := barrierStatus) );
END_PROGRAM
```### TD_LogWatch8Flags
Writes status of up to 8 bits ('flags') into logger on variable change.
Each bit is assigned a text via '.Flag[x]', where a '1' state is indicated with upper case letters and a '0' state with lower case letters.
If the output text in logger is preceded by an asterisk '*', this means that the state of this bit has changed.usage:
```
PROGRAM _INIT
TD_LogWatch8Flags_0( Enable := FALSE, LogName := 'mylog', SignalName := 'plc signals', EventID := BASIC_INFO_ID );
TD_LogWatch8Flags_0.Flag[0] := 'fr.Power';
TD_LogWatch8Flags_0.Flag[1] := 'fr.Auto';
TD_LogWatch8Flags_0.Flag[2] := 'to.Power';
TD_LogWatch8Flags_0.Flag[3] := 'to.Auto';
TD_LogWatch8Flags_0.Flag[4] := 'to.Cover';
TD_LogWatch8Flags_0.Flag[5] := 'to.Error';
TD_LogWatch8Flags_0.Enable := TRUE;
END_PROGRAMPROGRAM _CYCLIC
(* collect data *)
plcFlags.0 := fromPLC.PowerOn;
plcFlags.1 := fromPLC.StartAutomatic;
plcFlags.2 := toPLC.PowerIsOn;
plcFlags.3 := toPLC.AutomaticActive;
plcFlags.4 := toPLC.CoverOpenPermission;
plcFlags.5 := toPLC.Error;
(* wait for signal change *)
TD_LogWatch8Flags_0( Signal := plcFlags );
END_PROGRAM
```### TD_LogWatchDINT
Writes status of DINT variable into logger on variable change.
usage:
```
PROGRAM _INIT
TD_LogWatchDINT_0( Enable := FALSE, LogName := 'mylog', SignalName := 'shuttle ID', EventID := BASIC_INFO_ID );
TD_LogWatchDINT_0.Enable := TRUE;
END_PROGRAMPROGRAM _CYCLIC
(* wait for signal change *)
TD_LogWatchDINT_0( Signal := shuttleID) );
END_PROGRAM
```### TD_LogWatchSTRING
Writes contents of STRING variable into logger on variable change.
usage:
```
PROGRAM _INIT
TD_LogWatchSTRING_0( Enable := FALSE, LogName := 'mylog', SignalName := 'step', EventID := BASIC_INFO_ID );
TD_LogWatchSTRING_0.Enable := TRUE;
END_PROGRAMPROGRAM _CYCLIC
(* wait for signal change *)
TD_LogWatchSTRING_0( Signal := stepStr );
END_PROGRAM
```### TD_LogWrite
Writes into Logger. Generic function with 'Execute' input.
usage:
```
PROGRAM _INIT
TD_LogWrite_0(Execute := FALSE, Name := 'mylog', ObjectID := 'shuttle info', EventID := BASIC_INFO_ID );
END_PROGRAMPROGRAM _CYCLIC
(* wait for an event *)
IF shuttleArrived THEN
shuttleArrived := FALSE;(* prepare storing data into logger *)
TD_LogWrite_0.Ascii := 'cnt:';
brsitoa( shuttleCounter, ADR(tempstring) );
brsstrcat( ADR(TD_LogWrite_0.Ascii), ADR(tempstring) );brsstrcat( ADR(TD_LogWrite_0.Ascii), ADR( ' ID:') );
brsitoa( shuttleID, ADR(tempstring) );
brsstrcat( ADR(TD_LogWrite_0.Ascii), ADR(tempstring) );TD_LogWrite_0( Execute := TRUE );
TD_LogWrite_0( Execute := FALSE ); (* reset fb *)END_IF
END_PROGRAM
```## TD_SegCommandError
Simulates Segment Error.
Currently 'SEGMENT', 'CHANNEL' and 'ENCODER' errors are supported.usage:
```
PROGRAM _INIT
TD_SegCommandError_0( Execute := FALSE, Segment := ADR(Seg11), Type := TD_SEGERRCMD_ENCODER ); (* reset fb *)
END_PROGRAMPROGRAM _CYCLIC
TD_SegCommandError_0( Execute := simulateError );
END_PROGRAM
```## TD_CrashReport
Read motion logger entries into array and provides some filtering options.
The purpose is to provide some more information about segment errors for an operator.
Overreads entries that refer to shuttle commands since these are hardly useful for operators.(As the capabilities of mappMotion with respect to alarm handling continue to expand, the importance of this function block will diminish in future mappMotion versions.)
usage:
```
PROGRAM _INIT
MC_BR_AsmReadInfo_AcpTrak_0.Assembly := ADR(gAssembly_1);
MC_BR_AsmReadInfo_AcpTrak_0.Enable := TRUE;TD_CrashReport_0( thrSeverity := arEVENTLOG_SEVERITY_ERROR,
objectStartsWith1 := 'Seg_',
observationPeriod := T#2s,
pLoggerEntries := ADR(errorEntry), (* container for all logger entries *)
SizeLoggerEntries := SIZEOF(errorEntry),
Execute := FALSE ); (* reset fb *)
END_PROGRAMPROGRAM _CYCLIC
MC_BR_AsmReadInfo_AcpTrak_0();
TD_CrashReport_0( Execute := MC_BR_AsmReadInfo_AcpTrak_0.AssemblyInfo.SegmentsInErrorStopCount <> 0 );
END_PROGRAM
```## TD_LoggerReadEntry
Read logger entry (internal use).
## TD_Recorder
Records shuttle data cyclically and provides a video for playing back the last seconds before a failure happend as scene viewer would do.
Use an instance for each assembly.If 'Trigger' is set a html file containing the 'SvgData' with shuttle movements and a system dump file is created.
Since MC_BR_AsmCopyShuttleData_AcpTrak is used internally this FB is blocked for your application.
If you still need this data you can use the shuttle data provided by 'DataAddress'/'DataSize' for own usage instead.usage:
```
PROGRAM _INIT
MC_BR_AsmReadInfo_AcpTrak_0.Assembly := ADR(gAssembly_1);
MC_BR_AsmReadInfo_AcpTrak_0.Enable := TRUE;TD_Recorder_0.AssemblyName := 'gAssembly_1';
TD_Recorder_0.UserDataSize := 0; (* no user data used *)
TD_Recorder_0.FileDeviceName := 'Diagnosis';
TD_Recorder_0.DataAddress := ADR(shuttleData);
TD_Recorder_0.DataSize := SIZEOF(shuttleData); (* type of McAcpTrakShuttleData[] if no shuttle user data is defined, see MC_BR_AsmCopyShuttleData_AcpTrak *)
END_PROGRAMPROGRAM _CYCLIC
MC_BR_AsmReadInfo_AcpTrak_0();TD_Recorder_0.Enable := MC_BR_AsmReadInfo_AcpTrak_0.AssemblyInfo.PowerOn;
TD_Recorder_0.Trigger := MC_BR_AsmReadInfo_AcpTrak_0.AssemblyInfo.ShuttlesInErrorStopCount <> 0;TD_Recorder_0();
END_PROGRAM
```output:
![example_recorder](https://github.com/hilch/TrakDiag/blob/main/examples/screenshot_recorder.png)
[download this example and open it in your browser](https://github.com/hilch/TrakDiag/blob/main/examples/Demo_TD_Recorder_gAssembly_1_2024-09-27T13_04_53.html)
## TD_WebServices
Provides some live information about Trak system via web based services.
Data is provided by TD_Recorder or MC_BR_AsmCopyShuttleData_AcpTrak.usage:
```
PROGRAM _INIT
...
...
TD_WebServices_0.AssemblyName := TD_Recorder_0.AssemblyName;
TD_WebServices_0.DataAddress := TD_Recorder_0.DataAddress;
TD_WebServices_0.DataSize := TD_Recorder_0.DataSize;
TD_WebServices_0.UserDataSize := TD_Recorder_0.UserDataSize;
TD_WebServices_0.Enable := TRUE;
END_PROGRAMPROGRAM _CYCLIC
...
TD_WebServices_0();
...
END_PROGRAM
```starting with V3.0 this FB supports more than one Assembly. For this you have to include the assembly's name into the URL.
In most cases you only want to see the main page.If the ip is 127.0.0.1 and the assembly's name is `gAssembly_1` the request should be `http://127.0.0.1/TrakWebApi/gAssembly_1/index.html`.
### /TrakWebApi//index.html
HTML page with assembly's SvgData and shuttle positions.
Simply embedd this path into mappView's WebViewer widget.![video_webservices.gif](https://github.com/hilch/TrakDiag/blob/main/examples/video_webservices.gif)
![screenshot_mappView.png](https://github.com/hilch/TrakDiag/blob/main/examples/screenshot_webservices.png)
### /TrakWebApi//info
JSON with Basic information
```
{"TrakDiag" : "2.02.0","McAcpTrak" : "V5.22.1"}
```### /TrakWebApi//positions
JSON with shuttle information
we return an array of pairs of two UDINT:
- [0] Bit 0-31 : shuttle index
- [1] Bit 0-7 : PLCopen state
- [1] Bit 8 : active shuttle
- [1] Bit 9 : virtual shuttle
- [1] Bit 10-20 : segment index (11 Bit)
- [1] Bit 21-27 : segment position in % (7 Bit)```
[[1,197149959],[2,102778119],[3,10503431],[4,121636103],[5,6291719],[6,98566407],[7,182454535],[8,90179847],[9,207621383],[10,113249543]]
```### /TrakWebApi//assembly
assembly information (>= V2.2.x)
```
{"CommunicationReady" : true,"ReadyForPowerOn" : true,"PowerOn" : true,"SegmentsInDisabledCount" : 0,"SegmentsInStoppingCount" : 0,"SegmentsInErrorStopCount" : 0,"ShuttlesCount" : 10,"ShuttlesInErrorStopCount" : 0}
```### /TrakWebApi//segments
Deliver JSON with list of assembly's segments.
```
[ { "name": "gSegB7", "ID": 31, "length": 0.450642056481534 },{ "name": "gSegB6", "ID": 30, "length": 0.450642056481534 },{ "name": "gSegB8", "ID": 29, "length": 0.450642056481534 },{ "name": "gSegB9", "ID": 28, "length": 0.450642056481534 },{ "name": "gSegB10", "ID": 27, "length": 0.450642056481534 },{ "name": "gSegB11", "ID": 26, "length": 0.240000000000000 },{ "name": "gSegB12", "ID": 25, "length": 0.240000000000000 },{ "name": "gSegB13", "ID": 24, "length": 0.240000000000000 },{ "name": "gSegB14", "ID": 23, "length": 0.450642056481534 },{ "name": "gSegB16", "ID": 22, "length": 0.450642056481534 },{ "name": "gSegB15", "ID": 21, "length": 0.450642056481534 },{ "name": "gSegB17", "ID": 20, "length": 0.450642056481534 },{ "name": "gSegB18", "ID": 19, "length": 0.450642056481534 },{ "name": "gSegB1", "ID": 18, "length": 0.450642056481534 },{ "name": "gSegB2", "ID": 17, "length": 0.240000000000000 },{ "name": "gSegB3", "ID": 16, "length": 0.240000000000000 },{ "name": "gSegB4", "ID": 15, "length": 0.240000000000000 },{ "name": "gSegB5", "ID": 14, "length": 0.450642056481534 },{ "name": "gSegA2", "ID": 13, "length": 0.660000000000000 },{ "name": "gSegA3", "ID": 12, "length": 0.450642056481534 },{ "name": "gSegA4", "ID": 11, "length": 0.240000000000000 },{ "name": "gSegA5", "ID": 10, "length": 0.240000000000000 },{ "name": "gSegA6", "ID": 9, "length": 0.240000000000000 },{ "name": "gSegA7", "ID": 8, "length": 0.450642056481534 },{ "name": "gSegA8", "ID": 7, "length": 0.660000000000000 },{ "name": "gSegA9", "ID": 6, "length": 0.660000000000000 },{ "name": "gSegA10", "ID": 5, "length": 0.450642056481534 },{ "name": "gSegA11", "ID": 4, "length": 0.240000000000000 },{ "name": "gSegA12", "ID": 3, "length": 0.240000000000000 },{ "name": "gSegA13", "ID": 2, "length": 0.240000000000000 },{ "name": "gSegA14", "ID": 1, "length": 0.450642056481534 },{ "name": "gSegA1", "ID": 0, "length": 0.660000000000000 }]
```### /TrakWebApi//segment_status
returns segments' status (bit coded).
```
[ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7]
```### /TrakWebApi//svgdata
Deliver assembly's generated SvgData (SVG).
# Selective Logging
ACOPOStrak already generates many entries in the motion logger.
By cyclically calling internal function blocks, even TD_Recorder and TD_Webservices generate many more entries.
Currently, the entries can only be reduced by activating 'Selective Logging' in the [MappMotionConfiguration](https://help.br-automation.com/#/en/6/motion%2Fmapp_motion%2Fallgemeines%2Fkonfiguration%2Fbasiselemente%2Fmapp_motion_configuration.html).
The following setting is therefore recommended:
![selective_logging.png](https://github.com/hilch/TrakDiag/blob/main/doc/selective_logging.png)