rdiankov / openrave

Open Robotics Automation Virtual Environment: An environment for testing, developing, and deploying robotics motion planning algorithms.
http://www.openrave.org
Other
684 stars 339 forks source link

better modeling of custom kinematics #135

Closed rdiankov closed 11 years ago

rdiankov commented 11 years ago

Original mail from Franziska Zacharias

It would be nice if the direct kinematics could be added to parts of the robot like the ik plugin, so that a default serial kinematics is used if nothing is specified, but that for parts of the robot a different kinematics is valid. In case of our humanoid, we have an upper body with passive links and the arms and head is a normal serial kinematics. However the mobile plattform is also different.

Is it possible to create/define dependencies between robots? So that i can plug my different robots (Torso, Hands, arms,head,base) together as I need them by just defining who depends on who (e.g. the hand on the motion of the arm). In this case, extending the RobotBase? Class for a non standard forward kinematics would be straight forward, and I would just write new classes for those parts that are not standard kinematics. Else I would have to write a new class each time I plug want to use different parts of the robot. Eg. when using just the mobile base or the just the torso or the whole system.

With the approach you proposed, the above could only be represented by 3 separate robot classes.

Response from Rosen Diankov:

A more appealing option is to define custom xml tags inside your tag that trigger the different parameterizations of your kinematics for different parts of the robot. For example, 'mimic' joints are one way in openrave to get one joint's value be a function of another, and their parameters are defined inside the tag. Similarly, if you can somehow parameterize kinematics dependencies into a tag, then it would be very easy to mix and match different parts of the robot without having to worry about creating separate pieces of c++ code (ie, you can blindly include robot files into each other without worrying about data getting lost).

Here is how we would go about making this happen:

Currently it is possible to attach a custom XML handler to each interface (including kinbody) using the EnvironmentBase::RegisterXMLReader. I would first derive one robot class (check out the collisionmaprobot.h example in the baserobots plugin), and create a custom handler:

penv->RegisterXMLReader(PT_Robot,"jointdependency",MyCreateXMLReaderCallback);

The CollisionMapRobot? has one , and allows multiple tags to be specified. Each takes in two joints and a 2D map defining custom collision behavior. The C++ XMLReader defines a CollisionMapRobot::XMLData structure where to store all this custom data. The data pointer itself is automatically stored inside the robot interface and can always be retrieved with the RobotBase::GetReadableInterface?("collisionmap").

Once all the robot parsing is done, the ComputeJointHierarchy?() gets called in order to perform any extra post-processing on the robot file before it begins to be used. This is where you can start examining what custom dependencies have been read form the XML files, and set the appropriate methods for forward kinematics computation. Then you would use this data to overload the SetJointValues? function (just like CheckSelfCollision? was overloaded in CollisionMapRobot?)

Overall, this method relies only one extra class,

rdiankov commented 11 years ago

simultaneously to using openrave (for path planning) in the last years I also developped my one simulation, mainly only a kinematics viewer for my research. The structure uses the openInventor SceneTree?

Here I have a structure that is as follows :

I have a toplevel RobotComponent? Class which defines the interface for general type robots. (Oriented at the "Component"-Softwaredesign pattern)

Then I derived the Robot-Class and the Composite-Robot Class.

The Robot-Class is just a simple robot made out of elements-of class "link". The CompositeRobotClass? is a robot made out of other robots. I use it e.g. to model our 4 Finger hand or the mobile base, which has 4 individually extendable legs.

To the outside it behaves just like the RobotComponent? Class. The MoveRobot? method just distributes the joints-values to the robots it is composed of.

And the "MoveRobot?" method is where the Kinematics issue comes in. If no tag is specified in the scene file, a standard serial kinematics class is used and registered. If a tag is used, the specific kinematics class is build.

The direct kinematics classes all have the same small interface e.g. GetFrames?4JointValues(...) in which in the subclasses (e.g. four our fingers and torso) everything is hidden.

