Closed zachallaun closed 1 year ago
Hey Zach, thank you for your comment! The approach you mention does sound good.
We had started a Zebra printer driver a while back, but currently it just reports an error if there are any errors, or a warning, or normal -
When we revisit this driver I'll store all the errors and warnings in the value
passed to the cache, and compare them with those in the previous value, and report the status(es) accordingly via SHDR.
There's also a qualifier which looks like it could be part of the key (from part 3 of the standard) -
1051 When a qualifier of either HIGH or LOW is used with Fault and Warning, the 1052 Fault States can be differentiated as follows: 1053 Fault,LOW 1054 Warning,LOW 1055 Normal 1056 Warning,HIGH 1057 Fault,HIGH
I'll leave this issue open until we implement the handler.
Thanks again - let us know if you need help with anything. The repo is currently on version 0.7 in the 'develop' branch - working on 0.8 in the 'relay' branch.
Brian brian@mriiot.com
Thanks for the response, Brian!
I don’t believe Qualifier should be a part of the key. The qualifier is meant to indicate the “direction” in which something is out of tolerance. The example I saw was something like oil temp — a warning about it being high could use a “HIGH” qualifier to provide more information.
Given that, qualifier is more about providing context to the warning — I don’t believe it would make sense for a warning (with same native code) to ever have two entries with two different qualifiers, since that would be like saying the oil temp is both too high and too low at the same time.
—
I’ve been checking out the develop and relay branches as well. I’m amazed by the amount of work you’ve done on this! As a tiny bit of personal context: I found this project only a few days ago while looking for reference adapter implementations. I’m working on my own small shop monitor system (2 machines) and plan to write an adapter for our Brother Speedio (vs paying the $1500 for one that I believe exposes less data than I’ll be able to).
Our front-end needs are pretty different than the Ladder99 default, but it’s suuuuper cool to see that we made basically the same backend decisions (Postgres + timescaledb). I’m now thinking of potentially using the Ladder99 pipeline and just sticking my own app in front of the database.
Anyways, I may bug you later on for a bit of implementation/setup help, but for now I’m learning a lot just reading through your source.
On Tue, Apr 26, 2022 at 6:23 AM Brian Burns @.***> wrote:
Hey Zach, thank you for your comment! The approach you mention does sound good.
We had started a Zebra printer driver a while back, but currently it just reports an error if there are any errors, or a warning, or normal -
When we revisit this driver I'll store all the errors and warnings in the value passed to the cache, and compare them with those in the previous value, and report the status(es) accordingly via SHDR.
There's also a qualifier which looks like it could be part of the key (from part 3 of the standard) -
1051 When a qualifier of either HIGH or LOW is used with Fault and Warning, the 1052 Fault States can be differentiated as follows: 1053 Fault,LOW 1054 Warning,LOW 1055 Normal 1056 Warning,HIGH 1057 Fault,HIGH
I'll leave this issue open until we implement the handler.
Thanks again - let us know if you need help with anything. The repo is currently on version 0.7 in the 'develop' branch - working on 0.8 in the 'relay' branch.
Brian @.***
— Reply to this email directly, view it on GitHub https://github.com/Ladder99/ladder99-ce/issues/130#issuecomment-1109622102, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAD3BAWL4IOF5O47XW6EFW3VG673DANCNFSM5UHDBH4A . You are receiving this because you authored the thread.Message ID: @.***>
Ah you're right, no need for qualifier in the key!
Yeah pg/timescaledb is great, very flexible. The current db structure is a little experimental with nodes and edges tables, though we could switch to a more conventional table structure if needed, when we optimize everything in v0.9.
I'm refactoring the db a bit in the relay branch / v0.8, but should end up with the same or similar views. We need to be able to point the Relay at any combination of Agents, and there could be device name and dataitem id collisions, so need to handle things a little differently.
What kind of frontend are you planning to make?
The db structure is definitely neat! I enjoyed reading through the migrations. I've used jsonb
a fair amount before, but usually to store unknown/unstructured data. My initial concern was maybe losing some of timescaledb's performance or functionality by storing so much in jsonb
, but I know pg has come a long way in terms of query/indexing/etc. performance on JSON.
Storing underlying data as a graph and then using views (possibly some materialized) to create a more "conventional" interface could be a good approach.
As for what I'm working on: my focus is primarily on real-time monitoring for a small shop where everyone wears a lot of hats and are running between the shop and office:
At the moment, the benefit we're getting from it is less about understanding machine utilization and more about making sure that the next pallet is loaded up by the time the cycle is finished. =) In addition to storing underlying MTC data, I have a small state machine that's tracking and logging program executions. The eventual goal is to tie programs to parts and material and be able to use this for higher-level production tracking.
The source is closed for the time being, mostly because I need to more carefully audit the IP camera integration. All in all it consists of a RedwoodJS web application (sort of regretting it because Prisma is pretty limiting when you want to do fancy SQL things) and a Raspberry Pi that's 1) ingesting MTConnect data and 2) transcoding RTSP video from the IP cameras to something that can be streamed in a browser.
Zach, thanks for the kind words. Brian has put a lot of thought behind the design of Ladder99. Our focus has never been on the front-end but more on the validity and usability of data by MTC apps and SQL has been our proving ground. This would the north side direction for Ladder99. Focus for the south side of the Agent is adapter and device model development, which still needs more thought.
plan to write an adapter for our Brother
I would be interested in the details as we will have to develop a Brother as well. We also have an adapter for Fanuc CNCs. https://github.com/Ladder99/fanuc-driver
IP camera integration
Would there be value in capturing frames from the video feed and referencing them somewhere in MTC Assets?
-chris
Coincidentally, I read about this exact case earlier today in a MTConnect PowerPoint presentation that I’m now struggling to find. Anyways: Apparently the correct move here is to key Condition off of ID + native code. You can have more than one condition value for an ID, but only one for an ID + native code.
Say there are 3 conditions present at a machine tool:
logic_cond warning code=1 logic_cond warning code=2 logic_cond fault code=3
All 3 should be broadcast via SHDR. If the fault resolves, you broadcast:
logic_cond normal code=3
but the warnings for code 1/2 remain. When all warning conditions resolve, you can broadcast normal without reference to a native code.
The assumption here is that the adapter is responsible for maintaining state of individual conditions in order to eventually resolve to a NORMAL. To me this is preferred over blasting a single CONDITION.
Let's take a look at a several known conditions for a thermal printer: low ribbon, out of ribbon, low paper, out of paper, motor temperature. When generated at the source, they all might as well be a table of codes.
code | description |
---|---|
120 | motor over temp |
002 | ribbon low |
102 | ribbon out |
001 | paper low |
101 | paper out |
999 | something else |
You could model this like so, and blast the above codes.
<Device>
<Controller>
...
<DataItem category="CONDITION" id="system_cond" type="SYSTEM"/>
</Controller>
</Device>
Or you could develop the model further, and have the opportunity be more selective.
<Device>
...
<Controller>
...
<!-- catch all for underdeveloped model -->
<DataItem category="CONDITION" id="system_cond" type="SYSTEM" />
</Controller>
<Axes>
...
<Linear name="x">
...
<DataItem category="CONDITION" id="x_motor_temp_cond" type="TEMPERATURE" compositionId="x_motor" />
<!-- maps paper low warning, paper out fault -->
<DataItem category="CONDITION" id="paper_cond" type="DATA_RANGE" compositionId="paper_sensor" />
<!-- maps ribbon low warning, ribbon out fault -->
<DataItem category="CONDITION" id="ribbon_cond" type="DATA_RANGE" compositionId="ribbon_sensor" />
...
<Composition id="x_motor" type="MOTOR" />
<Composition id="paper_sensor" type="SENSING_ELEMENT" />
<Composition id="ribbon_sensor" type="SENSING_ELEMENT" />
</Linear>
</Axes>
<Systems>
</Systems>
</Device>
Hi Zach,
My initial concern was maybe losing some of timescaledb's performance or functionality by storing so much in jsonb
Storing underlying data as a graph and then using views (possibly some materialized) to create a more "conventional" interface could be a good approach.
Yeah I'll do some profiling soon - might need to migrate to tables like history_text and history_number instead of the jsonb. The end-user services like Grafana use the views, and are not meant to see the underlying tables.
I'll post a design decisions doc that explains some more to the github wiki today, with some diagrams.
In addition to storing underlying MTC data, I have a small state machine that's tracking and logging program executions. The eventual goal is to tie programs to parts and material and be able to use this for higher-level production tracking.
Ah, yeah we want to do similarly - currently we do tie in to JobBoss to get the job number, and reset a part counter when the value changes. We also get the work schedule for calculating the availability / utilization %. The Meter service calculates statistics like that, and will do more state machine tracking in the future.
Your app looks good - I like the video feed! Would be nice to have that with our setup also, but not sure about the hardware issues.
I uploaded some diagrams and design decisions to the wiki here - https://github.com/Ladder99/ladder99-ce/wiki
@MRIIOT Oh, I definitely agree with you re: modeling conditions. I just meant to point out that, in order to be compatible with the existing ecosystem, I think conditions need to be keyed off of the name/id + native code. I quite like the idea of compositional conditions such that a monitoring system could have a high level data item to look at to answer the simple question of "is the printer currently operational?" and then multiple lower-level data items to look at to dig into the subsystems.
Re: video frames. I'm not sure about frames, but it could be very cool to store clips associated with warnings/fault events. Depending on where I have a camera set up, I'd love to be able to see a clip of where a tool broke. This is something I'm planning on implementing in the future (clips would be uploaded to Amazon S3), but I hadn't considered exposing them as MTC Assets -- that could be kind of cool as well. (You'd just include a link to the S3 download in the asset.)
@bburns Re: video feed -- it's definitely a bit of a pain, but part of that for me may be that I'm transcoding the video stream on a WiFi-connected Raspberry Pi. =) Once I have a more stable system, I'll be happy to share the implementation details in case it's something you all are interested in at some point in the future.
@zachallaun Does the native code actually come across in the MTC stream? I never paid attention.
I ordered one of these last week to finally start learning CV.
Yep, they comes across. I think the idea is they usually map to the error/warning code that you'd look up in your device's manual. It obviously depends on your devices.xml, but I get native codes from my Mazak horizontal using the cppagent.
That camera kit is super interesting! I've been looking for something like this. IP67 sealed as well... I need to look into these...
That camera kit is super interesting! I've been looking for something like this. IP67 sealed as well... I need to look into these...
I know we're hijacking the thread at this point but whatever.
The camera works out of the box. I've been reading the docs and they've built a nice ecosystem, partnering with roboflow.com to train your own models. I also came across onepanel.ai a while back. @zachallaun, do you have much experience with CV? In the end, I'm looking to do basic classification, tracking tasks, but with my own data. Like a Cognex or Banner vision sensor.
@bburns , what was your experience with the OpenMV hardware?
The OpenMV was really easy to setup and use, but I guess is geared towards lower resolution / framerate applications - https://openmv.io/products/openmv-cam-h7-plus. It was able to scan moving barcodes pretty well though.
@bburns can this be closed?
@MRIIOT yes, i think you answered it - https://github.com/Ladder99/ladder99/issues/130#issuecomment-1110484999
Hi there! First off, this is a really neat project and I sincerely appreciate you all putting it out there into the world. It seems like this is being very actively developed and I’m eager to see it progress.
I was just acquainting myself a bit with the code and architecture and ran across this comment:
https://github.com/Ladder99/ladder99-ce/blob/9a583d7c255a1c2edb7c2472ab9352056b6fb733/services/adapter/src/cache.js#L144
Coincidentally, I read about this exact case earlier today in a MTConnect PowerPoint presentation that I’m now struggling to find. Anyways: Apparently the correct move here is to key Condition off of ID + native code. You can have more than one condition value for an ID, but only one for an ID + native code.
Say there are 3 conditions present at a machine tool:
logic_cond warning code=1 logic_cond warning code=2 logic_cond fault code=3
All 3 should be broadcast via SHDR. If the fault resolves, you broadcast:
logic_cond normal code=3
but the warnings for code 1/2 remain. When all warning conditions resolve, you can broadcast normal without reference to a native code.
At least that was my understanding as of earlier today! Please feel free to close this issue/manage it how you will, but I thought I’d share in case it was helpful and because the coincidence was just too delightful.