-
Notifications
You must be signed in to change notification settings - Fork 306
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
More uniform hardware_interface API #45
Comments
I'd like to add that I've been procrastinating writing tests for the hardware_interface package because of this. I wrote one, but never got to writing all others, as the code of each test would end up being an almost exact copy of the other. API differences are enough to disallow writing a single test for them all. When writing tests is inconvenient or difficult, I take that as a sign ;-) |
We went down the exact same path here. But then later scrapped the idea of messing with ros_control directly as it would have broken everything and everyone. But I'd be up for it.. On 06/12/2013 08:48 AM, Adolfo Rodriguez Tsouroukdissian wrote: The different interfaces implemented in the hardware_interface package have a very similar look and feel between them, the main differences being mostly aesthetic, eg. JointStateInterface: getJointNames(), registerJoint(...), getJointStateHandle() Implementations are also very similar, so e55fd29e55fd29 tried to refactor common code to avoid some duplication. Still, I'm not very satisfied with the current situation. I'd like to propose an API-breaking change ( lots of code will break), that would address the code duplication issue and make unit testing much much easier along the way. The idea would be to have something like: // Feel free to propose alternative names typedef ResourceManager JointStateInterface; The main things that changes apart from a uniform API across hardware interfaces is that to register a resource, you must first create a handle object instead of the current practice of providing the requisites to the register[Joint|Actuator|Sensor|Transmission] methods. I don't see a loss in code clarity by going from joint_state_iface.registerJoint(name, pos, vel, eff) to joint_state_iface.registerHandle(handle), but YMMV. Thoughts?. — |
That's really the first test, right? I really like the increased consistency of the proposed API, even if it does break things. That was one of the hurdles I encountered when originally figuring out ros_control. +1 |
@yamokosk I saw you tried something similar in the loadable_Transmissions branch. I also wanted to shy away from an API break with such repercussions, but every time I write a new hardware interface I end up repeating myself, hence this issue...
@jbohren I don't know if I understand the question. It's the first test I write for the hardware_interface package, yes, not the first in ros_control. |
@adolfo-rt Haha, no I mean that the difficulty of writing tests for an API is the first test of an API, like a meta-test. |
@davetcoleman might be interested |
@adolfo-rt It's take me some time, but I think I've come around to the new design for registering handles. I was struggling a bit with the extra step we'll require from users to first create a handle and then register that handle, but there seems to be a common pattern between HardwareInterfaces that themselves contain a number of interfaces to individual joints/actuators/etc. I assume in your example the ResourceManager will inherit from HardwareInterface? |
I agree that the current design is convenient in that you don't have to go through the intermediate step of explicitly creating a handle, but it's only one extra line of code per resource registration. The main thing that blocks harmonizing hardware interfaces is that the signature of the resource registering method is different for every interface. I think the benefits are worth the extra overhead.
Ah, yes. If the general feeling towards the proposal is favorable, I'll go ahead and implement it. |
Another comment concerning the convenience (or not) of having to explicitly create a resource handle. Resources like IMUs, which have many data fields --some of which are optional-- are a mess to add to a hardware interface through a |
I don't have a enough grasp of the code layout to comment on its necessity, it seems to makes sense. We should get this in soon so that we can stabilize the Hydro release. This change does add another layer of complexity to the code base - on a side note, do you think you could make some sort of diagram showing the inheritance layers of the various classes? I'll happily contribute to fixing it up/adding to it, and in fact I'm working on diagramming the data flow aspect of ros_control at the moment. Thanks! |
- Refs ros-controls#45. - HardwareInterface specifics (ie. resource claiming) has been factored out. We now have the non-polymorphic ResourceManager class for registering and getting handles, and the polymorphic HardwareResourceManager that additionally implements the HardwareInterface and takes care of resource claiming. - The above change is required if the transmission interface is to leverage the resource management code, but without the hardware interface specifics. - Move files back to the internal folder. They are building blocks of the public API of hardware interfaces, but should not be directly #included by end users, so it's best they don't share the same location as user-facing headers. - Update unit tests.
- Refs ros-controls#45 and ros-controls#48. - Leverage hardware_interface::internal::ResourceManager to implement TransmissionInterface more compactly and consistently. - Update unit tests.
These pull requests address the issue at hand for ros_control and ros_controllers. User-facing changesIn the pull requests, the public API of the joint, actuator, transmission (and soon sensor) interfaces changes. Consider the EffortJointInterface example: EffortJointInterface iface;
iface.registerHandle(JointHandle(js_handle, &eff_cmd));
// was iface.registerJoint(js_handle, &eff_cmd);
JointHandle h = iface.getHandle("foo");
// was JointHandle h = iface.getJointHandle("foo");
vector<string> names = iface.getNames();
// was vector<string> names = iface.getJointNames(); Other interfaces change in a similar way. Notice that now they all share a similar API, except for the handle type. If you're a ros_control user and don't plan on creating new interfaces, this is all you need to know. Internal changesResource management
Raw data validation
Unit testsThe hardware_interface package now has a complete unit test suite. This is important for a header-only package, because otherwise you need to rely on external code that depends on it to verify if the code compiles (and works as expected). Open questions & TODO
MoreRefer to the pull request commit messages. |
@adolfo-rt Could you update the wiki here https://github.com/willowgarage/ros_control/wiki/hardware_interface? |
@adolfo-rt, in your above example:
You missed changing Maybe this helps others as an example - I just updated the gazebo plugin demo and had to make these changes:
becomes
|
No problem, I'll take care of it today. I was waiting for the merge in case some additional API changes came out during the final review. @davetcoleman Yes, I made a mistake two examples ago. Good catch. The last example explaining the pull request should be good. Also, I'll take a look at the ros_control_gazebo packages sometime between now and early next week. |
fyi I've just started working on a fairly different version of the |
How would you compare the existing implementation with the one you're preparing?. What part of ros_control_gazebo have you found to be limiting generality?. I'm very interested in hearing out the difficulties/limitations others are encountering with ros_control and its surrounding packages (to then make it better, of course). |
This one populates its joints within the hardware interface based on the |
The different interfaces implemented in the hardware_interface package have a very similar look and feel between them, the main differences being mostly aesthetic, eg.
JointStateInterface: getJointNames(), registerJoint(...), getJointStateHandle()
ActuatorCommandInterface: getActuatorNames(), registerActuator(...), getActuatorHandle()
ImuSensorInterface: getSensorNames(), registerSensor(), getSensorHandle()
Implementations are also very similar, so e55fd29 tried to refactor common code to avoid some duplication. Still, I'm not very satisfied with the current situation.
I'd like to propose an API-breaking change ( lots of code will break), that would address the code duplication issue and make unit testing much much easier along the way.
The idea would be to have something like:
The main things that changes apart from a uniform API across hardware interfaces is that to register a resource, you must first create a handle object instead of the current practice of providing the requisites to the
register[Joint|Actuator|Sensor|Transmission]
methods.I don't see a loss in code clarity by going from
joint_state_iface.registerJoint(name, pos, vel, eff)
tojoint_state_iface.registerHandle(handle)
, but YMMV.Thoughts?.
The text was updated successfully, but these errors were encountered: