Skip to content

Review joint sizes shared between controller and solver #162

Closed
@PeterBowman

Description

@PeterBowman

BasicCartesianControl integrates two distinct members related to the number of controlled joints:

  • numRobotJoints is the number of joints as regarded by the joint controller (e.g. CanBusControlboard). On TEO, this is 7 (6 actuated rotary joints + 1 "fake" gripper joint).
  • numSolverJoints is the number of joints as regarded by the cartesian solver (e.g. KdlSolver). On TEO, this is 6 (the number of non-fixed joints after the kinematic chain is configured).

In the KDL world, the latter is returned by KDL::Chain::getNrOfJoints(). However, it's also important to note that certain solvers work with the number of segments (links), as returned by KDL::Chain::getNrOfSegments().

Since most data travels between API calls inside a container of some sort (std::vector), and its size is not enforced in any way, hard-to-spot errors may arise.

  • At the BasicCartesianControl level, a 7-element vector of external forces is instantiated and initialized here:

    std::vector< std::vector<double> > fexts;
    for (int i = 0; i < numRobotJoints - 1; i++) //-- "numRobotJoints-1" is important
    {
    std::vector<double> fext(6, 0);
    fexts.push_back(fext);
    }
    fexts.push_back(td);

    The first six force vectors (applied on each link) are null/empty, just the seventh one matters and it should be interpreted as a force exerted on the tool's TCP. Note that there are only six joints in the "standard" chain (gripper aside). KDL sees six joints, but eight links (kinematic chain prepended with H0, and HN appended thereafter). Inverse dynamics are performed on said vector (ref). However, the KDL implementation of ID requires to fill a vector of wrenches, built from the initial vector of external forces (esentially, their meaning is the same):

    KDL::Wrenches wrenches(chain.getNrOfSegments(), KDL::Wrench::Zero());
    for (int i = 0; i < fexts.size(); i++)
    {
    wrenches[i] = KDL::Wrench(
    KDL::Vector(fexts[i][0], fexts[i][1], fexts[i][2]),
    KDL::Vector(fexts[i][3], fexts[i][4], fexts[i][5])
    );
    }

    The weird part here is that idsolver.CartToJnt(...) (ref) expects a vector of eight external forces, that is, wrenches.size() == 8. As explained earlier, wrenches[0] should correspond to a force exerted on H0 (fixed joint), and wrenches[7] (in the case described here) to a force exerted on HN (another fixed joint). It becomes apparent that the assignment to wrenches[i] inside the loop (ref) should read wrenches[i+1] instead, size checks aside.

    Note: check how exactly KDL treats external forces. Is fexts[6] applied on the tip of the tool's TCP (probably), or perhaps on the COG of the last link?

  • Compare:

    ...and:

    Assuming that numRobotJoints equals to 7 (see previous point), t[6] now probably points to an unhandled (unassigned, perhaps used by another variable) memory block and trying to access it might result in undefined behavior. In fact, t.at(6) will throw an exception, while t[6] always spits out whatever resides at that location in memory.

    There are several places throughout the code where this is relevant.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions