Ladder99 / fanuc-driver

Configurable Fanuc Focas data collector and post processor.
Apache License 2.0
72 stars 25 forks source link

How to process the `fanuc-driver` output? #13

Closed tukusejssirs closed 1 year ago

tukusejssirs commented 3 years ago

I struggle a bit with processing the data fanuc-driver provides (via MQTT). I think it would be very useful to document this.


  1. Get the machine metadata (model, spindles, servos, etc). This is a one time job. TODO

  2. Get the current data and process it. This is a one time job on each fanuc-driver start.

  3. Check if the machine is still up. This should be done continually. I think we should use fanuc/$disco for this, using the payload value. TODO

Example payload:

payload: '{\n' +
    '  "m9_doosan_puma": {\n' +
    '    "added": 1627374718761,\n' +
    '    "seen": 1627374726936,\n' +
    '    "machineId": "m9_doosan_puma",\n' +
    '    "arrivalTopic": "fanuc/m9_doosan_puma-all",\n' +
    '    "changeTopic": "fanuc/m9_doosan_puma"\n' +
    '  }\n' +
    '}',
  1. Check alarm codes and messages. This should be done continually. It requires to check multiple topics.

Example payload for pressed emergency stop (message in state.data.msgs[].data and code 2001 in state.data.msgs[].datano):

payload: '{\n' +
  '  "observation": {\n' +
  '    "time": 1627374719725,\n' +
  '    "machine": "m9_doosan_puma",\n' +
  '    "type": "source",\n' +
  '    "name": "message1",\n' +
  '    "marker": {}\n' +
  '  },\n' +
  '  "source": {\n' +
  '    "method": "cnc_rdopmsg",\n' +
  '    "invocationMs": 6,\n' +
  '    "data": {\n' +
  '      "type": 0,\n' +
  '      "length": 262\n' +
  '    }\n' +
  '  },\n' +
  '  "state": {\n' +
  '    "time": "00:00:03.3303133",\n' +
  '    "data": {\n' +
  '      "msgs": [\n' +
  '        {\n' +
  '          "data": " STLACENO NOUZOVE TLACITKO EMERGENCY STOP NEBO OSA V PREJEZDU.",\n' +
  '          "datano": 2001,\n' +
  '          "type": 0\n' +
  '        }\n' +
  '      ]\n' +
  '    }\n' +
  '  }\n' +
  '}',
  1. Get number of pieces produced. This should be done continually. @MRIIOT, could the topic name be (later on) abstracted a bit? Like can we name it fanuc/{machine}/numberOfPieces or whatever and we would get there all three values (6711, 6712 and 6713)?
MRIIOT commented 3 years ago

I struggle a bit with processing the data fanuc-driver provides (via MQTT). I think it would be very useful to document this.

  1. Get the machine metadata (model, spindles, servos, etc). This is a one time job. TODO

Some Focas calls could be executed only once upon first connection and never called again, like system info, number of axes/spindles. Last time I checked the packet capture, some of these calls don't even make it across the wire, which would mean that fwlib holds the info in memory anyway.

Spindles and axes for each execution path is captured in $model topic.

structure ```json { ... }, "structure": { "observations": { "$ref": "#/observations/root" }, "path": [ { "name": 1, "observations": { "$ref": "#/observations/path" }, "axis": [ { "name": "X", "observations": { "$ref": "#/observations/axis" } }, { "name": "Y", "observations": { "$ref": "#/observations/axis" } }, { "name": "Z", "observations": { "$ref": "#/observations/axis" } } ], "spindle": [ { "name": "S", "observations": { "$ref": "#/observations/spindle" } } ] } ] } } ```

Execution path level l99.driver.fanuc.veneers.SysInfo observation provides model information. This observation is per path. In a multi-path machine, the number of axes per path could be different fanuc/{id}/sys_info/1, fanuc/{id}/sys_info/2, ...

system info ```json ... "path": [ { "name": "sys_info", "veneer": "l99.driver.fanuc.veneers.SysInfo" } ... ```

Similarly, l99.driver.fanuc.veneers.RdAxisname and l99.driver.fanuc.veneers.RdSpindlename observations are path level. Each path can have a different number and names of axes/spindles. fanuc/{id}/axis_names/1, fanuc/{id}/axis_names/2, ..., fanuc/{id}/spindle_names/1, fanuc/{id}/spindle_names/2, ...

axes and spindle names ```json ... "path": [ { "name": "axis_names", "veneer": "l99.driver.fanuc.veneers.RdAxisname" }, { "name": "spindle_names", "veneer": "l99.driver.fanuc.veneers.RdSpindlename" } ... ```
  1. Get the current data and process it. This is a one time job on each fanuc-driver start.
  2. Check if the machine is still up. This should be done continually. I think we should use fanuc/$disco for this, using the payload value. TODO

Example payload:

