Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial OpenRPC docs - with state subscription #5

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from

Conversation

evan-brooks
Copy link

Each method and schema is organized in its own file and compiled with the tool I created open-rpc-compiler into a single openrpc.json representing the complete API

A state schema is defined that is the basis of subsriptions.

Copy link
Contributor

@grandpaSam grandpaSam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only change needed, Which may or may not be required in this project is that jog speed is usually set by a separate register not in the parameters of the jog command.

In a way though we are creating a new standard and may want this to be a feature now.

@evan-brooks
Copy link
Author

Putting it in the jog command makes sense to me but either way seems fine!

Copy link
Contributor

@jakeanq jakeanq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a tool for editing these files? The format seems extremely verbose...

For comparison, an example of ROS's format (which doesn't cover the same information admittedly, but it's a similar use-case): http://docs.ros.org/en/melodic/api/sensor_msgs/html/msg/JointState.html

{
"type": "object",
"properties": {
"jointIndex": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps redundant if we're doing an array of these? I can't see a lot of uses for reading back just one joint at a time.

"type": "object",
"properties": {
"jointIndex": {
"type": "integer"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what the spec says about this but should we define ints etc with exact widths, eg a 32-bit integer? It's probably not too much of an issue to just define integer as 64-bit signed in all cases, but maybe we'd want to pack from/unpack to specific types on the motion controller side (ie C, C++ or Rust)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSON schema does not allow for this. We need to map keys to memory space on the controller anyway, so we probably can specify the type for C / Rust in the same lookup table we use for memory mapping?

Copy link
Author

@evan-brooks evan-brooks Sep 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we actually could just add our own keyword if we wanted.

{
  "type": "object",
    "properties": {
        "jointIndex": {
            "type": "integer",
            "data-type": "u8",
        }
    }
}

{
"type": "array",
"items": {
"$ref": "#/components/schemas/jointPosition"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like being able to reference stuff in like this, seems useful

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somewhere we need to include unit information. Presumably this is in μm for linear joints, but not sure what we'd be doing angular joints in? I'd maybe lean towards making it a double and using radians

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think defining the units in the name of the data type would be a good idea. For example jointPositionRadians

I didn't know what the unit was and none of this was meant to be finalized data types, just simple examples.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually if you are trying to look at raw motor positions. (which is really just for troubleshooting and calibrating) You would just get the step count from origin. Knowing the current radians of a motor that may fully rotate 20 to 30 times in the joints full range of motion is not as useful as you might think

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see us needing both values - the raw positions seems useful for calibration/troubleshooting as you mention, the joint position in radians would be the easiest way to display a 3D representation of the robot though I think.

"type": "object",
"properties": {
"robotOnline": {
"type": "boolean"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like it's going to be an enum, since we could have a lot of potential states - eg drives offline, estop, teach/manual, active-paused, run etc

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can define an enum

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to be careful about this. Most operators manuals for industrial robots have a state chapter (including error states) that are dozens of pages long. This could be daunting to write out on an enum

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the robotOnline was literally just put in as an example value. The point of this was just to establish a format that people like you can use to develop the details

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point on the enum getting pretty big - I can see us maybe having a hierarchy of states, eg the main state is error, the substate is error-hardware-overcurrent and there's also an associated error message.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thoughts maybe the state is just presented as a string (for showing to the user) and anything that needs to make decisions checks state flags which the controller toggles based on the state, eg jog_enabled, has_error - that keeps the state logic more contained inside the controller

@@ -0,0 +1,15 @@
{
"name": "getActiveSubscriptions",
"description": "Get a list of state keys for which the client is currently subscribed to value changes",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very useful

"type": "boolean"
},
"jointPositions": {
"$ref": "#/components/schemas/jointPositions"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd keep this separate from the controller state - the complete controller state does include joint positions, but it also includes a lot of other values and I think we need to be able to pick and choose. Also it just seems cleaner to keep things separate.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the getState method provides the ability to include or exclude keys. You can also call the getPosition method to get just that. The reason that all state items are also included in a state object is so that there is a place to list all of the state parameters and it is a mechanism for transmitting any changes to state.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a way to generalize the API. So we dont' necessarily have to create methods for every parameter that gets added to state. If you add a new key to state, it can automatically be subscribed to.

},
{
"name": "direction",
"description": "Direction to jog the joint.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably you could just specify a negative velocity rather than having this be separate?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. That makes sense

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have to be careful with the velocity field. There are other factors that contribute to the final velocity of the jog. Most of these factors are determined in the safety circuit. For example if a specific safety switch is open (like a person gate) than the max jog speed of the robot is radically lowered and would be outside of whatever value you sent to the API.

In that respect. I believe the velocity value should instead be a percentage.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that would depend on what you expected to happen if something changed the maximum permissible speed while the robot was moving, for example if the control setpoint is 20% and robot is moving at 20mm/s then the safety system changes the limit from 100mm/s to 50mm/s, would you expect the robot to drop back to 10mm/s or remain constant at 20mm/s.

We'd probably also want a separate absolute interface for use with external control systems (ROS etc) - perhaps that would be enabled in addition to the jog interface if the client has an extra permission enabled, since it shouldn't be accessible from the UI as it'd be operational in run mode instead of teach/manual mode.

@evan-brooks
Copy link
Author

Is there a tool for editing these files? The format seems extremely verbose...

For comparison, an example of ROS's format (which doesn't cover the same information admittedly, but it's a similar use-case): http://docs.ros.org/en/melodic/api/sensor_msgs/html/msg/JointState.html

See here: https://github.com/open-rpc/inspector

@jakeanq
Copy link
Contributor

jakeanq commented Sep 17, 2023

That inspector tool seems to be exactly what I was looking for - I'll see if I can use it to convert the examples in #6 to OpenRPC format later today

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants