orocos_kinematics_dynamics icon indicating copy to clipboard operation
orocos_kinematics_dynamics copied to clipboard

Segfault in treeidsolver_recursive_newton_euler.cpp

Open DimitriEckert137 opened this issue 4 years ago • 6 comments

@smits

Hi everyone

This error might be due to a bad installation (which i mentioned in this issue which i am waiting for an answer to) bu I think its a different problem. I am working with a simulated ur3e robot. I use the kdl_parser to to get a kdl tree from the urdf file.

Its a segfault and by adding printf statement to treeidsolver_recursive_newton_euler.cpp I could narrow it down, so I am pretty sure it happens on the following line: const std::string& parname = GetTreeElementParent(segment->second)->first; when it passes it the SECOND time:

Thread 8 "continuous_offs" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffdeffd700 (LWP 12010)]
0x00007ffff7bb830c in std::_Rb_tree_const_iterator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, KDL::TreeElement> >::operator->() const () from /home/dimitri/catkin_ws/devel/lib/libcontinuous_offset_calib.so

I tried to printf the name of the current segment to see at which segment the algorithm is at that moment but this also leads to a segfault (already at the first time it passes it).

Thread 8 "continuous_offs" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffe6ffd700 (LWP 13207)]
0x00007ffff683f470 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::c_str() const ()
   from /usr/lib/x86_64-linux-gnu/libstdc++.so.6

This is my code:

ContinuousOffsetCalib.hpp:


#pragma once

#include <any_node/any_node.hpp>
#include <UrKdl.hpp>
#include <sensor_msgs/JointState.h>
#include <geometry_msgs/WrenchStamped.h>
#include <std_msgs/String.h>
#include <std_msgs/Float64.h>
#include <sstream>
#include <memory>    // for std::shared_ptr

namespace continuous_offset_calib {

class ContinuousOffsetCalib : public any_node::Node {

public:

  ContinuousOffsetCalib() = delete;
  explicit ContinuousOffsetCalib(any_node::Node::NodeHandlePtr nh) : any_node::Node(nh) {}
  ~ContinuousOffsetCalib() override = default;

  bool init() override;
  void cleanup() override;
  bool update(const any_worker::WorkerEvent& event);

  void jointStatesSubscriberCallback(const boost::shared_ptr<const sensor_msgs::JointState>& msg);
  void rokuSubscriberCallback(const boost::shared_ptr<const geometry_msgs::WrenchStamped>& msg);

  void preCleanup() override;

  ros::Subscriber joint_states_subscriber;
  ros::Subscriber roku_subscriber;
  ros::Publisher filtered_FT_publisher;

private:

  ur_kdl::UrKdl complete_robot_tree;

  KDL::JntArray current_joint_positions;            // current joint positions              

  KDL::JntArray current_joint_velocities;            // current joint positions              

  struct joint_torques {
    double elbow_joint;
    double shoulder_lift_joint;
    double shoulder_pan_joint;
    double wrist_1_joint;
    double wrist_2_joint;
    double wrist_3_joint;
  } current_joint_torques;

  unsigned int nr_joints = 6;

  KDL::JntArray tau;

  std::map<std::string,KDL::Wrench> current_wrench_FTsensor;

};

} // namespace continuous_offset_calib

ContinuousOffsetCalib.cpp:


#include <ContinuousOffsetCalib.hpp>