payload: '{\n' +
    '  "m9_doosan_puma": {\n' +
    '    "added": 1627374718761,\n' +
    '    "seen": 1627374726936,\n' +
    '    "machineId": "m9_doosan_puma",\n' +
    '    "arrivalTopic": "fanuc/m9_doosan_puma-all",\n' +
    '    "changeTopic": "fanuc/m9_doosan_puma"\n' +
    '  }\n' +
    '}',

Or the ping topic where state.data is the result of the last Focas connection success/failure.

ping/pong ```json { "observation": { "time": 1627388911421, "machine": "sim", "name": "ping" }, "source": { "data": { "_id": "sim", "IPAddress": "10.20.30.101", "Port": 8193, "ConnectionTimeout": 3 } }, "state": { "data": "OK" } } ```
  1. Check alarm codes and messages. This should be done continually. It requires to check multiple topics.
  • The code and message can be acquired using cnc_rdopmsg. (What are the cnc_rdopmsg2 and cnc_rdopmsg3 for? Are they ever used/needed?).

See https://www.inventcom.net/fanuc-focas-library/misc/cnc_rdopmsg, https://www.inventcom.net/fanuc-focas-library/misc/cnc_rdopmsg2, https://www.inventcom.net/fanuc-focas-library/misc/cnc_rdopmsg3.

And the support matrix https://github.com/Ladder99/fanuc-driver/blob/main/FOCAS_FUNCTION_MATRIX.md.

Of course, it might be a good idea to process the timestamp in observation.time as the alarm start time (it is in UNIX Epoch and in milliseconds); this should be always process in any packet. When a particular alarm is dismissed, it should not be output in the state.data.msgs[] array—@MRIIOT, actually, no packet is sent to MQTT broker; is it a bug or feature? @MRIIOT, what does state.data.msgs[].type mean? Some kind of alarm severity (like error/warning/info)?

This needs to be investigated. Try changing https://github.com/Ladder99/fanuc-driver/blob/31c6ad63482f939be7261494efc789f163b2f99c/fanuc/veneers/OpMsgs.cs#L14 to msgs = new List<dynamic>() { -1 }. Need to implement a null object pattern.

type
Kind of operator's message is stored.

Series 15/15i
0 to 3  :   1st to 4th message
4   :   macro message

Series 16/18/21, 16i/18i/21i, 0i, 30i, Power Mate i, PMi-A
0   :   1st message

Series 16i/18i-W
0 to 3  :   1st to 4th message

Example payload for pressed emergency stop (message in state.data.msgs[].data and code 2001 in state.data.msgs[].datano):

payload: '{\n' +
  '  "observation": {\n' +
  '    "time": 1627374719725,\n' +
  '    "machine": "m9_doosan_puma",\n' +
  '    "type": "source",\n' +
  '    "name": "message1",\n' +
  '    "marker": {}\n' +
  '  },\n' +
  '  "source": {\n' +
  '    "method": "cnc_rdopmsg",\n' +
  '    "invocationMs": 6,\n' +
  '    "data": {\n' +
  '      "type": 0,\n' +
  '      "length": 262\n' +
  '    }\n' +
  '  },\n' +
  '  "state": {\n' +
  '    "time": "00:00:03.3303133",\n' +
  '    "data": {\n' +
  '      "msgs": [\n' +
  '        {\n' +
  '          "data": " STLACENO NOUZOVE TLACITKO EMERGENCY STOP NEBO OSA V PREJEZDU.",\n' +
  '          "datano": 2001,\n' +
  '          "type": 0\n' +
  '        }\n' +
  '      ]\n' +
  '    }\n' +
  '  }\n' +
  '}',
  • @MRIIOT, what kind of data can be received using cnc_rdalmmsg_ALL method (fanuc/{machine}/alarms topic)? I did not receive any alarm there, but it’s true that I am testing fanuc-driver on an idle machine.

Alarms!

...
      "alarms": [
        {
          "alm_no": 100,
          "type": 0,
          "axis": 0,
          "alm_msg": "PARAMETER ENABLE SWITCH ON\u0010\f\u0001h"
        }
      ]
...
  • @MRIIOT, is it necessary / a good idea to process fanuc/{machine}/alarms/$schema and fanuc/{machine}/$model? Does it ever change on different Fanuc models and versions?

Yes, it does. $model is dependent on observations defined in the collector and number of paths/axes/spindles. It will vary from machine to machine, and collector to collector (eg. UseCase01 vs Basic01). $schema for each observation defines the data structure for that observation, and should not change, unless we change the veneer code or use a different Handler. The idea behind $model and $schema is to create an intermediate data model to help with configuring MTConnect devices on the fly, see #12.

  1. Get number of pieces produced. This should be done continually. @MRIIOT, could the topic name be (later on) abstracted a bit? Like can we name it fanuc/{machine}/numberOfPieces or whatever and we would get there all three values (6711, 6712 and 6713)?
  • number of pieces already produced: fanuc/{machine}/6711/1;
  • number of pieces produced since last machine refresh [like an OS (re)installation]: fanuc/{machine}/6712/1;
  • number of pieces set by an operator to be produced: fanuc/{machine}/6713/1.