In some situations the software-design patterns are really useful. Here I decided is again one such point. The direct kinematics is combined with a builder pattern, where I just throw the DirectKinematicTag? from the scene file in and get a DirectKinematics? class of the correct subtype back. But what I see is only the directKinematics class. I handle my inverse kinematics class in the same manner.

Thus I have a robots that are encapsulated structures and know about their own structure. Which I then use for planning and reasoning.

In addition I included a parentRobot Tag, through which I connect robots among each other (which robot depends on who). Additionally a docking frame (homogenous matrix) determines how the dependent robot is offset from its parent

Thus our Humanoid is Build as follows

DEF MobileBase? RvCompositeRobot?{ isBaseMovable TRUE }

DEF Torso RvRobot?{ parentRobot MobileBase?

robotDOF 3

passiveDOF 1 kinematicsType JustinTorsoKin? }

DEF rightArm RvRobot?{

    robotDOF 7
    parentRobot Torso
    inverseKinematicsType JustinRightArm?
    DEF RightArmDockTF Transform{ }
    }

DEF leftArm RvRobot?{

robotDOF 7
parentRobot Torso
inverseKinematicsType JustinLeftArm?
DEF LeftArmDockTF Transform{

    }

}

DEF leftHandII RvCompositeRobot?{

isActive FALSE // for planning
parentRobot leftArm
DEF HandDockTF Transform{

    }

}

DEF rightHandII RvCompositeRobot?{

isActive FALSE
parentRobot rightArm

    DEF HandTF MatrixTransform? {

        }

DEF HandDockTF Transform{

    }

}

DEF TorsoHead? RvRobot?{

    robotDOF 2
    parentRobot Torso

    DEF DockTF Transform{

        }

}

I do not know whether something like this fits with the concepts of openrave, but just as an idea i posted it here.

Perhaps something like this could be integrated via the boost interface. In the BiRRT planner I linked a different sampling function with the path planner using the boost interface.

rdiankov commented 11 years ago

This sounds like a great idea to structure your custom tags. The default openrave structure already defines how links are hooked up to each other, so all you would have to do is create something similar to your structure with OpenInventor?, except it will only include information now specified in openrave, and it will be XML. For example:

<robot>
  <kinbody>
  <!-- fill in regular kinematics -->
  </kinbody>
  <!-- start adding custom tags -->
  <customkinematics parentRobot="MobileBase" robotDOF="3" passiveDOF="1" kinematicsType="JustinTorsoKin">
  </customkinematics>
</robot>

Then when you register your reader, you could read in the customkinematics tag and create your internal structures to do the later kinematics. Once you override the RobotBase::SetJointValues? function, you are free to mimic to OpenInventor?-like structure.

It is possible to do all this all withing your plugin so you do not modify the openrave core. Perhaps after we've had a few iterations of your custom kinematics framework, we can start thinking about what would be useful to put in the openrave core, if you feel it is the right thing to do.

rdiankov commented 11 years ago

Are the tags described above (customkinematics, parentRobot, RobotDOF...) the decided standard for defining custom kinematics? I am about to start re-implementing two of our main research platforms in OpenRAVE due to a major redesign of most of the underlying software and want to minimise the number of hacks that I had in the past - one of which was lots of messy code to handle the kinematics of a 6-link/7 joint arm with only 1-DOF.

Also, I am a bit confused about the use of the term "DOF" throughout openRAVE. Is RobotDOF above = "number of joints" and PassiveDOF = "those joints whose values are dependant on the custom kinematic code" i.e. for my arm RobotDOF=7, PassiveDOF=6?

I have until the new build environment is up and running to complete this task (~2 weeks?) before people start having other development tasks delayed due to a lack of a simulation environment, so if I can write my code to fit into OpenRAVE properly now, I'd rather do that than come up with another hacky solution.

rdiankov commented 11 years ago

the newest versions of openrave (0.7.x+) offer two features to make custom kinematics:

  1. complex equations can be specified for computing the value of one joint with respect to another
  2. A joint can be defined by a timed Trajectory so that the 6D relationship between the connected links is Trajectory.Sample(t). This allows cool stuff like conveyors to be implemented.

i think this should cover all requirements for this feature.