Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Loading robot calibration values #390

Closed
Doomerdinger opened this issue Feb 17, 2021 · 16 comments
Closed

Loading robot calibration values #390

Doomerdinger opened this issue Feb 17, 2021 · 16 comments
Labels
enhancement more-info-needed Waiting on additional information from poster

Comments

@Doomerdinger
Copy link
Contributor

Doomerdinger commented Feb 17, 2021

Currently there is no way to add kinematic calibration offsets to any of the motoman arms.

This is a functionality that I currently need so I am looking for feedback on my thoughts on how to implement this. I have a couple trains of thought.

First is to have the nominal values for xyz rpy coded direcetly in the xacro file and then offsets are applied to those on each joint, pulling from a dictionary value that is provided to the macro. This would allow loading of a yaml file to be passed in, or if yaml loading must be avoided within this project itself we could define the values something like

 <xacro:property name="kin_offsets" value="${
        dict([
          ('1_s',
                dict([
                    ('x', 1),
                    ('y', 0),
                    ('z', 0)
                    ...

which would just be mimicking a yaml file. To be clear, a yaml file could still be parsed externally to this project and the result used as input, but within this project the loading yaml could be avoided since some projects that depend on this one do not support yaml loading.

That's the first approach, hardcoded nominal + configurable offsets for each joint.

Second approach is not specifying offsets from nominal, but specifying the whole offset. In this case the default values would be the nominal values, and those values would be overwritten with calibration values.
From a functionality standpoint this second one seems better, avoids any potential issues with calibration offsets not being calculated with the right nominal values or whatever. If they are incorrect they will be clearly incorrect since it'd likely be a whole 90+ degrees off instead of just a tiny fraction off.

This approach does make the nominal values less clear/harder to locate since they would all be dictionary values instead of clearly hardcoded. Assuming loading yaml is out of the question, the same format used example dictionary above could be used to specify the default nominal values which would only be used if a calibration dictionary was not specified.

Again, the second approach I believe is better from a functional standpoint (based partially on real world issues my team has encountered) but at the cost of some clarity which I know is of high importance in a library like this. Could be some other trade-offs I'm not thinking of. Thoughts?

@gavanderhoorn
Copy link
Member

gavanderhoorn commented Feb 22, 2021

Thanks for posting the issue.

Calibration of robots is an interesting topic, especially when you want to store the results in a non-robot-OEM-specific way.

I believe there are two separate things to figure out here:

  1. how to store the result of such kinematic calibrations in a nice, efficient and not overly verbose way
  2. whether to store offsets/deltas from a perfect/default kinematic model, or absolute link lengths and orientations of joints

However, even if these are separate issues, a choice for the second does in fact influence what would make sense for the first.

The only other robot OEM I know where there is currently support for exporting and using the kinematic calibration data is Universal Robots. @fmauch was responsible for designing the conversion and the way to store the results in that case. He's used the non-delta approach IIRC.

@fmauch: would you perhaps be willing to share why you chose that approach (perhaps because the UR controller doesn't store deltas)? And whether you'd do it again?

Personally I'd probably go for that as well.

From what I can see now, this would require the least amount of changes, and would also not result in very verbose constructs in the .xacros which would otherwise need offsets added to nominal values (with 3 for the position and 3 for the orientation of joints, that gets really very ugly quickly).

There would also (probably) be a 1-to-1 correspondence between the structure in the .xacro and the values in the controller, instead of deltas which then have to be added to nominal values.

As to where to store that data, and how to get it into an existing .xacro, there are a few options.

.yaml comes to mind, as it nicely separates the structure from the variable data. It's also easy to generate by external systems, contrary to having to parse and update XML (requires knowledge of the .xacro's structure).

Another option would be to avoid a separate .yaml file, and simply generate a "calibrated .xacro". That would result in a very "flat" approach, but would result in essentially forking the upstream package for each-and-every calibrated robot. It would be trivial to support for other parsers though (as there is nothing to support: it'd be standard xacro).


Edit: and an additional aspect to consider: axis/joint orientation.

Ideally, we keep everything compliant with ROS REP-103: Standard Units of Measure and Coordinate Conventions, especially wrt chirality and orientation.

@gavanderhoorn
Copy link
Member

gavanderhoorn commented Feb 22, 2021

I'd like to ask some opinions / comments of other users of xacro (not necessarily motoman users).

@rhaschke: you're an extensive xacro user (+ the maintainer): what would you suggest we consider here? Deltas, absolute values, or perhaps something else entirely?

@simonschmeisser @JeroenDM: any comments on what would work best/better with opw_kinematics? I guess it doesn't really matter, as long as the values are known, but would it be able to deal with joint transforms which are not strictly parallel? It's possible results of calibration will invalidate some assumptions.

@rhaschke has commented on calibration related issues wrt IK solvers in UniversalRobots/Universal_Robots_ROS_Driver#316 (continued at ros-industrial/universal_robot#564).

@marip8 @steviedale @JeremyZoss @Levi-Armstrong: have you guys done any work on/with calibrated urdfs?

@marip8: you seem to have gone for the nominal+offsets approach in marip8/abb_experimental@9a755f5?

Perhaps even @shaun-edwards: have you guys done any work with calibration?

@gavanderhoorn gavanderhoorn added enhancement more-info-needed Waiting on additional information from poster labels Feb 22, 2021
@rhaschke
Copy link

In our setup, we inject calibration data via yaml-loaded dictionaries as absolute values. If you like, you can easily provide a default calibration file as a fallback if nothing else is specified. Absolute values are definitely to prefer for readability. All the required information will be stored in a single locatio - the yaml file - instead of being distributed across multiple files.

@simonschmeisser
Copy link
Contributor

we have not found a satisfying solution besides recommending people to use high quality robots when they need precision. For our use case (bin-picking) numerical IK-solvers just simply don't work. So when customers want to use UR we inform them that precision won't be better than 5mm and use the nominal model. We used a hybrid approach of seeding trac-ik (calibrated) with ur-kinematics (nominal values) in one project but that still failed in edge cases so I would not recommend it.
If you need speed I would suggest trying to first check if joint offsets are sufficient (typically you can even calibrate/fix that on-device) and if not see if you can squeeze the imperfections of your robot into the analytical model (ie check if some numerical optimization of the opw parameters gives a sufficiently small error on you measured data?) This could then be stored as just another opw parameter file (ie yaml) format.

@gavanderhoorn
Copy link
Member

@rhaschke wrote:

In our setup, we inject calibration data via yaml-loaded dictionaries as absolute values. If you like, you can easily provide a default calibration file as a fallback if nothing else is specified. Absolute values are definitely to prefer for readability. All the required information will be stored in a single locatio - the yaml file - instead of being distributed across multiple files.

Yes, this was what I was considering as well. The fall back would be the nominal model.

@simonschmeisser wrote:

we have not found a satisfying solution besides recommending people to use high quality robots when they need precision. For our use case (bin-picking) numerical IK-solvers just simply don't work

Could you clarify why numerical solvers "don't work"?

I remember @fmauch presenting about the impressive reduction in difference between the FK performed by robot_state_publisher and the UR TP with his calibration data incorporated into the URDF. I believe that was with either KDL or Trac-IK.

I don't remember the exact nrs, but I'm pretty sure it was < 5 mm.

Which precision are you referring to here?

if not see if you can squeeze the imperfections of your robot into the analytical model (ie check if some numerical optimization of the opw parameters gives a sufficiently small error on you measured data?) This could then be stored as just another opw parameter file (ie yaml) format.

So you're suggesting to not update the nominal OPW parameters with calibrated values?

Is this a UR-specific example + mitigation, or a general comment?


Just for clarification: we're discussing updating the nominal models encoded in the .xacros with the results of kinematic calibration, either provided by the OEM or aftermarket.

@simonschmeisser
Copy link
Contributor

@simonschmeisser wrote:

we have not found a satisfying solution besides recommending people to use high quality robots when they need precision. For our use case (bin-picking) numerical IK-solvers just simply don't work

Could you clarify why numerical solvers "don't work"?

In my tests numerical solvers would always end up in the ms range at best while analytical solvers give you a solution in µs (or tell you there is no solution).

@gavanderhoorn
Copy link
Member

Ok, so this is about performance? You wrote:

we have not found a satisfying solution besides recommending people to use high quality robots when they need precision. For our use case (bin-picking) numerical IK-solvers just simply don't work

which confused me, as it seems to say that precision/accuracy is a problem with numerical solvers.

@simonschmeisser
Copy link
Contributor

sorry for the confusion, of course if you have the time numerical solvers will give you any precision you need (or fail to converge) and give you a lot more liberty in how you load your calibration.

@fmauch
Copy link

fmauch commented Feb 22, 2021

@fmauch: would you perhaps be willing to share why you chose that approach (perhaps because the UR controller doesn't store deltas)? And whether you'd do it again?

Basically, we get the (calibrated) full DH parameters from the robot as per this definition. From this, we create a structure, where we split each link into two chain segments in order to allow virtually "dragging" in the segments along their calibrated axes. This works with the way UR calibrations are stored, as explained here.

As the robot sends its full DH parameters and not an offset from a nominal, this seemed the easiest approach. We cannot use the calibration parameters directly, but have to perform the geometric correction. With this, we end up having a full 6D transformation for each joint. Subtracting a nominal from that would be an extra step and we would have to know the nominal for the robot in question. With using the full definition, we do not have to know the nominal and can save our result directly.

In the end, we went for 6D parameters for each joint used in the urdf directly.

I think, I would go that path again giving the cirumstances we had with the calibration information sent from the robot. If no geometric correction has to be applied to this information, I think I would still go for storing the information that we get from the robot.

I remember @fmauch presenting about the impressive reduction in difference between the FK performed by robot_state_publisher and the UR TP with his calibration data incorporated into the URDF. I believe that was with either KDL or Trac-IK.

Yes, for the FK case we had precisions (in terms if difference to the TP values / internal UR FK) in the sub-micrometer range. Obviously, that would only be the upper boundary of an IK system and in fact we never evaluated an IK system precision as this would be out of scope for the driver work that we did.

@Doomerdinger
Copy link
Contributor Author

@gavanderhoorn wrote:

As to where to store that data, and how to get it into an existing .xacro, there are a few options.

.yaml comes to mind, as it nicely separates the structure from the variable data. It's also easy to generate by external systems, contrary to having to parse and update XML (requires knowledge of the .xacro's structure). It will also be easy for 3rd party parsers, as they won't have to have support for expressions nor for loading .yaml files.

Is this not contrary to your follwing statement/other discussions we've had about this topic? Won't having the values in a .yaml file be more difficult for 3rd party parsers since they would in fact have to support loading .yaml files?

I personally am all for using an external .yaml file, 3rd party parsers being my only apprehension.

@gavanderhoorn
Copy link
Member

That sentence was supposed to be the last sentence of the paragraph below it. I've removed it.

To clarify:

  • use .yaml: separates static structure from per-robot data, well supported by the official xacro parser, not so much by 3rd party ones
  • generate per-robot .xacro: easy on 3rd party parsers, but no separation, proliferation of .xacro files and updates to structure will not be automatically merged with previously generated files (although that could also be an advantage of course)

At the moment I'm still leaning towards the .yaml option.

If necessary, generating a flat .urdf is possible using xacro itself. A 'flat' .xacro would be possible with some simple Python scripting (replacing dictionary refs with the values from the .yaml).

@Doomerdinger
Copy link
Contributor Author

Doomerdinger commented Feb 25, 2021

With some of the new arms I'm putting together for this repository, I'd be happy to make examples of them to see if that's something we like.
.yaml file for nominal values.
The dictionary values are what is passed into the xacro macro itself, not a path to the yaml.
In the default .xacro file (not the macro) it will allow for a yaml file path, using that if provided or the default if not, parsing that and passing it into the macro.

I currently use a format similar to the UR one and use the joint names less the joint prefix as the base keys (1_s, 2_l, 3_u, etc.). It may be better to use the full joint names as specified in the joint_names.yaml file or the default 1,2,3,4,5,6 (with or without the joint_ prefix depending) if no specialized names are specified.

@gavanderhoorn
Copy link
Member

I'd be happy to make examples of them to see if that's something we like.

yes, that would be good.

It would be best to discuss them here in the issue before spending a lot of time on them though. Otherwise you may end up having to 'throw away' some of your work.

I currently use a format similar to the UR one and use the joint names less the joint prefix as the base keys (1_s, 2_l, 3_u, etc.). It may be better to use the full joint names as specified in the joint_names.yaml file or the default 1,2,3,4,5,6 (with or without the joint_ prefix depending) if no specialized names are specified.

I would suggest to use full joint names, as that would be the least ambiguous.

Any advantage gained by shortening them or using abbreviations is immediately lost by the possibility introduced for errors or mistakes -- and eventually increased support requests I believe.

@Doomerdinger
Copy link
Contributor Author

We already have to use calibration offsets internally, so work is getting thrown out one way or another, not very concerned with that.

Full joint names definitely makes more sense. I was blinded the first time I did it.

I'll throw some stuff together, perhaps just include it in the GP180 addition I have?

@gavanderhoorn
Copy link
Member

We already have to use calibration offsets internally, so work is getting thrown out one way or another, not very concerned with that.

I'm not sure I understand.

Are you saying you have a good reason to use offsets instead of absolute values? If so, please describe, as it would be good input to the discussion.

I'll throw some stuff together, perhaps just include it in the GP180 addition I have?

It would be best if we could keep things separated.

I'd not like to bottleneck reviews for new support packages by functionality which is still being designed.

@Doomerdinger
Copy link
Contributor Author

I'm not sure I understand.

Are you saying you have a good reason to use offsets instead of absolute values? If so, please describe, as it would be good input to the discussion.

No I'm sorry. I meant we already have to use calibration (in general) for the motoman arms for our own projects, so I already have an implementation (which happens to be offsets for parity with some older functionality of ours), rework will be required no matter what so that's not a large consideration on my end.

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
enhancement more-info-needed Waiting on additional information from poster
Development

No branches or pull requests

5 participants