Something like this? I don't remember if these parameters are global or if each execution path has their own counts (TODO). If each path holds their own counts then it would become fanuc/{machine}/numberOfPieces/1, fanuc/{machine}/numberOfPieces/2, ...

await Peel("numberOfPieces",
    await SetNative("produced", await platform.RdParamDoubleWordNoAxisAsync(6711)),
    await SetNative("producedLife", await platform.RdParamDoubleWordNoAxisAsync(6712)),
    await SetNative("remaining", await platform.RdParamDoubleWordNoAxisAsync(6713)));
tukusejssirs commented 3 years ago
  • @MRIIOT, is it necessary / a good idea to process fanuc/{machine}/alarms/$schema and fanuc/{machine}/$model? Does it ever change on different Fanuc models and versions?

Yes, it does. $model is dependent on observations defined in the collector and number of paths/axes/spindles. It will vary from machine to machine, and collector to collector (eg. UseCase01 vs Basic01). $schema for each observation defines the data structure for that observation, and should not change, unless we change the veneer code or use a different Handler. The idea behind $model and $schema is to create an intermediate data model to help with configuring MTConnect devices on the fly, see #12.

I see. As I basically only need to gather the data and insert it into a database, I think I won’t need to parse neither $model nor $schema. Or is there any usefulness in that? I understand I could use $schema to validate the JSONs in payloads.

OT: What is the advantage to configure MTConnect devices? Does it mean to use fanuc-driver as an adapter (backend) in order to create MTConnect XML? I somewhat don’t see any usefulness in that unless you want to use MTConnect for machines of multiple vendors/manufacturers (like Fanucs and Mazaks). IMHO this would create some overhead b/c of processing the same data twice.

  • @MRIIOT, what kind of data can be received using cnc_rdalmmsg_ALL method (fanuc/{machine}/alarms topic)? I did not receive any alarm there, but it’s true that I am testing fanuc-driver on an idle machine.

Alarms!

...
      "alarms": [
        {
          "alm_no": 100,
          "type": 0,
          "axis": 0,
          "alm_msg": "PARAMETER ENABLE SWITCH ON\u0010\f\u0001h"
        }
      ]
...

Well, the thing is I didn’t receive any alarms in there (just an empty array in fanuc/{machine}/alarms and fanuc/{machine}/alarms2), only in fanuc/{machine}/message1. In Fanucs, is there any difference between alarms and messages? From my point of view, they are the same (as in alarm messages/codes).

Something like this? I don't remember if these parameters are global or if each execution path has their own counts (TODO). If each path holds their own counts then it would become fanuc/{machine}/numberOfPieces/1, fanuc/{machine}/numberOfPieces/2, ...

await Peel("numberOfPieces",
    await SetNative("produced", await platform.RdParamDoubleWordNoAxisAsync(6711)),
    await SetNative("producedLife", await platform.RdParamDoubleWordNoAxisAsync(6712)),
    await SetNative("remaining", await platform.RdParamDoubleWordNoAxisAsync(6713)));

I think yes, something like this.

As for the question if these params are global, IMHO yes, because one machine can produce only a single piece at a time, but I haven’t checked it anywhere.

MRIIOT commented 3 years ago

I see. As I basically only need to gather the data and insert it into a database, I think I won’t need to parse neither $model nor $schema. Or is there any usefulness in that? I understand I could use $schema to validate the JSONs in payloads.

The $model is useful in that it tells you how many paths/axes/spindles there are.

OT: What is the advantage to configure MTConnect devices? Does it mean to use fanuc-driver as an adapter (backend) in order to create MTConnect XML? I somewhat don’t see any usefulness in that unless you want to use MTConnect for machines of multiple vendors/manufacturers (like Fanucs and Mazaks). IMHO this would create some overhead b/c of processing the same data twice.

fanuc-driver will be used as a data feed to an MTConnect adapter which will generate a devices.xml for Agent. fanuc-driver Native handler outputs proprietary data format. SparkplugB handler adheres to SpB data format. MTConnect is there as a semantic gateway. Nothing is stopping you from adding data from MES, in-process quality checks, etc to build a more complete model of the asset/process, Fanuc or other. Then again, nothing is stopping you from doing the same without MTConnect. To me, MTConnect is all about ease of interoperability and higher level reasoning ability.

Well, the thing is I didn’t receive any alarms in there (just an empty array in fanuc/{machine}/alarms and fanuc/{machine}/alarms2), only in fanuc/{machine}/message1. In Fanucs, is there any difference between alarms and messages? From my point of view, they are the same (as in alarm messages/codes).

Alarms and Messages are two different things. https://www.youtube.com/watch?v=-3Na1_t1W8A

Something like this? I don't remember if these parameters are global or if each execution path has their own counts (TODO). If each path holds their own counts then it would become fanuc/{machine}/numberOfPieces/1, fanuc/{machine}/numberOfPieces/2, ...