namespace continuous_offset_calib {

bool ContinuousOffsetCalib::init(){
  // called on startup
  // add new workers (threads) like this. The workers are automatically stopped before the cleanup() function is called
  constexpr double defaultWorkerTimeStep = 3.0;
  constexpr int priority = 10;
  auto workerTimeStep = param<double>("time_step", defaultWorkerTimeStep);
  addWorker("continuousOffsetCalib::updateWorker", workerTimeStep, &ContinuousOffsetCalib::update, this, priority);

  // to create publishers/subscribers/service clients/servers or read params, use the functions provided by the any_node::Node base class
  // the name of the publishers/subscribers/.. has to be consistent
  // with the names specified in the yaml file (see description of Topic.hpp above)
  constexpr unsigned int defaultQueueSize = 1;

  joint_states_subscriber =
    subscribe("joint_states_subscriber", "/joint_states", defaultQueueSize, &ContinuousOffsetCalib::jointStatesSubscriberCallback, this);
  roku_subscriber =
    subscribe("roku_subscriber", "/roku/FT", defaultQueueSize, &ContinuousOffsetCalib::rokuSubscriberCallback, this);

  MELO_INFO("init called");
  
  MELO_INFO("init tau before: %i", tau.rows());
  tau.resize(6);
  MELO_INFO("init tau after: %i", tau.rows());

  return true;
}

void ContinuousOffsetCalib::cleanup() {
  // this function is called when the node is requested to shut down, _after_ the ros spinners and workers were stopped
  // no need to stop workers which are started with addWorker(..) function
  MELO_INFO("cleanup called");
}

bool ContinuousOffsetCalib::update(const any_worker::WorkerEvent& event) {
  // called by the worker which is automatically set up if rosparam standalone == True.
  // The frequency is defined in the time_step rosparam.
  constexpr unsigned int defaultQueueSize = 1;
  filtered_FT_publisher = advertise<sensor_msgs::JointState>("filtered_FT_publisher", "/filtered_FT", defaultQueueSize);  

  current_joint_positions.resize(6);
  current_joint_velocities.resize(6);
  //tau.resize(6);

  //TODO: joint accelerations
  sensor_msgs::JointState current_estimated_torques = complete_robot_tree.calculateTorques(current_joint_positions, current_joint_velocities, current_joint_positions, current_wrench_FTsensor, tau);

  filtered_FT_publisher.publish(current_estimated_torques);

  MELO_INFO("update called");
  return true;
}

void ContinuousOffsetCalib::preCleanup() {
  // this function is called when the node is requested to shut down, _before_ the ros spinners and workers are beeing stopped
  MELO_INFO("preCleanup called");
}

void ContinuousOffsetCalib::jointStatesSubscriberCallback(const boost::shared_ptr<const sensor_msgs::JointState>& msg) {
  // called asynchrounously when ros messages arrive for the subscriber created in init() function

  current_joint_torques.elbow_joint = msg->effort[0]; 
  current_joint_torques.shoulder_lift_joint = msg->effort[1]; 
  current_joint_torques.shoulder_pan_joint = msg->effort[2]; 
  current_joint_torques.wrist_1_joint = msg->effort[3]; 
  current_joint_torques.wrist_2_joint = msg->effort[4]; 
  current_joint_torques.wrist_3_joint = msg->effort[5]; 

  current_joint_positions.data <<  msg->position[1], msg->position[2], msg->position[0], msg->position[3], msg->position[4], msg->position[5];

  current_joint_velocities.data <<  msg->velocity[1], msg->velocity[2], msg->velocity[0], msg->velocity[3], msg->velocity[4], msg->velocity[5];
}

void ContinuousOffsetCalib::rokuSubscriberCallback(const boost::shared_ptr<const geometry_msgs::WrenchStamped>& msg){

  KDL::Wrench wrench;
  wrench.force[0] = msg->wrench.force.x;
  wrench.force[1] = msg->wrench.force.y;
  wrench.force[2] = msg->wrench.force.z;

  wrench.torque[0] = msg->wrench.force.x;
  wrench.torque[1] = msg->wrench.force.y;
  wrench.torque[2] = msg->wrench.force.z;

  current_wrench_FTsensor.insert(std::pair<std::string,KDL::Wrench>((std::string)"sensor_top_link",wrench));

}

} // namespace continuous_offset_calib

UrKdl.hpp:


#pragma once

#include <kdl_parser/kdl_parser.hpp>
#include <urdf/model.h>
#include <kdl/treeidsolver_recursive_newton_euler.hpp>
#include <kdl/jacobian.hpp>
#include <kdl/tree.hpp>
#include <kdl/jntarray.hpp>
#include <kdl/treejnttojacsolver.hpp>
#include <sensor_msgs/JointState.h>
#include <vector>

namespace ur_kdl {

class UrKdl {

public:

  UrKdl(){
    KDL::Tree ur_tree;
    ros::NodeHandle node;
    std::string robot_desc_string;
    KDL::Vector g(0.0, 0.0, 9.81);
    node.param("robot_description", robot_desc_string, std::string());
    if (!kdl_parser::treeFromString(robot_desc_string, ur_tree)){
      ROS_ERROR("Failed to construct kdl tree");
    }
    else {
      ROS_INFO("Successfully kdl_parsed urdf file");
    }
    invDynSolver = new KDL::TreeIdSolver_RNE(ur_tree, g);
  }

  ~UrKdl(){};

  // parsing kdl tree from the ros param server (only works when master and robot acturally launched not standalone) https://wiki.ros.org/kdl_parser/Tutorials/Start%20using%20the%20KDL%20parser

  sensor_msgs::JointState calculateTorques(const KDL::JntArray &q, const KDL::JntArray &q_dot, const KDL::JntArray &q_dotdot, const KDL::WrenchMap& f_ext, KDL::JntArray &tau){
    int error = 0;
    MELO_INFO("before carttojnt tau: %i", tau.rows());
    error = invDynSolver->CartToJnt(q, q_dot, q_dotdot, f_ext, tau);
    MELO_INFO("after carttojnt tau: %i", tau.rows());
    sensor_msgs::JointState torques;
    std::vector<double> effort;
    MELO_INFO("calculateTorques, %i", error);
    for(int i = 0; i < tau.data.rows(); i++){
      effort.push_back(tau.data[i]);
      MELO_INFO("%i   %f", i, tau.data[i]);
    }
    torques.effort = effort;
    return torques;
  }

private:

  KDL::WrenchMap current_wrench_FTsensor;
  KDL::TreeIdSolver_RNE* invDynSolver;

};

} // namespace ur_kdl

DimitriEckert137 avatar Jun 18 '20 11:06 DimitriEckert137