From 313146af05760662128138390dc90af0c1ff7156 Mon Sep 17 00:00:00 2001 From: Rohan Budhiraja <budhiraja@laas.fr> Date: Fri, 8 Apr 2016 20:34:34 +0200 Subject: [PATCH] [cpp] change joint-limits to model class + temporary fix for specificities --- include/sot-dynamic/dynamic.h | 40 ++- src/dynamic-command.h | 23 ++ .../sot/dynamics/humanoid_robot.py | 118 ++++--- src/sot-dynamic.cpp | 322 +++++++++++------- unitTesting/test_config.cpp | 2 + unitTesting/two_link.urdf | 47 +-- 6 files changed, 314 insertions(+), 238 deletions(-) diff --git a/include/sot-dynamic/dynamic.h b/include/sot-dynamic/dynamic.h index 85e9b53..eeb247f 100644 --- a/include/sot-dynamic/dynamic.h +++ b/include/sot-dynamic/dynamic.h @@ -49,6 +49,7 @@ #include <pinocchio/multibody/parser/urdf.hpp> #include <pinocchio/algorithm/rnea.hpp> #include <pinocchio/algorithm/jacobian.hpp> +#include <pinocchio/algorithm/operational-frames.hpp> /* --------------------------------------------------------------------- */ /* --- API ------------------------------------------------------------- */ @@ -173,24 +174,23 @@ class SOTDYNAMIC_EXPORT Dynamic /* --- MODEL CREATION --- */ - /// \brief parse a urdf file to create robot model + /// \brief sets a urdf filepath to create robot model. Call parseUrdfFile to parse /// \param path file location. /// - /// \note creates a pinocchio model. needs urdfdom libraries to parse. void setUrdfFile( const std::string& path ); - //TODO: - // void parseAndAddFrames(se3::Model& pinocchio_model, - // const std::string& filename); - - /// \name Construction of a robot by commands - ///@{ + /// \brief parses a urdf filepath to create robot model. Call setUrdfFile to give path + /// \param none. /// + /// \note creates a pinocchio model. needs urdfdom libraries to parse. + void parseUrdfFile(void); + /// \brief Create an empty device void createRobot(); - void displayModel(){ std::cout<<m_model<<std::endl; }; + void displayModel() const + { std::cout<<m_model<<std::endl; }; /// \brief create a joint /// \param inJointName name of the joint, @@ -336,11 +336,19 @@ class SOTDYNAMIC_EXPORT Dynamic /// \return result vector dg::Vector& getMaxEffortLimits(dg::Vector& res,const int&); - - protected: - dg::Matrix& computeGenericJacobian(int jointId,dg::Matrix& res,int time ); - dg::Matrix& computeGenericEndeffJacobian(int jointId,dg::Matrix& res,int time ); - MatrixHomogeneous& computeGenericPosition(int jointId,MatrixHomogeneous& res,int time ); + + // dg::Vector& getAnklePositionInFootFrame() const; + + protected: + dg::Matrix& computeGenericJacobian(bool isFrame, + int jointId, + dg::Matrix& res,int time ); + dg::Matrix& computeGenericEndeffJacobian(bool isFrame, + int jointId, + dg::Matrix& res,int time ); + MatrixHomogeneous& computeGenericPosition(bool isFrame, + int jointId, + MatrixHomogeneous& res,int time ); dg::Vector& computeGenericVelocity(int jointId,dg::Vector& res,int time ); dg::Vector& computeGenericAcceleration(int jointId,dg::Vector& res,int time ); @@ -371,12 +379,12 @@ class SOTDYNAMIC_EXPORT Dynamic dg::Vector getPinocchioVel(int); dg::Vector getPinocchioAcc(int); - typedef std::pair<std::string,dg::Matrix> JointDetails; + typedef std::pair<std::string,Eigen::Matrix4d> JointDetails; std::map<std::string, JointDetails> jointMap_; std::vector<std::string> jointTypes; - std::map<std::string,std::string> specificitiesMap; + //std::map<std::string,std::string> specificitiesMap; }; diff --git a/src/dynamic-command.h b/src/dynamic-command.h index bd4b4fe..c8668dd 100644 --- a/src/dynamic-command.h +++ b/src/dynamic-command.h @@ -55,6 +55,29 @@ namespace dynamicgraph { namespace sot { } }; // class SetFiles + // Command Parse + class Parse : public Command + { + public: + virtual ~Parse() {} + /// Create command and store it in Entity + /// \param entity instance of Entity owning this command + /// \param docstring documentation of the command + Parse(Dynamic& entity, const std::string& docstring) : + Command(entity, std::vector<Value::Type>(), docstring) + { + } + virtual Value doExecute() + { + Dynamic& robot = static_cast<Dynamic&>(owner()); + if(! robot.init ) robot.parseUrdfFile(); + else std::cout << " !! Already parsed." << std::endl; + // return void + return Value(); + } + }; // class Parse + + // Command CreateRobot class CreateRobot : public Command { diff --git a/src/dynamic_graph/sot/dynamics/humanoid_robot.py b/src/dynamic_graph/sot/dynamics/humanoid_robot.py index 7a56201..a565072 100755 --- a/src/dynamic_graph/sot/dynamics/humanoid_robot.py +++ b/src/dynamic_graph/sot/dynamics/humanoid_robot.py @@ -47,6 +47,10 @@ class AbstractHumanoidRobot (object): - rightAnkle, - Gaze. + Operational points are mapped to the actual joints in the robot model + via 'OperationalPointsMap' dictionary. + This attribute *must* be defined in the subclasses + Other attributes require to be defined: - halfSitting: half-sitting position is the robot initial pose. This attribute *must* be defined in subclasses. @@ -65,6 +69,8 @@ class AbstractHumanoidRobot (object): OperationalPoints = ['left-wrist', 'right-wrist', 'left-ankle', 'right-ankle', 'gaze'] + + """ Operational points are specific interesting points of the robot used to control it. @@ -91,7 +97,6 @@ class AbstractHumanoidRobot (object): """ - frames = dict() """ Additional frames defined by using OpPointModifier. @@ -163,51 +168,48 @@ class AbstractHumanoidRobot (object): self.setProperties(model) return model - def loadModelFromJrlDynamics(self, name, modelDir, modelName, - specificitiesPath, jointRankPath, - dynamicType): + def loadModelFromUrdf(self, name, urdfPath, + dynamicType): """ - Load a model using the jrl-dynamics parser. This parser looks - for VRML files in which kinematics and dynamics information - have been added by extending the VRML format. - - It is mainly used by OpenHRP. + Load a model using the pinocchio urdf parser. This parser looks + for urdf files in which kinematics and dynamics information + have been added. Additional information are located in two different XML files. """ model = dynamicType(name) - self.setProperties(model) - model.setFiles(modelDir, modelName, - specificitiesPath, jointRankPath) + #TODO: setproperty flags in sot-pinocchio + #self.setProperties(model) + model.setFile(urdfPath) model.parse() return model - def setProperties(self, model): - model.setProperty('TimeStep', str(self.timeStep)) - - model.setProperty('ComputeAcceleration', 'false') - model.setProperty('ComputeAccelerationCoM', 'false') - model.setProperty('ComputeBackwardDynamics', 'false') - model.setProperty('ComputeCoM', 'false') - model.setProperty('ComputeMomentum', 'false') - model.setProperty('ComputeSkewCom', 'false') - model.setProperty('ComputeVelocity', 'false') - model.setProperty('ComputeZMP', 'false') - - model.setProperty('ComputeAccelerationCoM', 'true') - model.setProperty('ComputeCoM', 'true') - model.setProperty('ComputeVelocity', 'true') - model.setProperty('ComputeZMP', 'true') - - if self.enableZmpComputation: - model.setProperty('ComputeBackwardDynamics', 'true') - model.setProperty('ComputeAcceleration', 'true') - model.setProperty('ComputeMomentum', 'true') + #TODO: put these flags in sot-pinocchio + #def setProperties(self, model): + # model.setProperty('TimeStep', str(self.timeStep)) + # + # model.setProperty('ComputeAcceleration', 'false') + # model.setProperty('ComputeAccelerationCoM', 'false') + # model.setProperty('ComputeBackwardDynamics', 'false') + # model.setProperty('ComputeCoM', 'false') + # model.setProperty('ComputeMomentum', 'false') + # model.setProperty('ComputeSkewCom', 'false') + # model.setProperty('ComputeVelocity', 'false') + # model.setProperty('ComputeZMP', 'false') + # model.setProperty('ComputeAccelerationCoM', 'true') + # model.setProperty('ComputeCoM', 'true') + # model.setProperty('ComputeVelocity', 'true') + # model.setProperty('ComputeZMP', 'true') + # + # if self.enableZmpComputation: + # model.setProperty('ComputeBackwardDynamics', 'true') + # model.setProperty('ComputeAcceleration', 'true') + # model.setProperty('ComputeMomentum', 'true') def initializeOpPoints(self, model): for op in self.OperationalPoints: - model.createOpPoint(op, op) + model.createOpPoint(self.OperationalPointsMap[op], self.OperationalPointsMap[op]) def createFrame(self, frameName, transformation, operationalPoint): frame = OpPointModifier(frameName) @@ -263,27 +265,27 @@ class AbstractHumanoidRobot (object): self.initializeOpPoints(self.dynamic) - # --- additional frames --- - self.frames = dict() - frameName = 'rightHand' - self.frames [frameName] = self.createFrame ( - "{0}_{1}".format (self.name, frameName), - self.dynamic.getHandParameter (True), "right-wrist") + #TODO: hand parameters through srdf --- additional frames --- + #self.frames = dict() + #frameName = 'rightHand' + #self.frames [frameName] = self.createFrame ( + # "{0}_{1}".format (self.name, frameName), + # self.dynamic.getHandParameter (True), "right-wrist") # rightGripper is an alias for the rightHand: - self.frames ['rightGripper'] = self.frames [frameName] + #self.frames ['rightGripper'] = self.frames [frameName] - frameName = 'leftHand' - self.frames [frameName] = self.createFrame ( - "{0}_{1}".format (self.name, frameName), - self.dynamic.getHandParameter (False), "left-wrist") + #frameName = 'leftHand' + #self.frames [frameName] = self.createFrame ( + # "{0}_{1}".format (self.name, frameName), + # self.dynamic.getHandParameter (False), "left-wrist") # leftGripper is an alias for the leftHand: - self.frames ["leftGripper"] = self.frames [frameName] + #self.frames ["leftGripper"] = self.frames [frameName] - for (frameName, transformation, signalName) in self.AdditionalFrames: - self.frames[frameName] = self.createFrame( - "{0}_{1}".format(self.name, frameName), - transformation, - signalName) + #for (frameName, transformation, signalName) in self.AdditionalFrames: + # self.frames[frameName] = self.createFrame( + # "{0}_{1}".format(self.name, frameName), + # transformation, + # signalName) def addTrace(self, entityName, signalName): if self.tracer: @@ -371,21 +373,25 @@ class AbstractHumanoidRobot (object): self.dynamic.Jcom.recompute(self.device.state.time+1) for op in self.OperationalPoints: - self.dynamic.signal(op).recompute(self.device.state.time+1) - self.dynamic.signal('J'+op).recompute(self.device.state.time+1) + self.dynamic.signal(self.OperationalPointsMap[op]).recompute(self.device.state.time+1) + self.dynamic.signal('J'+self.OperationalPointsMap[op]).recompute(self.device.state.time+1) class HumanoidRobot(AbstractHumanoidRobot): halfSitting = [] #FIXME - + name = None filename = None def __init__(self, name, filename, tracer = None): AbstractHumanoidRobot.__init__(self, name, tracer) self.filename = filename - self.dynamic = \ - self.loadModelFromKxml (self.name + '_dynamics', self.filename) + self.OperationalPointsMap ={'left-wrist' : 'left-wrist', + 'right-wrist' : 'right-wrist', + 'left-ankle' : 'left-ankle', + 'right-ankle' : 'right-ankle', + 'gaze' : 'gaze'} + self.dynamic = self.loadModelFromKxml (self.name + '_dynamics', self.filename) self.dimension = self.dynamic.getDimension() self.halfSitting = self.dimension*(0.,) self.initializeRobot() diff --git a/src/sot-dynamic.cpp b/src/sot-dynamic.cpp index e1bfd9a..c6fc097 100644 --- a/src/sot-dynamic.cpp +++ b/src/sot-dynamic.cpp @@ -17,7 +17,6 @@ * have received a copy of the GNU Lesser General Public License along * with sot-dynamic. If not, see <http://www.gnu.org/licenses/>. */ -#include <limits> #include <sot/core/debug.hh> #include <sot-dynamic/dynamic.h> @@ -27,7 +26,6 @@ #include <boost/format.hpp> #include <pinocchio/algorithm/kinematics.hpp> -#include <pinocchio/algorithm/joint-limits.hpp> #include <pinocchio/algorithm/center-of-mass.hpp> #include <pinocchio/spatial/motion.hpp> #include <pinocchio/algorithm/crba.hpp> @@ -47,7 +45,7 @@ Dynamic( const std::string & name) :Entity(name) ,m_model() ,m_data(NULL) - ,m_urdfPath() + ,m_urdfPath("") ,init(false) @@ -128,18 +126,18 @@ Dynamic( const std::string & name) jointTypes.push_back("JointModelTranslation"); - //TODO: wrist and ankle have different roll-pitch-yaw frames. Confirm which? + + //TODO: gaze_joint is fixed joint: not one of pinocchio joint types. Confirm specificities joint. /* - specificitiesMap["right-wrist"] = "RWristRoll"; - specificitiesMap["left-wrist"] = "RWristRoll"; - specificitiesMap["right-ankle"] = "RWristRoll"; - specificitiesMap["left-ankle"] = "RWristRoll"; - specificitiesMap["gaze"] = ""; - specificitiesMap["waist"] = ""; - specificitiesMap["chest"] = ""; + specificitiesMap["right-wrist"] = "RWristPitch"; + specificitiesMap["left-wrist"] = "LWristPitch"; + specificitiesMap["right-ankle"] = "LAnkleRoll"; + specificitiesMap["left-ankle"] = "RAnkleRoll"; + specificitiesMap["gaze"] = "HeadRoll"; + specificitiesMap["waist"] = "waist"; + specificitiesMap["chest"] = "TrunkYaw"; */ - //TODO------------------------------------------- //if( build ) buildModel(); @@ -184,6 +182,16 @@ Dynamic( const std::string & name) addCommand("setFile", new command::SetFile(*this, docstring)); + docstring = + "\n" + " Parse files in order to build the robot.\n" + "\n" + " Input:\n" + " - none \n" + "\n"; + addCommand("parse", + new command::Parse(*this, docstring)); + docstring = "\n" " Display the current robot configuration.\n" @@ -243,7 +251,7 @@ Dynamic( const std::string & name) addCommand("createJoint", new command::CreateJoint(*this, docstring)); docstring = " \n" - " Add a child joint\n" + " Add a child Body\n" " \n" " Input:\n" " - a string: name of the parent body,\n" @@ -273,15 +281,25 @@ Dynamic( const std::string & name) addCommand("getDimension", new command::GetDimension(*this, docstring)); - docstring = " \n" - " Write the robot kinematic chain in a file.\n" - " \n" - " Input:\n" - " a string: a filename.\n" - " \n"; - addCommand("write", - new command::Write(*this, docstring)); - //TODO: add specifities commands + docstring = " \n" + " Write the robot kinematic chain in a file.\n" + " \n" + " Input:\n" + " a string: a filename.\n" + " \n"; + addCommand("write", + new command::Write(*this, docstring)); + //TODO: add specifities commands + + /* + docstring = " \n" + " Get ankle position in left foot frame.\n" + " \n"; + addCommand("getAnklePositionInFootFrame", + new dynamicgraph::command::Getter<Dynamic, dynamicgraph::Vector> + (*this, &Dynamic::getAnklePositionInFootFrame, docstring)); + + */ docstring = " \n" " Set the position of the center of mass of a body\n" " \n" @@ -384,26 +402,35 @@ Dynamic::~Dynamic( void ) { //Import from urdf file void Dynamic::setUrdfFile(const std::string& filename) { sotDEBUGIN(15); - // m_model = new se3::Model(); - m_model = se3::urdf::buildModel(filename); - this->m_urdfPath = filename; + m_urdfPath = filename; + sotDEBUG(15)<<"Urdf file path: "<<m_urdfPath<<std::endl; + sotDEBUGOUT(15); +} + +void Dynamic::parseUrdfFile() { + sotDEBUGIN(15); + if (m_urdfPath.empty()) std::cerr<<"Set input file first"<<std::endl; + m_model = se3::urdf::buildModel(this->m_urdfPath, false); if (m_data) delete m_data; m_data = new se3::Data(m_model); - se3::jointLimits(m_model, *m_data, Eigen::VectorXd::Zero(m_model.nq)); init=true; + std::vector<se3::Frame>::const_iterator it = m_model.operational_frames.begin(); + for(;it!=m_model.operational_frames.end();it++) + sotDEBUG(15)<<"Operational Frames Added: "<<it->name<<std::endl; + sotDEBUG(15)<<m_model<<std::endl; + displayModel(); sotDEBUGOUT(15); } + //Create an empty robot void Dynamic::createRobot() { sotDEBUGIN(15); - // if (m_model) { - //m_model.~Model(); - delete m_data; - //} + delete m_data; m_model= se3::Model(); m_data = new se3::Data(m_model); + init=true; sotDEBUGOUT(15); } @@ -422,7 +449,8 @@ void Dynamic::createJoint(const std::string& inJointName, " already exists in the model."); if(std::find(jointTypes.begin(),jointTypes.end(),inJointType) != jointTypes.end()) { - JointDetails jointDetails(inJointType,inPosition); + Eigen::Matrix4d inposition_ = inPosition; + JointDetails jointDetails(inJointType,inposition_); jointMap_[inJointName] = jointDetails; } else { @@ -444,7 +472,6 @@ void Dynamic::addBody(const std::string& inParentName, sotDEBUGOUT(15); } - void Dynamic::addBody(const std::string& inParentName, const std::string& inJointName, const std::string& inChildName, @@ -512,7 +539,6 @@ void Dynamic::addBody(const std::string& inParentName, if(m_data) delete m_data; m_data = new se3::Data(m_model); - se3::jointLimits(m_model, *m_data, Eigen::VectorXd::Zero(m_model.nq)); sotDEBUGOUT(15); } @@ -580,11 +606,12 @@ void Dynamic::setDofBounds(const std::string& inJointName, "No joint with name " + inJointName + " has been created."); se3::Model::Index joint_index = m_model.getJointId(inJointName); - //TODO: Only change in data->vector. No change in the joint model class. Potential bug int prev_cumulative_nq = se3::idx_q(m_model.joints[joint_index]); + assert(se3::nq(m_model.joints[joint_index]) > inDofId); - m_data->lowerPositionLimit(prev_cumulative_nq+inDofId) = inMinValue; - m_data->upperPositionLimit(prev_cumulative_nq+inDofId) = inMaxValue; + + m_model.lowerPositionLimit(prev_cumulative_nq+inDofId) = inMinValue; + m_model.upperPositionLimit(prev_cumulative_nq+inDofId) = inMaxValue; sotDEBUGOUT(15); return; } @@ -598,9 +625,8 @@ void Dynamic::setLowerPositionLimit(const std::string& inJointName, se3::Model::Index joint_index = m_model.getJointId(inJointName); int prev_cumulative_nq = se3::idx_q(m_model.joints[joint_index]); - //TODO: Only change in data->vector. No change in the joint model class. Potential bug assert (se3::nq(m_model.joints[joint_index])==1 && "Joint is not revolute"); - m_data->lowerPositionLimit(prev_cumulative_nq) = lowPos; + m_model.lowerPositionLimit(prev_cumulative_nq) = lowPos; return; } @@ -613,9 +639,8 @@ void Dynamic::setLowerPositionLimit(const std::string& inJointName, se3::Model::Index joint_index = m_model.getJointId(inJointName); int prev_cumulative_nq = se3::idx_q(m_model.joints[joint_index]); int current_nq = se3::nq(m_model.joints[joint_index]); - //TODO: Only change in data->vector. No change in the joint model class. Potential bug assert (lowPos.size()==current_nq); - m_data->lowerPositionLimit.segment(prev_cumulative_nq,current_nq) = lowPos; + m_model.lowerPositionLimit.segment(prev_cumulative_nq,current_nq) = lowPos; return; } @@ -628,9 +653,8 @@ void Dynamic::setUpperPositionLimit(const std::string& inJointName, " has been created."); se3::Model::Index joint_index = m_model.getJointId(inJointName); int prev_cumulative_nq = se3::idx_q(m_model.joints[joint_index]); - //TODO: Only change in data->vector. No change in the joint model class. Potential bug assert (se3::nq(m_model.joints[joint_index])==1 && "Joint is not revolute"); - m_data->upperPositionLimit(prev_cumulative_nq) = upPos; + m_model.upperPositionLimit(prev_cumulative_nq) = upPos; return; } @@ -645,8 +669,7 @@ void Dynamic::setUpperPositionLimit(const std::string& inJointName, int current_nq = se3::nq(m_model.joints[joint_index]); assert (upPos.size()==current_nq); - //TODO: Only change in data->vector. No change in the joint model class. Potential bug - m_data->upperPositionLimit.segment(prev_cumulative_nq,current_nq) = upPos; + m_model.upperPositionLimit.segment(prev_cumulative_nq,current_nq) = upPos; return; } @@ -660,8 +683,7 @@ void Dynamic::setMaxVelocityLimit(const std::string& inJointName, int prev_cumulative_nv = se3::idx_v(m_model.joints[joint_index]); assert (se3::nv(m_model.joints[joint_index])==1 && "Joint is not revolute"); - //TODO: Only change in data->vector. No change in the joint model class. Potential bug - m_data->velocityLimit(prev_cumulative_nv) = maxVel; + m_model.velocityLimit(prev_cumulative_nv) = maxVel; return; } @@ -674,9 +696,8 @@ void Dynamic::setMaxVelocityLimit(const std::string& inJointName, se3::Model::Index joint_index = m_model.getJointId(inJointName); int prev_cumulative_nv = se3::idx_v(m_model.joints[joint_index]); int current_nv = se3::nv(m_model.joints[joint_index]); - //TODO: Only change in data->vector. No change in the joint model class. Potential bug assert (maxVel.size()==current_nv); - m_data->velocityLimit.segment(prev_cumulative_nv,current_nv) = maxVel; + m_model.velocityLimit.segment(prev_cumulative_nv,current_nv) = maxVel; return; } @@ -690,9 +711,8 @@ void Dynamic::setMaxEffortLimit(const std::string& inJointName, " has been created."); se3::Model::Index joint_index = m_model.getJointId(inJointName); int prev_cumulative_nv = se3::idx_v(m_model.joints[joint_index]); - //TODO: Only change in data->vector. No change in the joint model class. Potential bug assert (se3::nv(m_model.joints[joint_index])==1 && "Joint is not revolute"); - m_data->effortLimit(prev_cumulative_nv) = maxEffort; + m_model.effortLimit(prev_cumulative_nv) = maxEffort; return; } @@ -706,9 +726,8 @@ void Dynamic::setMaxEffortLimit(const std::string& inJointName, se3::Model::Index joint_index = m_model.getJointId(inJointName); int prev_cumulative_nv = se3::idx_v(m_model.joints[joint_index]); int current_nv = se3::nv(m_model.joints[joint_index]); - //TODO: Only change in data->vector. No change in the joint model class. Potential bug assert (maxEffort.size()==current_nv); - m_data->effortLimit.segment(prev_cumulative_nv,current_nv) = maxEffort; + m_model.effortLimit.segment(prev_cumulative_nv,current_nv) = maxEffort; return; } @@ -721,7 +740,7 @@ getLowerPositionLimits(dg::Vector& res, const int&) sotDEBUGIN(15); res.resize(m_model.nq); - res = m_data->lowerPositionLimit; + res = m_model.lowerPositionLimit; sotDEBUG(15) << "lowerLimit (" << res << ")=" << std::endl; sotDEBUGOUT(15); return res; @@ -732,7 +751,7 @@ getUpperPositionLimits(dg::Vector& res, const int&) { sotDEBUGIN(15); res.resize(m_model.nq); - res = m_data->upperPositionLimit; + res = m_model.upperPositionLimit; sotDEBUG(15) << "upperLimit (" << res << ")=" <<std::endl; sotDEBUGOUT(15); return res; @@ -743,7 +762,7 @@ getUpperVelocityLimits(dg::Vector& res, const int&) { sotDEBUGIN(15); res.resize(m_model.nv); - res = m_data->velocityLimit; + res = m_model.velocityLimit; sotDEBUG(15) << "upperVelocityLimit (" << res << ")=" <<std::endl; sotDEBUGOUT(15); return res; @@ -754,11 +773,30 @@ getMaxEffortLimits(dg::Vector& res, const int&) { sotDEBUGIN(15); res.resize(m_model.nv); - res = m_data->effortLimit; + res = m_model.effortLimit; sotDEBUGOUT(15); return res; } + +//TODO: To be set via srdf file +/*dynamicgraph::Vector Dynamic::getAnklePositionInFootFrame() const +{ + if (!m_data) { + SOT_THROW ExceptionDynamic(ExceptionDynamic::GENERIC, + "you must create a robot first."); + } + + dg::Vector anklePosition(3); + foot->getAnklePositionInLocalFrame(anklePosition); + dynamicgraph::Vector res(3); + res(0) = anklePosition[0]; + res(1) = anklePosition[1]; + res(2) = anklePosition[2]; + return res; +} +*/ + /* ---------------- INTERNAL ------------------------------------------------ */ dg::Vector Dynamic::getPinocchioPos(int time) { @@ -821,16 +859,28 @@ Eigen::VectorXd Dynamic::getPinocchioAcc(int time) dg::SignalTimeDependent< dg::Matrix,int > & Dynamic:: createJacobianSignal( const std::string& signame, const std::string& jointName ) { - int jointId = m_model.getJointId(jointName); - - dg::SignalTimeDependent< dg::Matrix,int > * sig - = new dg::SignalTimeDependent< dg::Matrix,int > - ( boost::bind(&Dynamic::computeGenericJacobian,this,jointId,_1,_2), - newtonEulerSINTERN, - "sotDynamic("+name+")::output(matrix)::"+signame ); + sotDEBUGIN(15); + dg::SignalTimeDependent< dg::Matrix,int > * sig; + if(m_model.existFrame(jointName)) { + int frameId = m_model.getFrameId(jointName); + sig = new dg::SignalTimeDependent< dg::Matrix,int > + ( boost::bind(&Dynamic::computeGenericJacobian,this,true,frameId,_1,_2), + newtonEulerSINTERN, + "sotDynamic("+name+")::output(matrix)::"+signame ); + } + else if(m_model.existJointName(jointName)) { + int jointId = m_model.getJointId(jointName); + sig = new dg::SignalTimeDependent< dg::Matrix,int > + ( boost::bind(&Dynamic::computeGenericJacobian,this,false,jointId,_1,_2), + newtonEulerSINTERN, + "sotDynamic("+name+")::output(matrix)::"+signame ); + } + else SOT_THROW ExceptionDynamic(ExceptionDynamic::GENERIC, + "Robot has no joint corresponding to " + jointName); genericSignalRefs.push_back( sig ); signalRegistration( *sig ); + sotDEBUGOUT(15); return *sig; } @@ -838,16 +888,25 @@ dg::SignalTimeDependent< dg::Matrix,int > & Dynamic:: createEndeffJacobianSignal( const std::string& signame, const std::string& jointName ) { sotDEBUGIN(15); - int jointId = m_model.getJointId(jointName); - dg::SignalTimeDependent< dg::Matrix,int > * sig - = new dg::SignalTimeDependent< dg::Matrix,int > - ( boost::bind(&Dynamic::computeGenericEndeffJacobian,this,jointId,_1,_2), - newtonEulerSINTERN, - "sotDynamic("+name+")::output(matrix)::"+signame ); - + dg::SignalTimeDependent< dg::Matrix,int > * sig; + if(m_model.existFrame(jointName)) { + int frameId = m_model.getFrameId(jointName); + sig = new dg::SignalTimeDependent< dg::Matrix,int > + ( boost::bind(&Dynamic::computeGenericEndeffJacobian,this,true,frameId,_1,_2), + newtonEulerSINTERN, + "sotDynamic("+name+")::output(matrix)::"+signame ); + } + else if(m_model.existJointName(jointName)) { + int jointId = m_model.getJointId(jointName); + sig = new dg::SignalTimeDependent< dg::Matrix,int > + ( boost::bind(&Dynamic::computeGenericEndeffJacobian,this,false,jointId,_1,_2), + newtonEulerSINTERN, + "sotDynamic("+name+")::output(matrix)::"+signame ); + } + else SOT_THROW ExceptionDynamic(ExceptionDynamic::GENERIC, + "Robot has no joint corresponding to " + jointName); genericSignalRefs.push_back( sig ); signalRegistration( *sig ); - sotDEBUGOUT(15); return *sig; } @@ -856,15 +915,26 @@ dg::SignalTimeDependent< MatrixHomogeneous,int >& Dynamic:: createPositionSignal( const std::string& signame, const std::string& jointName) { sotDEBUGIN(15); - int jointId = m_model.getJointId(jointName); - dg::SignalTimeDependent< MatrixHomogeneous,int > * sig - = new dg::SignalTimeDependent< MatrixHomogeneous,int > - ( boost::bind(&Dynamic::computeGenericPosition,this,jointId,_1,_2), - newtonEulerSINTERN, - "sotDynamic("+name+")::output(matrixHomo)::"+signame ); + dg::SignalTimeDependent< MatrixHomogeneous,int > * sig; + if(m_model.existFrame(jointName)) { + int frameId = m_model.getFrameId(jointName); + sig = new dg::SignalTimeDependent< MatrixHomogeneous,int > + ( boost::bind(&Dynamic::computeGenericPosition,this,true,frameId,_1,_2), + newtonEulerSINTERN, + "sotDynamic("+name+")::output(matrixHomo)::"+signame ); + } + else if(m_model.existJointName(jointName)) { + int jointId = m_model.getJointId(jointName); + sig = new dg::SignalTimeDependent< MatrixHomogeneous,int > + ( boost::bind(&Dynamic::computeGenericPosition,this,false,jointId,_1,_2), + newtonEulerSINTERN, + "sotDynamic("+name+")::output(matrixHomo)::"+signame ); + } + else SOT_THROW ExceptionDynamic(ExceptionDynamic::GENERIC, + "Robot has no joint corresponding to " + jointName); + genericSignalRefs.push_back( sig ); signalRegistration( *sig ); - sotDEBUGOUT(15); return *sig; } @@ -1034,9 +1104,9 @@ dg::Vector& Dynamic::computeZmp( dg::Vector& res,int time ) return res; } -//In world frame +//In world coordinates dg::Matrix& Dynamic:: -computeGenericJacobian( int jointId,dg::Matrix& res,int time ) +computeGenericJacobian(bool isFrame, int jointId, dg::Matrix& res,int time ) { sotDEBUGIN(25); newtonEulerSINTERN(time); @@ -1044,25 +1114,32 @@ computeGenericJacobian( int jointId,dg::Matrix& res,int time ) se3::computeJacobians(m_model,*m_data,this->getPinocchioPos(time)); se3::Data::Matrix6x m_output = Eigen::MatrixXd::Zero(6,m_model.nv); - //Computes Jacobian in world frame. - se3::getJacobian<false>(m_model,*m_data,(se3::Model::Index)jointId,m_output); - + //Computes Jacobian in world coordinates. + if(isFrame){ + se3::framesForwardKinematics(m_model,*m_data); + se3::getFrameJacobian<false>(m_model,*m_data,(se3::Model::Index)jointId,m_output); + } + else se3::getJacobian<false>(m_model,*m_data,(se3::Model::Index)jointId,m_output); res = m_output; sotDEBUGOUT(25); return res; } dg::Matrix& Dynamic:: -computeGenericEndeffJacobian( int jointId,dg::Matrix& res,int time ) +computeGenericEndeffJacobian(bool isFrame, int jointId,dg::Matrix& res,int time ) { sotDEBUGIN(25); newtonEulerSINTERN(time); res.resize(6,m_model.nv); - //In local Frame. + //In local coordinates. se3::computeJacobians(m_model,*m_data,this->getPinocchioPos(time)); - se3::Data::Matrix6x m_output = Eigen::MatrixXd::Zero(6,m_model.nv); - se3::getJacobian<true>(m_model,*m_data,(se3::Model::Index)jointId,m_output); + + if(isFrame){ + se3::framesForwardKinematics(m_model,*m_data); + se3::getFrameJacobian<true>(m_model,*m_data,(se3::Model::Index)jointId,m_output); + } + else se3::getJacobian<true>(m_model,*m_data,(se3::Model::Index)jointId,m_output); res = m_output; sotDEBUGOUT(25); @@ -1071,18 +1148,25 @@ computeGenericEndeffJacobian( int jointId,dg::Matrix& res,int time ) } MatrixHomogeneous& Dynamic:: -computeGenericPosition( int jointId, MatrixHomogeneous& res, int time) +computeGenericPosition(bool isFrame, int jointId, MatrixHomogeneous& res, int time) { sotDEBUGIN(25); newtonEulerSINTERN(time); - res.matrix()= m_data->oMi[jointId].toHomogeneousMatrix(); + + if(isFrame){ + //TODO: Confirm if we need this. Already being called when calculating jacobian + //se3::framesForwardKinematics(m_model,*m_data); + res.matrix()= m_data->oMof[jointId].toHomogeneousMatrix(); + } + else res.matrix()= m_data->oMi[jointId].toHomogeneousMatrix(); + + sotDEBUGOUT(25); return res; } dg::Vector& Dynamic:: computeGenericVelocity( int jointId, dg::Vector& res,int time ) { - sotDEBUGIN(25); newtonEulerSINTERN(time); res.resize(6); @@ -1321,7 +1405,7 @@ commandLine( const std::string& cmdLine, displayModel(); } else if( cmdLine == "parse" ) { - if(!init) std::cout << "No file parsed, run command setFile" << std::endl; + if(!init) parseUrdfFile(); else std::cout << " !! Already parsed." <<std::endl; } else if( cmdLine == "displayFile" ) { @@ -1398,6 +1482,28 @@ commandLine( const std::string& cmdLine, << " - {create|destroy}Position\t:handle position signals." <<std::endl << " - {create|destroy}OpPoint\t:handle Operation Point (ie pos+jac) signals." <<std::endl << " - {create|destroy}Acceleration\t:handle acceleration signals." <<std::endl + /*TODO: Put these flags for computations (copied from humanoid_robot.py): + def setProperties(self, model): + model.setProperty('TimeStep', str(self.timeStep)) + model.setProperty('ComputeAcceleration', 'false') + model.setProperty('ComputeAccelerationCoM', 'false') + model.setProperty('ComputeBackwardDynamics', 'false') + model.setProperty('ComputeCoM', 'false') + model.setProperty('ComputeMomentum', 'false') + model.setProperty('ComputeSkewCom', 'false') + model.setProperty('ComputeVelocity', 'false') + model.setProperty('ComputeZMP', 'false') + + model.setProperty('ComputeAccelerationCoM', 'true') + model.setProperty('ComputeCoM', 'true') + model.setProperty('ComputeVelocity', 'true') + model.setProperty('ComputeZMP', 'true') + + if self.enableZmpComputation: + model.setProperty('ComputeBackwardDynamics', 'true') + model.setProperty('ComputeAcceleration', 'true') + model.setProperty('ComputeMomentum', 'true') + */ // << " - {get|set}Property <name> [<val>]: set/get the property." <<std::endl // << " - displayProperties: print the prop-val couples list." <<std::endl << " - ndof\t\t\t: display the number of DOF of the robot."<< std::endl; @@ -1411,56 +1517,26 @@ commandLine( const std::string& cmdLine, } +//jointName is either a fixed-joint (pinocchio operational frame) or a +//movable joint (pinocchio joint-variant). void Dynamic::cmd_createOpPointSignals( const std::string& opPointName, const std::string& jointName ) { - if(std::find(m_model.names.begin(), - m_model.names.end(), - jointName)!=m_model.names.end()) { createEndeffJacobianSignal(std::string("J")+opPointName,jointName); createPositionSignal(opPointName,jointName); - } - else - SOT_THROW ExceptionDynamic(ExceptionDynamic::GENERIC, - "Robot has no joint corresponding to " + jointName); - } void Dynamic::cmd_createJacobianWorldSignal( const std::string& signalName, const std::string& jointName ) { - if(std::find(m_model.names.begin(), - m_model.names.end(), - jointName)!=m_model.names.end()) { createJacobianSignal(signalName, jointName); - } - else - SOT_THROW ExceptionDynamic(ExceptionDynamic::GENERIC, - "Robot has no joint corresponding to " + jointName); } void Dynamic::cmd_createJacobianEndEffectorSignal( const std::string& signalName, const std::string& jointName ) { - if(std::find(m_model.names.begin(), - m_model.names.end(), - jointName)!=m_model.names.end()) { createEndeffJacobianSignal(signalName, jointName); - } - else - SOT_THROW ExceptionDynamic(ExceptionDynamic::GENERIC, - "Robot has no joint corresponding to " + jointName); } void Dynamic::cmd_createPositionSignal( const std::string& signalName, const std::string& jointName ) { - SOT_THROW ExceptionDynamic(ExceptionDynamic::GENERIC, - "Robot has no joint corresponding to " + jointName); - if(std::find(m_model.names.begin(), - m_model.names.end(), - jointName)!=m_model.names.end()) { createPositionSignal(signalName, jointName); - } - else - SOT_THROW ExceptionDynamic(ExceptionDynamic::GENERIC, - "Robot has no joint corresponding to " + jointName); - } diff --git a/unitTesting/test_config.cpp b/unitTesting/test_config.cpp index 8010561..09c212a 100644 --- a/unitTesting/test_config.cpp +++ b/unitTesting/test_config.cpp @@ -46,6 +46,8 @@ BOOST_AUTO_TEST_CASE (config) //Parse urdf file dynamic_.setUrdfFile("urdf/two_link.urdf"); + dynamic_.parseUrdfFile(); + dynamic_.displayModel(); BOOST_CHECK_EQUAL(dynamic_.m_model.nbody,3); BOOST_CHECK_EQUAL(std::strcmp(dynamic_.m_model.names[0].c_str(),"universe"),0); BOOST_CHECK_EQUAL(std::strcmp(dynamic_.m_model.names[1].c_str(),"JOINT1"),0); diff --git a/unitTesting/two_link.urdf b/unitTesting/two_link.urdf index d20a2d2..570717d 100644 --- a/unitTesting/two_link.urdf +++ b/unitTesting/two_link.urdf @@ -14,8 +14,6 @@ <origin xyz="1 0 0"/> <limit effort="12" lower="0" upper="3.14" velocity="10"/> </joint> - - <link name="CHILD1"> <inertial> <origin xyz="0.5 0 0" rpy="0 0 0"/> @@ -37,48 +35,11 @@ <inertia ixx="1" ixy="0" ixz="0" iyy="1" iyz="0" izz="1" /> </inertial> </link> -<!-- - <link name="CHILD3"> - <inertial> - <origin xyz="0.5 0 0" rpy="0 0 0"/> - <mass value="20"/> - <inertia ixx="1" ixy="0" ixz="0" iyy="1" iyz="0" izz="1" /> - </inertial> - </link> - <link name="CHILD4"> - <inertial> - <origin xyz="0.5 0 0" rpy="0 0 0"/> - <mass value="20"/> - <inertia ixx="1" ixy="0" ixz="0" iyy="1" iyz="0" izz="1" /> - </inertial> - </link> - <link name="CHILD5"> - <inertial> - <origin xyz="0.5 0 0" rpy="0 0 0"/> - <mass value="20"/> - <inertia ixx="1" ixy="0" ixz="0" iyy="1" iyz="0" izz="1" /> - </inertial> - </link> - <joint name="JOINT3" type="revolute"> - <axis xyz="0 0 1"/> + <joint name="FRAMEJOINT1" type="fixed"> <parent link="CHILD2"/> <child link="CHILD3"/> - <origin xyz="1 0 0"/> - <limit effort="100" lower="0" upper="3.14" velocity="10"/> + <origin rpy="0 0 0" xyz="0 0 -0.16"/> </joint> - <joint name="JOINT4" type="revolute"> - <axis xyz="0 0 1"/> - <parent link="CHILD3"/> - <child link="CHILD4"/> - <origin xyz="1 0 0"/> - <limit effort="100" lower="0" upper="3.14" velocity="10"/> - </joint> - <joint name="JOINT5" type="revolute"> - <axis xyz="0 0 1"/> - <parent link="CHILD4"/> - <child link="CHILD5"/> - <origin xyz="1 0 0"/> - <limit effort="100" lower="0" upper="3.14" velocity="10"/> - </joint> ---> + <link name="CHILD3"/> + </robot> -- GitLab