await Peel("numberOfPieces",
    await SetNative("produced", await platform.RdParamDoubleWordNoAxisAsync(6711)),
    await SetNative("producedLife", await platform.RdParamDoubleWordNoAxisAsync(6712)),
    await SetNative("remaining", await platform.RdParamDoubleWordNoAxisAsync(6713)));

I think yes, something like this.

What is your db structure and data type to hold this? Would you still be breaking out each piece count from the single json?

As for the question if these params are global, IMHO yes, because one machine can produce only a single piece at a time, but I haven’t checked it anywhere.

Unless the machine has multiple and independent execution paths, then each one should be able to produce at its own takt.

tukusejssirs commented 3 years ago

The $model is useful in that it tells you how many paths/axes/spindles there are.

All I need from $model is in structure, right? Namely:

To me, MTConnect is all about ease of interoperability and higher level reasoning ability.

This might be interesting to us in the future. For now, we need to gather the data. Thanks for the explanation.

Alarms and Messages are two different things. https://www.youtube.com/watch?v=-3Na1_t1W8A

So by message Fanuc means a message created by a user/operator/programmer (it is not considered an error, just an info message), while by alarm they mean one from the alarm list published by Fanuc in the manuals (it is considered an error), right? However, that does not makes sense with the 2360 (spindle clamping loosened), which comes from fanuc/{machine}/message1, but IMO it is considered an error (and a red light is lit/blinking on the light indicator) and therefore it is an alarm. Here is an example payload:

payload: '{"observation":{"time":1627466563564,"machine":"m9_doosan_puma","type":"source","name":"message1","marker":{}},"source":{"method":"cnc_rdopmsg","invocationMs":7,"data":{"type":0,"length":262}},"state":{"time":"00:00:03.3303999","data":{"msgs":[{"data":" 2360 UVOLNENE UPNUTI VRETENE.","datano":2360,"type":0}]}}}',

Something like this? I don't remember if these parameters are global or if each execution path has their own counts (TODO). If each path holds their own counts then it would become fanuc/{machine}/numberOfPieces/1, fanuc/{machine}/numberOfPieces/2, ...

await Peel("numberOfPieces",
    await SetNative("produced", await platform.RdParamDoubleWordNoAxisAsync(6711)),
    await SetNative("producedLife", await platform.RdParamDoubleWordNoAxisAsync(6712)),
    await SetNative("remaining", await platform.RdParamDoubleWordNoAxisAsync(6713)));

I think yes, something like this.

What is your db structure and data type to hold this?

The DB structure is not yet decided; it heavily depends on the data we can gather via fanuc-driver, but basically each machine will have a separate schema with the following tables:

Anyway, we use PostgreSQL.

Would you still be breaking out each piece count from the single json?

Well, all in all, we only need the number of pieces produced with a particular program, but sometimes the operators don’t provide how many pieces they need to produce, as they sometimes produce only one piece. In that situation, the pieces to be produced parameter is 0, but the total number produced [since last Fanuc OS (re-) installation] is incremented. If fanuc-driver would take of of this, it would be awesome, but I think the client app should take care of this.

As for the question if these params are global, IMHO yes, because one machine can produce only a single piece at a time, but I haven’t checked it anywhere.

Unless the machine has multiple and independent execution paths, then each one should be able to produce at its own takt.

I see. Then my production table should include a path ID, right?

MRIIOT commented 3 years ago

The $model is useful in that it tells you how many paths/axes/spindles there are.

All I need from $model is in structure, right? Namely:

  • name is the path name (an integer);
  • observations what data I could gather from a particular machine;
  • axis and spindles array list of names of axes/spindles and observations I could gather from a particular machine.

Correct.

To me, MTConnect is all about ease of interoperability and higher level reasoning ability.

This might be interesting to us in the future. For now, we need to gather the data. Thanks for the explanation.

The future is now :)

Alarms and Messages are two different things. https://www.youtube.com/watch?v=-3Na1_t1W8A

So by message Fanuc means a message created by a user/operator/programmer (it is not considered an error, just an info message), while by alarm they mean one from the alarm list published by Fanuc in the manuals (it is considered an error), right? However, that does not makes sense with the 2360 (spindle clamping loosened), which comes from fanuc/{machine}/message1, but IMO it is considered an error (and a red light is lit/blinking on the light indicator) and therefore it is an alarm. Here is an example payload:

payload: '{"observation":{"time":1627466563564,"machine":"m9_doosan_puma","type":"source","name":"message1","marker":{}},"source":{"method":"cnc_rdopmsg","invocationMs":7,"data":{"type":0,"length":262}},"state":{"time":"00:00:03.3303999","data":{"msgs":[{"data":" 2360 UVOLNENE UPNUTI VRETENE.","datano":2360,"type":0}]}}}',

We could eventually merge alarms and messages into a single observation... but we would need to know the severity and impact of each alarm and message.

tukusejssirs commented 3 years ago

The future is now :)

True, but some stuff is out of my hands. I need to finish off some stuff, after which we need to optimise + refactor some of the code, and only afterwards I am able to implement MTConect.

We could eventually merge alarms and messages into a single observation... but we would need to know the severity and impact of each alarm and message.

From my point of view, they are still the same; the only difference being the severity. Mazaks have only one type of alarms and two levels of severity, error and warning, as I call it. Errors are always red alarms (i.e. with red background and usually white foreground), others have different fg/bg colours.

tukusejssirs commented 3 years ago

What is fanuc/{machine}/connect all about? Is its purpose to connect to the machine via FOCAS and report if the connection was successful?

tukusejssirs commented 3 years ago

I have noticed that I always receive fanuc/{machine}/paths/$schema after fanuc/{machine}/paths. Is there anything we could do to send it right after the connection is made (together with all other machine metadata)?

Actually: how should I process the fanuc/{machine}/paths? As I understand it, it reports the currently used path and the path number (maxpath_no), right? Do I actually need to process fanuc/{machine}/paths/$schema? Actually, now I think that all schemas should be sent to the subscribers in fanuc/{machine}/schemas once fanuc-driver is connected to the machine/FOCAS. Then all schemas would be sent in one packet/topic. Or are the schemas used with each packet/topic separately?

tukusejssirs commented 3 years ago

What about fanuc/{machine}/alarms/$schema? Is it changing from machine to machine? As I understand it, it does not change; it only changes when you change it in fanuc-driver, therefore there is no need to process this, right?

tukusejssirs commented 3 years ago

Could you define the sys_info payload properties please?


"state": {
  "time": "00:00:04.6447356",
  "data": {
    "loader_control": false,
    "i_series": true,
    "compound_machining": false,
    "transfer_line": false,
    "model": "MODEL F",
    "max_axis": 32,
    "cnc_type": "Series 0i",
    "mt_type": "Lathe",
    "series": "D6G1",
    "version": "34.0",
    "axes": 2
  }
}

My understanding:
- `loader_control`, `compound_machining`, `transfer_line`: ???;
- `i_series`, `model`, `max_axis`, `cnc_type`, `mt_type`, `series`, `version`, `axes`:
   - self-evident, mostly model definition (except for `max_axis` and `axes`).
tukusejssirs commented 3 years ago

On a machine I get the following cnc_statinfo:

"state": {
  "time": "00:00:04.7472348",
  "data": {
    "mode": {
      "automatic": "****(No selection)"
    },
    "status": {
      "run": "STOP",
      "edit": "****(Not editing)",
      "motion": "***",
      "mstb": "***",
      "emergency": "EMerGency",
      "alarm": "ALarM"
    }
  }
}

The state.data.mode.automatic property seems to be incorrect. The machine is in MDI mode (set before machine reboot), but FOCAS/fanuc-driver reports it ****(No selection). Granted, I haven’t been doing anything with the machine, apart from booting it up. Is it a bug or feature?

Anyway, what is that mstb? I see in fanuc/veneers/StatInfoText.cs that the only possible values are *** and FIN, but what does it mean?

Also: why is state.data.mode.automatic property called automatic? Because the mode is evaluated automatically?

tukusejssirs commented 3 years ago

What is fanuc/{machine}/figures/1 for? Could you describe its payload please?

tukusejssirs commented 3 years ago

Latest version of the algorithm description/documentation.

Adding a new Fanuc machine

@MRIIOT, it might be a good idea to create a separate collector for this (to gather initial machine metadata). I think that it should automatically quit when all information was gathered or when a error occured (like when the connection failed).

@MRIIOT, do I need to know the order of paths/axes/spindles or their names are enough?

Gather machine metadata:

{"observation":{"time":1627983214926,"machine":"m21_xxx","type":"source","name":"sys_info","marker":{"path_no":1}},"source":{"method":"cnc_sysinfo","invocationMs":0,"data":{}},"state":{"time":"00:00:04.6447356","data":{"loader_control":false,"i_series":true,"compound_machining":false,"transfer_line":false,"model":"MODEL F","max_axis":32,"cnc_type":"Series 0i","mt_type":"Lathe","series":"D6G1","version":"34.0","axes":2}}}
{"observation":{"time":1627983213244,"machine":"m21_xxx","type":"source","name":"paths","marker":{}},"source":{"method":"cnc_getpath","invocationMs":0,"data":{"path_no":0}},"state":{"time":"00:00:03.0311346","data":{"path_no":1,"maxpath_no":1}}}

@MRIIOT, what does that source.data.data_num mean?

{"observation":{"time":1627983214677,"machine":"m21_xxx","type":"source","name":"axis_names","marker":{"path_no":1}},"source":{"method":"cnc_rdaxisname","invocationMs":20,"data":{"data_num":8}},"state":{"time":"00:00:04.3788431","data":{"axes":[{"name":"X","suff":""},{"name":"Z","suff":""}]}}}

@MRIIOT, what do the following values mean?

{"observation":{"time":1627983214777,"machine":"m21_xxx","type":"source","name":"spindle_names","marker":{"path_no":1}},"source":{"method":"cnc_rdspdlname","invocationMs":11,"data":{"data_num":4}},"state":{"time":"00:00:04.4763858","data":{"spindles":[{"name":"S","suff1":"1","suff2":""}]}}}

Table

-- Fanuc-specific machine metadata
CREATE TABLE md.machines_fanuc (
  id SERIAL PRIMARY KEY,
  machine_id INT NOT NULL REFERENCES md.machines (machine),
  loader_control BOOLEAN NOT NULL  -- state.data.loader_control
  i_series BOOLEAN NOT NULL  -- state.data.i_series
  compound_machining BOOLEAN NOT NULL  -- state.data.compound_machining
  transfer_line BOOLEAN NOT NULL  -- state.data.transfer_line
  model VARCHAR  -- state.data.model
  max_axis SMALLINT NOT NULL  -- state.data.max_axis
  cnc_type VARCHAR  -- state.data.cnc_type
  mt_type VARCHAR  -- state.data.mt_type
  series VARCHAR  -- state.data.series
  version VARCHAR  -- state.data.version
  axes_num  SMALLINT NOT NULL  -- state.data.axes; TODO: I might want to remove this in favour of `axes` below.
  -- Note: I might want to change the arrays to tables.
  paths VARCHAR[] NOT NULL,
  axes VARCHAR[] NOT NULL,
  spindles VARCHAR[] NOT NULL,
);

REVOKE ALL ON TABLE md.machines_fanuc FROM PUBLIC;
GRANT ALL ON TABLE md.machines_fanuc TO machinescs;
ALTER TABLE md.machines_fanuc OWNER TO machinescs;

Data processed while the machine is being monitored

Note: Always process the timestamp in observation.time (it is in UNIX Epoch and in milliseconds).

  1. If the machine is online: fanuc/$disco and fanuc/{machine}/ping.
    • TODO: Which one is a better approach?
'{\n' +
  '  "m21_xxx": {\n' +
  '    "added": 1627983212722,\n' +
  '    "seen": 1627983212804,\n' +
  '    "machineId": "m21_xxx",\n' +
  '    "arrivalTopic": "fanuc/m21_xxx-all",\n' +
  '    "changeTopic": "fanuc/m21_xxx"\n' +
  '  }\n' +
  '}',

{"observation":{"time":1627983215759,"machine":"m21_xxx","name":"ping"},"source":{"data":{"_id":"m21_xxx","IPAddress":"10.14.7.42","Port":8193,"ConnectionTimeout":10}},"state":{"data":"OK"}}
  1. Process alarms (including messages):
    • fanuc/{machine}/alarms;
    • fanuc/{machine}/alarms2;
    • fanuc/{machine}/message1;
    • potentially other alarms/messages with different integer suffixes;
    • TODO: end time, level, potentially merge messages with alarms, extra info, place where the alarm occured

Note: Process observation.time as start time when an alarm first shows up, and as end time when it disappears.

{"observation":{"time":1627983213872,"machine":"m21_xxx","type":"source","name":"alarms","marker":{}},"source":{"method":"cnc_rdalmmsg_ALL","invocationMs":266,"data":{"minType":0,"maxType":20,"count":10}},"state":{"time":"00:00:03.6566516","data":{"alarms":[{"alm_no":1401,"type":15,"axis":0,"alm_msg":" AFTER EMG PLS.PUSH\\"EMG RESET\\" "}]}}}

{"observation":{"time":1627983214368,"machine":"m21_xxx","type":"source","name":"alarms2","marker":{}},"source":{"method":"cnc_rdalmmsg2_ALL","invocationMs":332,"data":{"minType":0,"maxType":20,"count":10}},"state":{"time":"00:00:04.1515902","data":{"alarms":[{"alm_no":1401,"type":15,"axis":0,"alm_msg":" AFTER EMG PLS.PUSH\\"EMG RESET\\" BUTTON(A14.1)"}]}}}

{"observation":{"time":1627983214510,"machine":"m21_xxx","type":"source","name":"message1","marker":{}},"source":{"method":"cnc_rdopmsg","invocationMs":30,"data":{"type":0,"length":262}},"state":{"time":"00:00:04.2931885","data":{"msgs":[{"data":" AL2174   WHEN POWER ON, MCC OFF TEST REQUEST(A17.4)  1.ALL AXES NEED STOP.    2.CLOSE THE DOOR.     3.SELECT MPG MODE.       4.PUSH FEED HOLD BUTTON.     5.CYCLE START ENABLE AFTER MCC TEST COMPLETE.","datano":2174,"type":0}]}}}

Table

-- Fanuc-specific alarms table
CREATE TABLE mx.alarms (
  id SERIAL PRIMARY KEY,
  start_time TIMESTAMP WITH TIME ZONE NOT NULL,
  end_time TIMESTAMP WITH TIME ZONE NOT NULL,
  level md.alarm_types NOT NULL,
  code SMALLINT NOT NULL,
  message VARCHAR NOT NULL,
  -- extra_info VARCHAR(59),
  -- head VARCHAR(3),
  -- place VARCHAR(8) NOT NULL,
);

REVOKE ALL ON TABLE md.machines_fanuc FROM PUBLIC;
GRANT ALL ON TABLE md.machines_fanuc TO machinescs;
ALTER TABLE md.machines_fanuc OWNER TO machinescs;
  1. machine state (mode, alarm, emergency, etc): fanuc/{machine}/stat_info/1

    • TODO: feedrate override and rapid override
{"observation":{"time":1627983215037,"machine":"m21_xxx","type":"source","name":"stat_info","marker":{"path_no":1}},"source":{"method":"cnc_statinfo","invocationMs":8,"data":{}},"state":{"time":"00:00:04.7472348","data":{"mode":{"automatic":"****(No selection)"},"status":{"run":"STOP","edit":"****(Not editing)","motion":"***","mstb":"***","emergency":"EMerGency","alarm":"ALarM"}}}}

Table

-- Fanuc-specific status table
CREATE TABLE mx.status (
  id SERIAL PRIMARY KEY,
  date_time TIMESTAMP WITH TIME ZONE NOT NULL,
  -- TODO: Fix the constrait, as `paths` column will be an array.
  path_id INT NOT NULL REFERENCES md.machines_fanuc (paths),
  green BOOLEAN NOT NULL,
  orange BOOLEAN NOT NULL,
  red BOOLEAN NOT NULL,
  turned_off BOOLEAN NOT NULL,
  -- Note: For available values, see `fanuc/veneers/StatInfoText.cs`.
  -- TODO: Define column data types.
  mode  -- state.data.mode.automatic
  run  -- state.data.status.run
  edit  -- state.data.status.edit
  motion  -- state.data.status.motion
  mstb  -- state.data.status.mstb
  emergency  -- state.data.status.emergency
  alarm  -- state.data.status.alarm
);

REVOKE ALL ON TABLE md.machines_fanuc FROM PUBLIC;
GRANT ALL ON TABLE md.machines_fanuc TO machinescs;
ALTER TABLE md.machines_fanuc OWNER TO machinescs;
  1. parts count:
    • fanuc/{machine}/6711/1 (number of pieces produced);
    • fanuc/{machine}/6713/1 (number of pieces to be produced)
    • fanuc/{machine}/6712/1 (total number of pieces produced);
    • TODO: program name
{"observation":{"time":1627983215483,"machine":"m21_xxx","type":"source","name":"6711","marker":{"path_no":1}},"source":{"method":"cnc_rdparam","invocationMs":38,"data":{"number":6711,"axis":0,"length":8,"IODBPSD_type":1}},"state":{"time":"00:00:05.1866236","data":{"ldata":107}}}

{"observation":{"time":1627983215522,"machine":"m21_xxx","type":"source","name":"6712","marker":{"path_no":1}},"source":{"method":"cnc_rdparam","invocationMs":16,"data":{"number":6712,"axis":0,"length":8,"IODBPSD_type":1}},"state":{"time":"00:00:05.2240095","data":{"ldata":105214}}}

{"observation":{"time":1627983215556,"machine":"m21_xxx","type":"source","name":"6713","marker":{"path_no":1}},"source":{"method":"cnc_rdparam","invocationMs":12,"data":{"number":6713,"axis":0,"length":8,"IODBPSD_type":1}},"state":{"time":"00:00:05.2578817","data":{"ldata":0}}}

Table

-- Fanuc-specific production table
CREATE TABLE mx.production (
  id SERIAL PRIMARY KEY,
  start_time TIMESTAMP WITH TIME ZONE NOT NULL,
  end_time TIMESTAMP WITH TIME ZONE NOT NULL,
  path_id INT NOT NULL REFERENCES md.machines_fanuc (paths),  -- TODO: Fix the constrait, as `paths` column will be an array.
  program_name VARCHAR,
  parts_produced SMALLINT,
  parts_to_produce SMALLINT,
  total_parts_produced INT
);

REVOKE ALL ON TABLE md.machines_fanuc FROM PUBLIC;
GRANT ALL ON TABLE md.machines_fanuc TO machinescs;
ALTER TABLE md.machines_fanuc OWNER TO machinescs;
MRIIOT commented 3 years ago

What is fanuc/{machine}/connect all about? Is its purpose to connect to the machine via FOCAS and report if the connection was successful?

Yes. If we fail to connect, we don't collect data. Connect -> collect data -> disconnect.

MRIIOT commented 3 years ago

I have noticed that I always receive fanuc/{machine}/paths/$schema after fanuc/{machine}/paths. Is there anything we could do to send it right after the connection is made (together with all other machine metadata)?

It would have to all be in the same topic. It is possible, but see my note about $schema in the next comment.

Actually: how should I process the fanuc/{machine}/paths? As I understand it, it reports the currently used path and the path number (maxpath_no), right? Do I actually need to process fanuc/{machine}/paths/$schema? Actually, now I think that all schemas should be sent to the subscribers in fanuc/{machine}/schemas once fanuc-driver is connected to the machine/FOCAS. Then all schemas would be sent in one packet/topic. Or are the schemas used with each packet/topic separately?

Correct, current path and max paths. I don't think this packet is very valuable.

Do you have an example how you would use the $schema payloads?

MRIIOT commented 3 years ago

What about fanuc/{machine}/alarms/$schema? Is it changing from machine to machine? As I understand it, it does not change; it only changes when you change it in fanuc-driver, therefore there is no need to process this, right?

You bring up a good point. So the issue is that I did not statically type a lot of the code, this would take forever. Instead I used the 'dynamic' .NET type. Alarms for example, when the payload is empty, the published schema will look different than when a JSON schema is built from a payload where alarms are present. I'm not sure how to handle this, but I don't think I'll be creating static types for every data structure.

MRIIOT commented 3 years ago

Could you define the sys_info payload properties please?

"state": {
  "time": "00:00:04.6447356",
  "data": {
    "loader_control": false,
    "i_series": true,
    "compound_machining": false,
    "transfer_line": false,
    "model": "MODEL F",
    "max_axis": 32,
    "cnc_type": "Series 0i",
    "mt_type": "Lathe",
    "series": "D6G1",
    "version": "34.0",
    "axes": 2
  }
}

My understanding:
- `loader_control`, `compound_machining`, `transfer_line`: ???;
- `i_series`, `model`, `max_axis`, `cnc_type`, `mt_type`, `series`, `version`, `axes`:
   - self-evident, mostly model definition (except for `max_axis` and `axes`).

https://www.inventcom.net/fanuc-focas-library/misc/cnc_sysinfo

MRIIOT commented 3 years ago

On a machine I get the following cnc_statinfo:

"state": {
  "time": "00:00:04.7472348",
  "data": {
    "mode": {
      "automatic": "****(No selection)"
    },
    "status": {
      "run": "STOP",
      "edit": "****(Not editing)",
      "motion": "***",
      "mstb": "***",
      "emergency": "EMerGency",
      "alarm": "ALarM"
    }
  }
}

The state.data.mode.automatic property seems to be incorrect. The machine is in MDI mode (set before machine reboot), but FOCAS/fanuc-driver reports it ****(No selection). Granted, I haven’t been doing anything with the machine, apart from booting it up. Is it a bug or feature?

Bug. 0i aut=0 is MDI. Look at all the lists for every different controller model. https://www.inventcom.net/fanuc-focas-library/misc/cnc_statinfo

I would say for now use StatInfo instead StatInfoText. We will need to pass cnc_sysinfo response into StatInfoText to make decision on the text based on controller model.

Anyway, what is that mstb? I see in fanuc/veneers/StatInfoText.cs that the only possible values are *** and FIN, but what does it mean?

Don't know.

Also: why is state.data.mode.automatic property called automatic? Because the mode is evaluated automatically?

That's a bug. Should be just state.data.mode.

image

MRIIOT commented 3 years ago

What is fanuc/{machine}/figures/1 for? Could you describe its payload please?

https://www.inventcom.net/fanuc-focas-library/misc/cnc_getfigure

number of decimal places under the input/output unit, which is related to various data of CNC.

Used to put the decimal point in the correct place for axis position.

https://github.com/Ladder99/fanuc-driver/blob/abe26bc4625d75b36e55751875173c92c13e2915/fanuc/veneers/RdDynamic2_1.cs#L45-L51

MRIIOT commented 3 years ago

Latest version of the algorithm description/documentation.

Adding a new Fanuc machine

@MRIIOT, it might be a good idea to create a separate collector for this (to gather initial machine metadata). I think that it should automatically quit when all information was gathered or when a error occured (like when the connection failed).

Why?

@MRIIOT, do I need to know the order of paths/axes/spindles or their names are enough?

I guess you want to know which axis belongs to which path...

@MRIIOT, what does that source.data.data_num mean?

@MRIIOT, what do the following values mean?

  • source.data.data_num;
  • state.data.loader_control;
  • state.data.compound_machining;
  • state.data.transfer_line.

You'll have to look these up in the Focas docs.

  1. If the machine is online: fanuc/$disco and fanuc/{machine}/ping.

$disco - discovery endpoint and last time Focas interrogated the machine ping - updated every sweep with state.data OK/NOK depending if any Focas errors were encountered during collection

  • TODO: Which one is a better approach?
'{\n' +
  '  "m21_xxx": {\n' +
  '    "added": 1627983212722,\n' +
  '    "seen": 1627983212804,\n' +
  '    "machineId": "m21_xxx",\n' +
  '    "arrivalTopic": "fanuc/m21_xxx-all",\n' +
  '    "changeTopic": "fanuc/m21_xxx"\n' +
  '  }\n' +
  '}',

{"observation":{"time":1627983215759,"machine":"m21_xxx","name":"ping"},"source":{"data":{"_id":"m21_xxx","IPAddress":"10.14.7.42","Port":8193,"ConnectionTimeout":10}},"state":{"data":"OK"}}
MRIIOT commented 1 year ago

I don't see anymore work to be done on this. Closing.