├── resources
└── screenshot.png
├── humanoid_constraint_sampler_plugin.xml
├── .gitignore
├── config
└── hrp2jsknt_stability.yaml
├── package.xml
├── CMakeLists.txt
├── README.md
├── include
└── moveit_humanoid_stability
│ ├── humanoid_stability.h
│ └── humanoid_constraint_sampler.h
└── src
├── humanoid_stability.cpp
└── humanoid_constraint_sampler.cpp
/resources/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davetcoleman/moveit_humanoid_stability/HEAD/resources/screenshot.png
--------------------------------------------------------------------------------
/humanoid_constraint_sampler_plugin.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Samples a whole body humanoid robot, starting with one leg
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files
2 | *.slo
3 | *.lo
4 | *.o
5 |
6 | # Compiled Dynamic libraries
7 | *.so
8 | *.dylib
9 |
10 | # Compiled Static libraries
11 | *.lai
12 | *.la
13 | *.a
14 |
15 | # Python stuff
16 | *.pyc
17 |
18 | # Data files
19 | *.dat
20 |
21 | # Emacs temp files
22 | .#*
23 | *~
24 |
25 | # Silly OSX Files
26 | .DS_Store
27 |
28 | # CSV Files of Data
29 | *.csv
30 |
31 | # Catkin Workspace
32 | /CMakeLists.txt
33 |
34 | # Images
35 | *.png
36 | *.jpg
37 |
38 | # Catkin config
39 | CATKIN_IGNORE
--------------------------------------------------------------------------------
/config/hrp2jsknt_stability.yaml:
--------------------------------------------------------------------------------
1 | humanoid_stability:
2 | # A heuristic for quickly determining the valid sampled area limits of a torso's virtual joint for stability checking
3 | bounding_box:
4 | min_x: -0.44564
5 | max_x: 0.44564
6 | min_y: -0.223091
7 | max_y: 0.223091
8 | min_z: 0.193524
9 | max_z: 0.732025
10 | padding: 0.1
11 | # Link names for the URDF
12 | left_foot_name: LLEG_LINK5
13 | right_foot_name: RLEG_LINK5
14 | # Planning groups names from the SRDF
15 | left_leg_name: left_leg
16 | right_leg_name: right_leg
17 | whole_body_minus_left_leg_name: whole_body_minus_left_leg
18 | whole_body_minus_right_leg_name: whole_body_minus_right_leg
19 | # this MoveIt planning group does NOT contain any virtual joints but does have all fingers, feet, head, etc
20 | all_joints_group: robot_joints
21 | # convex hull scaling factor for stability checking foot polygon
22 | foot_polygon_scale: 0.9
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | moveit_humanoid_stability
4 | 0.0.1
5 | Humanoid stability functionality for MoveIt
6 |
7 | Dave Coleman
8 |
9 | Dave Coleman
10 |
11 | BSD
12 |
13 | https://github.com/davetcoleman/moveit_humanoid_stability
14 | https://github.com/davetcoleman/moveit_humanoid_stability/issues
15 | https://github.com/davetcoleman/moveit_humanoid_stability/
16 |
17 | catkin
18 |
19 | hrl_kinematics
20 | moveit_core
21 | moveit_visual_tools
22 | roscpp
23 | pluginlib
24 |
25 | hrl_kinematics
26 | moveit_core
27 | moveit_visual_tools
28 | roscpp
29 | pluginlib
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(moveit_humanoid_stability)
3 |
4 | find_package(catkin REQUIRED COMPONENTS
5 | hrl_kinematics
6 | moveit_core
7 | moveit_visual_tools
8 | pluginlib
9 | roscpp
10 | )
11 |
12 | ## System dependencies are found with CMake's conventions
13 | find_package(Boost REQUIRED COMPONENTS system)
14 |
15 | # Catkin
16 | catkin_package(
17 | LIBRARIES
18 | ${PROJECT_NAME}
19 | CATKIN_DEPENDS
20 | hrl_kinematics
21 | moveit_core
22 | moveit_visual_tools
23 | INCLUDE_DIRS
24 | include
25 | )
26 |
27 | include_directories(
28 | include
29 | ${catkin_INCLUDE_DIRS}
30 | )
31 |
32 | # Stability Library
33 | add_library(${PROJECT_NAME}
34 | src/humanoid_stability.cpp
35 | )
36 | target_link_libraries(${PROJECT_NAME}
37 | ${catkin_LIBRARIES}
38 | ${Boost_LIBRARIES}
39 | )
40 | add_dependencies(${PROJECT_NAME} ${catkin_EXPORTED_TARGETS})
41 |
42 | # Sampling Library
43 | add_library(humanoid_moveit_constraint_sampler
44 | src/humanoid_constraint_sampler.cpp
45 | )
46 | target_link_libraries(humanoid_moveit_constraint_sampler
47 | ${catkin_LIBRARIES}
48 | ${Boost_LIBRARIES}
49 | )
50 | add_dependencies(humanoid_moveit_constraint_sampler ${catkin_EXPORTED_TARGETS})
51 |
52 | # Install library
53 | install(
54 | TARGETS
55 | ${PROJECT_NAME}
56 | humanoid_moveit_constraint_sampler
57 | LIBRARY DESTINATION
58 | ${CATKIN_PACKAGE_LIB_DESTINATION}
59 | )
60 |
61 | # Install header files
62 | install(
63 | DIRECTORY
64 | include
65 | DESTINATION
66 | ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
67 | )
68 |
69 | # Install plugins
70 | install(
71 | FILES
72 | humanoid_constraint_sampler_plugin.xml
73 | DESTINATION
74 | ${CATKIN_PACKAGE_SHARE_DESTINATION}
75 | )
76 |
77 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MoveIt! Humanoid Stability
2 |
3 | Libraries for sampling and validating a humanoid biped with one or more fixed feet for stability constraints in MoveIt! including:
4 |
5 | - Fast stability heuristic checking
6 | - Center of mass, static stability, and support polygon computations.
7 | - Smart sampling of whole body positions using random number generation
8 |
9 | Provides a wrapper for [hrl_kinematics](https://github.com/ahornung/hrl_kinematics) that allows the center of mass stability testing for robots based on KDL.
10 |
11 | Developed by [Dave Coleman](http://dav.ee) and Shintaro Noda at JSK, University of Tokyo.
12 |
13 |
14 | .
15 |
16 | ## Install
17 |
18 | This package requires an experimental branch of moveit_core be installed. It might be a while until it is merged into the main distribution. See [experimental_fake_base](https://github.com/davetcoleman/moveit_core/tree/experimental_fake_base)
19 |
20 | Overall, making this work on your machine will be fairly complicated until a long list of pending MoveIt! pull requests are accepted. See Dave Coleman for more details.
21 |
22 | ## Usage and Explanation
23 |
24 | ### Balance Constraint Validator
25 |
26 | Performs two course-grain checks and, if they pass, finally does full COM check:
27 |
28 | 1. Checks for a course-grain stability check by seeing if the torso is within a bounding box. This bound box is set in the yaml file and should be found through many iterations. A 0.1m expansion is added to the bounding box so that it over-accepts poses.
29 | 2. Checks if the other foot is above ground (z >= 0)
30 | 3. Checks if the COM is within the foot projection using hrl_kinematics
31 |
32 | It does not check for self collision or collision with environment, because that is accomplished by other components in MoveIt! automatically.
33 |
34 | You can use the validator within a MoveIt! planning scene as a custom stability checker - see the function ``getStateFeasibilityFn()`` for use with a planning scene by calling:
35 |
36 | ```
37 | planning_scene_->setStateFeasibilityPredicate(humanoid_stability_->getStateFeasibilityFn());
38 | ```
39 |
40 | ### State Sampling
41 |
42 | The sampler first samples the fixed leg, performs some quick checks, then samples the rest of the body and performs exact checks.
43 |
44 | You can use a custom constraint sampler plugin for MoveIt! by adding a "constraint_samplers" param to your move_group launch file, for example:
45 |
46 | ```
47 |
48 |
49 |
50 |
51 | ```
52 |
53 | ## Configuration
54 |
55 | A yaml configuration file is required to load the settings for your robot. See [config/hrp2jsknt_stability.yaml](https://github.com/davetcoleman/moveit_humanoid_stability/blob/hydro-devel/config/hrp2jsknt_stability.yaml)
56 |
57 | ## Debug
58 |
59 | ### Balance Constraint Validator
60 |
61 | N/A
62 |
63 | ### State Sampling
64 |
65 | Rviz markers are available on topic ``/humanoid_constraint_sample_markers`` and the robot state is published on ``/humanoid_constraint_sample_robots``
66 |
67 | ## Limitations / Future Work
68 |
69 | ### Stability Validator
70 |
71 | - Only supports standing on left or right foot - needs dual feet support
72 | - Only supports fixed link remaining the same (never changes location or link)
73 | - Improve conversion of joint states from MoveIt! to KDL
74 | - Smartly check which foot/feet to check for stability
75 | - Improve other foot check for above ground to include all of mesh, not just the origin of the tip link of the leg
76 |
77 | ### Constraint Sampler
78 |
79 | - Cleanup code (currently research code)
80 | - Sample for dual legs, which is a closed chain, and probably requires an IK solver
--------------------------------------------------------------------------------
/include/moveit_humanoid_stability/humanoid_stability.h:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Software License Agreement (BSD License)
3 | *
4 | * Copyright (c) 2014, JSK, The University of Tokyo.
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * * Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | * * Redistributions in binary form must reproduce the above
14 | * copyright notice, this list of conditions and the following
15 | * disclaimer in the documentation and/or other materials provided
16 | * with the distribution.
17 | * * Neither the name of the JSK, The University of Tokyo nor the names of its
18 | * contributors may be used to endorse or promote products derived
19 | * from this software without specific prior written permission.
20 | *
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 | * POSSIBILITY OF SUCH DAMAGE.
33 | *********************************************************************/
34 |
35 | /* Author: Dave Coleman
36 | Desc: Wrapper for hrl_kinematics for calculing COM
37 | */
38 |
39 | #ifndef MOVEIT_HUMANOID_STABILITY__HUMANOID_STABILITY
40 | #define MOVEIT_HUMANOID_STABILITY__HUMANOID_STABILITY
41 |
42 | // ROS
43 | #include
44 |
45 | // Helper for Rviz
46 | #include
47 |
48 | // Humanoid balance constraint tester
49 | #include
50 |
51 | namespace moveit_humanoid_stability
52 | {
53 |
54 | class HumanoidStability
55 | {
56 | private:
57 |
58 | // Show more visual and console output, with general slower run time.
59 | bool verbose_;
60 |
61 | // For visualizing things in rviz
62 | moveit_visual_tools::MoveItVisualToolsPtr visual_tools_;
63 |
64 | // Bounds for estimating virtual joint contraint
65 | double min_x_;
66 | double max_x_;
67 | double min_y_;
68 | double max_y_;
69 | double min_z_;
70 | double max_z_;
71 |
72 | // Model semantics
73 | const robot_model::LinkModel* left_foot_;
74 | const robot_model::LinkModel* right_foot_;
75 | const robot_model::LinkModel* free_foot_; // opposite of fixed_foot, this is the foot that is in the air
76 | const robot_model::JointModelGroup* all_joints_group_;
77 |
78 | // Stability checker
79 | hrl_kinematics::TestStabilityPtr test_stability_;
80 | std::map joint_positions_map_;
81 | hrl_kinematics::Kinematics::FootSupport support_mode_;
82 | tf::Vector3 normal_vector_;
83 |
84 | public:
85 |
86 | /**
87 | * \brief Constructor
88 | * \param verbose - run in debug mode
89 | * \param robot_state
90 | * \param visual_tools - shared visual tools ptr for debugging (optional)
91 | */
92 | HumanoidStability(bool verbose, const moveit::core::RobotState &robot_state,
93 | const moveit_visual_tools::MoveItVisualToolsPtr &visual_tools = moveit_visual_tools::MoveItVisualToolsPtr());
94 |
95 | /**
96 | * \brief Destructor
97 | */
98 | ~HumanoidStability() {};
99 |
100 | /**
101 | * \brief Helper for setting a planning scene state validator function
102 | * \return boost function pointer for use in PlanningScene
103 | */
104 | planning_scene::StateFeasibilityFn getStateFeasibilityFn()
105 | {
106 | return boost::bind(&HumanoidStability::isValid, this, _1, _2);
107 | }
108 |
109 | /**
110 | * \brief Check if a robot state is stable/balanced based on all checks including heuristics
111 | * NOTE: this function can be used as a planning_scene StateFeasibilityFn
112 | * \param robot_state - input state to check
113 | * \return true if stable
114 | */
115 | bool isValid(const robot_state::RobotState &robot_state, bool verbose);
116 |
117 | /**
118 | * \brief Run quick/low-cost virtual joint bounding box test on state to see if vjoint is within rough bounds
119 | * \param robot_state - input state to check
120 | * \return true if within bounds
121 | */
122 | bool isApproximateValidBase(const robot_state::RobotState &robot_state);
123 |
124 | /**
125 | * \brief Run quick/low-cost other leg test to see if its above the z 0 value, e.g. above ground
126 | * \param robot_state - input state to check
127 | * \return true if within bounds
128 | */
129 | bool isApproximateValidFoot(const robot_state::RobotState &robot_state);
130 |
131 | /**
132 | * \brief Run HRL kinematics COM calculation
133 | * \param robot_state - input state to check
134 | * \return true if stable
135 | */
136 | bool isValidCOM(const robot_state::RobotState &robot_state);
137 |
138 | /**
139 | * \brief Debug function for showing the course-grain constraint enforcement of torso
140 | * \return true on success
141 | */
142 | bool displayBoundingBox(const Eigen::Affine3d &translation = Eigen::Affine3d::Identity()) const;
143 |
144 | /**
145 | * \brief For debugging
146 | */
147 | void printVirtualJointExtremes() const;
148 |
149 | /**
150 | * \brief Getter for Verbose
151 | */
152 | bool getVerbose()
153 | {
154 | return verbose_;
155 | }
156 |
157 | /**
158 | * \brief Setter for Verbose
159 | */
160 | void setVerbose(bool verbose)
161 | {
162 | verbose_ = verbose;
163 | }
164 |
165 |
166 | }; // end class
167 |
168 | // Create boost pointers for this class
169 | typedef boost::shared_ptr HumanoidStabilityPtr;
170 | typedef boost::shared_ptr HumanoidStabilityConstPtr;
171 |
172 | } // end namespace
173 |
174 | #endif
175 |
--------------------------------------------------------------------------------
/include/moveit_humanoid_stability/humanoid_constraint_sampler.h:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Software License Agreement ("Modified BSD License")
3 | *
4 | * Copyright (c) 2014, JSK, The University of Tokyo.
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * * Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | * * Redistributions in binary form must reproduce the above
14 | * copyright notice, this list of conditions and the following
15 | * disclaimer in the documentation and/or other materials provided
16 | * with the distribution.
17 | * * Neither the name of the JSK, The University of Tokyo nor the names of its
18 | * contributors may be used to endorse or promote products derived
19 | * from this software without specific prior written permission.
20 | *
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 | * POSSIBILITY OF SUCH DAMAGE.
33 | *********************************************************************/
34 |
35 | /* Author: Dave Coleman
36 | Desc: Samples 1 leg joint random, checks for partial validity,
37 | then samples rest of joints randomly adn checks for validity again
38 | */
39 |
40 | #ifndef MOVEIT_HUMANOID_STABILITY__HUMANOID_CONSTRAINT_SAMPLER_
41 | #define MOVEIT_HUMANOID_STABILITY__HUMANOID_CONSTRAINT_SAMPLER_
42 |
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 | #include
49 |
50 | // Stability checker
51 | #include
52 |
53 | // Helper for Rviz
54 | #include
55 |
56 | namespace moveit_humanoid_stability
57 | {
58 |
59 | /**
60 | * \brief HumanoidConstraintSampler is a class that allows the sampling
61 | * of joints in a particular group of the robot, subject to a set of individual joint constraints.
62 | *
63 | * The set of individual joint constraint reduce the allowable bounds
64 | * used in the sampling. Unconstrained values will be sampled within
65 | * their limits.
66 | *
67 | */
68 | class HumanoidConstraintSampler : public constraint_samplers::ConstraintSampler
69 | {
70 | public:
71 |
72 | /**
73 | * Constructor
74 | *
75 | * @param [in] scene The planning scene used to check the constraint
76 | *
77 | * @param [in] group_name The group name associated with the
78 | * constraint. Will be invalid if no group name is passed in or the
79 | * joint model group cannot be found in the kinematic model
80 | *
81 | */
82 | HumanoidConstraintSampler(const planning_scene::PlanningSceneConstPtr &scene,
83 | const std::string &group_name)
84 | : ConstraintSampler(scene, group_name)
85 | {
86 | }
87 |
88 | /**
89 | * \brief Configures a joint constraint given a Constraints message.
90 | *
91 | * If more than one constraint for a particular joint is specified,
92 | * the most restrictive set of bounds will be used (highest minimum
93 | * value, lowest maximum value). For the configuration to be
94 | * successful, the following condition must be met, in addition to
95 | * the conditions specified in \ref configure(const std::vector &jc) :
96 |
97 | * \li The Constraints message must contain one or more valid joint
98 | * constraints (where validity is judged by the ability to configure
99 | * a \ref JointConstraint)
100 | *
101 | * @param [in] constr The message containing the constraints
102 | *
103 | * @return True if the conditions are met, otherwise false
104 | */
105 | virtual bool configure(const moveit_msgs::Constraints &constr);
106 |
107 | /**
108 | * \brief Helper for setting up the visualizer in Rviz
109 | */
110 | void loadVisualTools();
111 |
112 | /**
113 | * \brief Configures a joint constraint given a vector of constraints.
114 | *
115 | * If more than one constraint for a particular joint is specified,
116 | * the most restrictive set of bounds will be used (highest minimum
117 | * value, lowest_maximum value. For the configuration to be
118 | * successful, the following conditions must be met:
119 |
120 | * \li The vector must contain one or more valid, enabled joint
121 | * constraints
122 | *
123 | * \li At least one constraint must reference a joint in the
124 | * indicated group. If no additional bounds exist for this group,
125 | * then RobotState::setToRandomPositions() can be
126 | * used to generate a sample independently from the
127 | * constraint_samplers infrastructure.
128 | *
129 | * \li The constraints must allow a sampleable region for all
130 | * joints, where the most restrictive minimum bound is less than the
131 | * most restrictive maximum bound
132 | *
133 | * @param [in] jc The vector of joint constraints
134 | *
135 | * @return True if the conditions are met, otherwise false
136 | */
137 | bool configureJoint(const std::vector &jc);
138 |
139 | virtual bool sample(robot_state::RobotState &robot_state, const robot_state::RobotState &ks,
140 | unsigned int max_attempts);
141 |
142 | bool sampleJoints(robot_state::RobotState &robot_state);
143 |
144 | virtual bool project(robot_state::RobotState &robot_state,
145 | unsigned int max_attempts);
146 |
147 | /**
148 | * \brief Gets the number of constrained joints - joints that have an
149 | * additional bound beyond the joint limits.
150 | *
151 | *
152 | * @return The number of constrained joints.
153 | */
154 | std::size_t getConstrainedJointCount() const
155 | {
156 | return bounds_.size();
157 | }
158 |
159 | /**
160 | * \brief Gets the number of unconstrained joints - joint that have
161 | * no additional bound beyond the joint limits.
162 | *
163 | * @return The number of unconstrained joints.
164 | */
165 | std::size_t getUnconstrainedJointCount() const
166 | {
167 | return unbounded_.size();
168 | }
169 |
170 | /**
171 | * \brief Get the name of the constraint sampler, for debugging purposes
172 | * should be in CamelCase format.
173 | * \return string of name
174 | */
175 | virtual const std::string& getName() const
176 | {
177 | //printVirtualJointExtremes();
178 | static const std::string SAMPLER_NAME = "HumanoidConstraintSampler";
179 | return SAMPLER_NAME;
180 | }
181 |
182 | /**
183 | * \brief Override so we can set verbose flag in sub components
184 | */
185 | virtual void setVerbose(bool verbose);
186 |
187 | private:
188 |
189 |
190 | protected:
191 |
192 | /// \brief An internal structure used for maintaining constraints on a particular joint
193 | struct JointInfo
194 | {
195 | /**
196 | * \brief Constructor
197 | *
198 | * @return
199 | */
200 | JointInfo()
201 | {
202 | min_bound_ = -std::numeric_limits::max();
203 | max_bound_ = std::numeric_limits::max();
204 | }
205 |
206 | /**
207 | * \brief Function that adjusts the joints only if they are more
208 | * restrictive. This means that the min limit is higher than the
209 | * current limit, or the max limit is lower than the current max
210 | * limit.
211 | *
212 | * @param min The min limit for potential adjustment
213 | * @param max The max limit for potential adjustment
214 | */
215 | void potentiallyAdjustMinMaxBounds(double min, double max)
216 | {
217 | min_bound_ = std::max(min, min_bound_);
218 | max_bound_ = std::min(max, max_bound_);
219 | }
220 |
221 | double min_bound_; /**< The most restrictive min value of those set */
222 | double max_bound_; /**< The most restrictive max value of those set */
223 | std::size_t index_; /**< The index within the joint state vector for this joint */
224 | };
225 |
226 | virtual void clear();
227 |
228 | random_numbers::RandomNumberGenerator random_number_generator_; /**< \brief Random number generator used to sample */
229 | std::vector bounds_; /**< \brief The bounds for any joint with bounds that are more restrictive than the joint limits */
230 |
231 | std::vector unbounded_; /**< \brief The joints that are not bounded except by joint limits */
232 | std::vector uindex_; /**< \brief The index of the unbounded joints in the joint state vector */
233 | std::vector values_; /**< \brief Values associated with this group to avoid continuously reallocating */
234 |
235 | std::string sampler_name_; // used for debugging
236 |
237 | // Leg IK solvers
238 | //const robot_model::JointModelGroup* left_leg_;
239 | //const robot_model::JointModelGroup* right_leg_;
240 |
241 | // Store desired feet positions
242 | //Eigen::Affine3d left_foot_position_;
243 | //Eigen::Affine3d right_foot_position_;
244 |
245 | // Store foot to torso translation
246 | //Eigen::Affine3d left_foot_to_torso_;
247 |
248 | // Allocate memory for storing transforms of feet
249 | //Eigen::Affine3d left_foot_position_new_;
250 | //Eigen::Affine3d right_foot_position_new_;
251 |
252 | // Verbose mode
253 | geometry_msgs::Pose text_pose_;
254 |
255 | // For visualizing things in rviz
256 | moveit_visual_tools::MoveItVisualToolsPtr visual_tools_;
257 |
258 | // Tool for checking balance
259 | moveit_humanoid_stability::HumanoidStabilityPtr humanoid_stability_;
260 |
261 | // Properties of robot's standing stance
262 | const robot_model::JointModelGroup *whole_body_minus_fixed_leg_;
263 | const robot_model::JointModelGroup *fixed_leg_;
264 | const robot_model::LinkModel* left_foot_;
265 | const robot_model::LinkModel* right_foot_;
266 | // Robot model properties
267 | const robot_model::JointModelGroup *whole_body_minus_left_leg_;
268 | const robot_model::JointModelGroup *whole_body_minus_right_leg_;
269 | const robot_model::JointModelGroup *left_leg_;
270 | const robot_model::JointModelGroup *right_leg_;
271 |
272 | };
273 |
274 | // define the sampler allocator plugin interface
275 | class HumanoidConstraintSamplerAllocator : public constraint_samplers::ConstraintSamplerAllocator
276 | {
277 | public:
278 |
279 | virtual constraint_samplers::ConstraintSamplerPtr alloc(const planning_scene::PlanningSceneConstPtr &scene,
280 | const std::string &group_name, const moveit_msgs::Constraints &constr)
281 | {
282 | constraint_samplers::ConstraintSamplerPtr cs(new HumanoidConstraintSampler(scene, group_name));
283 | cs->configure(constr);
284 | return cs;
285 | }
286 |
287 | virtual bool canService(const planning_scene::PlanningSceneConstPtr &scene, const std::string &group_name,
288 | const moveit_msgs::Constraints &constr) const
289 | {
290 | // override: always use
291 | return true;
292 |
293 | // do not use this sampler if there are any joint constraints, because then we are in the goal sampling stage
294 | if (
295 | constr.joint_constraints.size() == 0 &&
296 | group_name == "whole_body")
297 | {
298 | logInform("humanoid_constraint_sampler: Using custom constraint sampler");
299 | return true;
300 | }
301 |
302 | logInform("humanoid_constraint_sampler: NOT using custom constraint sampler");
303 | return false;
304 | }
305 |
306 | };
307 |
308 | } // namespace
309 |
310 | PLUGINLIB_EXPORT_CLASS(moveit_humanoid_stability::HumanoidConstraintSamplerAllocator,
311 | constraint_samplers::ConstraintSamplerAllocator);
312 |
313 |
314 | #endif
315 |
--------------------------------------------------------------------------------
/src/humanoid_stability.cpp:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Software License Agreement (BSD License)
3 | *
4 | * Copyright (c) 2014, JSK, The University of Tokyo.
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * * Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | * * Redistributions in binary form must reproduce the above
14 | * copyright notice, this list of conditions and the following
15 | * disclaimer in the documentation and/or other materials provided
16 | * with the distribution.
17 | * * Neither the name of the JSK, The University of Tokyo nor the names of its
18 | * contributors may be used to endorse or promote products derived
19 | * from this software without specific prior written permission.
20 | *
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 | * POSSIBILITY OF SUCH DAMAGE.
33 | *********************************************************************/
34 |
35 | /* Author: Dave Coleman
36 | Desc: Wrapper for hrl_kinematics for calculing COM
37 | */
38 |
39 | #include
40 |
41 | namespace moveit_humanoid_stability
42 | {
43 |
44 | HumanoidStability::HumanoidStability(bool verbose, const moveit::core::RobotState &robot_state,
45 | const moveit_visual_tools::MoveItVisualToolsPtr &visual_tools)
46 | : verbose_(verbose)
47 | , visual_tools_(visual_tools)
48 | , normal_vector_(0.0, 0.0, 1.0)
49 | {
50 | // Configurations
51 | static const std::string ROOT_NAME = "humanoid_stability";
52 |
53 | normal_vector_.normalize(); // TODO is this necessary?
54 |
55 | ros::NodeHandle nh("~");
56 |
57 | // Temporary vars for loading from param server
58 | double bounding_box_padding;
59 | double foot_polygon_scale;
60 | std::string left_foot_name = "left_foot";
61 | std::string right_foot_name = "right_foot";
62 | std::string all_joints_group = "robot_joints";
63 | std::string base_link = robot_state.getRobotModel()->getRootLink()->getName();
64 |
65 | // Load the torso (vjoint) bounds from yaml file
66 | nh.param(ROOT_NAME + "/bounding_box/min_x", min_x_, 0.0);
67 | nh.param(ROOT_NAME + "/bounding_box/max_x", max_x_, 0.0);
68 | nh.param(ROOT_NAME + "/bounding_box/min_y", min_y_, 0.0);
69 | nh.param(ROOT_NAME + "/bounding_box/max_y", max_y_, 0.0);
70 | nh.param(ROOT_NAME + "/bounding_box/min_z", min_z_, 0.0);
71 | nh.param(ROOT_NAME + "/bounding_box/max_z", max_z_, 0.0);
72 | nh.param(ROOT_NAME + "/bounding_box/padding", bounding_box_padding, 0.1);
73 |
74 | // Load other settings from yaml file
75 | nh.getParam(ROOT_NAME + "/left_foot_name", left_foot_name);
76 | nh.getParam(ROOT_NAME + "/right_foot_name", right_foot_name);
77 | nh.getParam(ROOT_NAME + "/all_joints_group", all_joints_group);
78 | nh.param(ROOT_NAME + "/foot_polygon_scale", foot_polygon_scale, 1.0);
79 |
80 | // Add padding to all limits just in case
81 | min_x_ += bounding_box_padding;
82 | max_x_ += bounding_box_padding;
83 | min_y_ += bounding_box_padding;
84 | max_y_ += bounding_box_padding;
85 | min_z_ += bounding_box_padding;
86 | max_z_ += bounding_box_padding;
87 |
88 | // Useful links to remember
89 | left_foot_ = robot_state.getRobotModel()->getLinkModel(left_foot_name);
90 | right_foot_ = robot_state.getRobotModel()->getLinkModel(right_foot_name);
91 | all_joints_group_ = robot_state.getRobotModel()->getJointModelGroup(all_joints_group);
92 |
93 | // Get the offset between the foot and the torso to allow correct positioning of bounding box
94 | // TODO: this assumes the fixed link never changes, which will eventually be a bad assumption
95 | moveit::core::RobotState temp_state(robot_state);
96 | temp_state.setToDefaultValues();
97 | Eigen::Affine3d left_foot_to_torso = temp_state.getGlobalLinkTransform(left_foot_);
98 |
99 | // Move the x & y bounds over from foot frame of reference to torso frame of reference. z is always w.r.t. ground (0)
100 | max_x_ -= left_foot_to_torso.translation().x();
101 | max_y_ -= left_foot_to_torso.translation().y();
102 | min_x_ -= left_foot_to_torso.translation().x();
103 | min_y_ -= left_foot_to_torso.translation().y();
104 |
105 | // Setup HRL Kinematics Balance Constraint
106 |
107 | // Choose which foot is fixed
108 | if (robot_state.getFixedFoot() == left_foot_)
109 | {
110 | support_mode_ = hrl_kinematics::Kinematics::SUPPORT_SINGLE_LEFT;
111 | free_foot_ = right_foot_;
112 | }
113 | else if (robot_state.getFixedFoot() == right_foot_)
114 | {
115 | support_mode_ = hrl_kinematics::Kinematics::SUPPORT_SINGLE_RIGHT;
116 | free_foot_ = left_foot_;
117 | }
118 | else
119 | {
120 | ROS_ERROR_STREAM_NAMED("temp","Could not match a foot link with the chosen fixed on in RobotState. rosparam may be misconfigured to your URDF");
121 | }
122 | // TODO: allow both
123 | //hrl_kinematics::Kinematics::FootSupport support_mode_ = hrl_kinematics::Kinematics::SUPPORT_DOUBLE;
124 |
125 | // Preload joint positions map for less memory usage
126 | for (std::size_t i = 0; i < all_joints_group_->getVariableCount(); ++i)
127 | {
128 | // Intitialize empty
129 | joint_positions_map_.insert(std::make_pair(all_joints_group_->getJointModels()[i]->getName(), 0));
130 | }
131 |
132 | // Error check
133 | if (!visual_tools_ && verbose_)
134 | {
135 | ROS_ERROR_STREAM_NAMED("stability","No visual_tools passed in when in verbose mode, turning off verbose");
136 | verbose_ = false;
137 | }
138 |
139 | // Show bounding box
140 | if (verbose_)
141 | printVirtualJointExtremes();
142 |
143 | // Load hrl_kinematics
144 | test_stability_.reset(new hrl_kinematics::TestStability(right_foot_name, // rfoot_mesh_link_name
145 | base_link, // root_link_name
146 | right_foot_name, left_foot_name, // rfoot, lfoot link name
147 | robot_state.getRobotModel()->getURDF(),
148 | foot_polygon_scale));
149 |
150 |
151 | ROS_INFO_STREAM_NAMED("stability","Humanoid stability validator initialized.");
152 | }
153 |
154 | bool HumanoidStability::isValid(const robot_state::RobotState &robot_state, bool verbose)
155 | {
156 | // Turn on verbose mode if planner requests it
157 | if (verbose == true && verbose_ == false)
158 | {
159 | if (!visual_tools_)
160 | ROS_ERROR_STREAM_NAMED("stability","No visual_tools passed in when in verbose mode, turning off verbose");
161 | else
162 | {
163 | ROS_WARN_STREAM_NAMED("temp","Verbose mode forced on but IGNORED");
164 | //verbose_ = true; // TODO
165 | }
166 | }
167 |
168 | // Publish state
169 | if (verbose_)
170 | {
171 | visual_tools_->publishRobotState(robot_state);
172 | ros::Duration(0.25).sleep();
173 | }
174 |
175 | // Check torso
176 | if (!isApproximateValidBase(robot_state))
177 | {
178 | if (verbose_)
179 | ROS_WARN_STREAM_NAMED("stability","Invalid because of approximate base location");
180 | return false;
181 | }
182 |
183 | // Check COM
184 | if (!isApproximateValidFoot(robot_state))
185 | {
186 | if (verbose_)
187 | ROS_WARN_STREAM_NAMED("stability","Invalid because of approximate foot location");
188 | return false;
189 | }
190 |
191 | // Check COM
192 | if (!isValidCOM(robot_state))
193 | {
194 | if (verbose_)
195 | ROS_WARN_STREAM_NAMED("stability","Invalid because of COM");
196 | return false;
197 | }
198 |
199 | return true;
200 | }
201 |
202 | bool HumanoidStability::isApproximateValidBase(const robot_state::RobotState &robot_state)
203 | {
204 | // Check if vjoint (torso) is within reasonable limits
205 | const robot_model::JointModel *vjoint = robot_state.getJointModel("virtual_joint"); // TODO unhard code
206 | const double* vjoint_positions = robot_state.getJointPositions(vjoint);
207 | if (verbose_)
208 | {
209 | if (false) // disabled
210 | {
211 | std::cout << "Vjoint: " << std::endl;
212 | std::cout << " X: " << boost::format("%8.4f") % min_x_ << boost::format("%8.4f") % vjoint_positions[0]
213 | << boost::format("%8.4f") % max_x_ << std::endl;
214 | std::cout << " Y: " << boost::format("%8.4f") % min_y_ << boost::format("%8.4f") % vjoint_positions[1]
215 | << boost::format("%8.4f") % max_y_ << std::endl;
216 | std::cout << " Z: " << boost::format("%8.4f") % min_z_ << boost::format("%8.4f") % vjoint_positions[2]
217 | << boost::format("%8.4f") % max_z_ << std::endl;
218 | }
219 |
220 | if (!visual_tools_)
221 | ROS_ERROR_STREAM_NAMED("temp","Caught that error");
222 | visual_tools_->deleteAllMarkers();
223 | displayBoundingBox(robot_state.getFakeBaseTransform());
224 | }
225 |
226 | if (vjoint_positions[0] < min_x_ + robot_state.getFakeBaseTransform().translation().x() ||
227 | vjoint_positions[0] > max_x_ + robot_state.getFakeBaseTransform().translation().x() ||
228 | vjoint_positions[1] < min_y_ + robot_state.getFakeBaseTransform().translation().y() ||
229 | vjoint_positions[1] > max_y_ + robot_state.getFakeBaseTransform().translation().y() ||
230 | vjoint_positions[2] < min_z_ + robot_state.getFakeBaseTransform().translation().z() ||
231 | vjoint_positions[2] > max_z_ + robot_state.getFakeBaseTransform().translation().z() )
232 | {
233 | return false;
234 | }
235 | return true;
236 | }
237 |
238 | bool HumanoidStability::isApproximateValidFoot(const robot_state::RobotState &robot_state)
239 | {
240 | if (robot_state.getGlobalLinkTransform(free_foot_).translation().z() < 0)
241 | return false;
242 |
243 | return true;
244 | }
245 |
246 | bool HumanoidStability::isValidCOM(const robot_state::RobotState &robot_state)
247 | {
248 | // Copy robot state to map
249 | for (std::size_t i = 0; i < all_joints_group_->getVariableCount(); ++i)
250 | {
251 | joint_positions_map_[all_joints_group_->getJointModels()[i]->getName()] =
252 | robot_state.getJointPositions(all_joints_group_->getJointModels()[i])[0];
253 | }
254 |
255 | // Run test
256 | bool stable = test_stability_->isPoseStable(joint_positions_map_, support_mode_, normal_vector_);
257 |
258 | bool show_com_makers = false;
259 |
260 | // Publish COM marker
261 | if (verbose_ && show_com_makers)
262 | {
263 | visualization_msgs::Marker com_marker = test_stability_->getCOMMarker();
264 | // Translate to world frame
265 | com_marker.pose =
266 | moveit_visual_tools::MoveItVisualTools::convertPose(moveit_visual_tools::MoveItVisualTools::convertPose(com_marker.pose) *
267 | robot_state.getGlobalLinkTransform(com_marker.header.frame_id));
268 |
269 | // Change frame name to world fame
270 | com_marker.header.frame_id = robot_state.getRobotModel()->getModelFrame(); // odom
271 | com_marker.ns = "COM";
272 | visual_tools_->publishMarker(com_marker);
273 | }
274 |
275 | // Publish footprint polygon
276 | if (verbose_ && show_com_makers)
277 | {
278 | const geometry_msgs::PolygonStamped polygon_msg = test_stability_->getSupportPolygon();
279 |
280 | // Change polygon points to world frame
281 | std::vector points;
282 | for (std::size_t i = 0; i < polygon_msg.polygon.points.size(); ++i)
283 | {
284 | Eigen::Affine3d temp_pose = moveit_visual_tools::MoveItVisualTools::convertPoint32ToPose(polygon_msg.polygon.points[i]);
285 | // TODO make this hard coded, but also fix this whole transforms thing cause it doesn't work right
286 | temp_pose = temp_pose * robot_state.getGlobalLinkTransform("BODY");
287 |
288 | points.push_back( visual_tools_->convertPose(temp_pose).position );
289 | }
290 | points.push_back(points.front()); // connect first and last points for last line
291 |
292 | visual_tools_->publishPath(points);
293 | }
294 |
295 | return stable;
296 | }
297 |
298 | bool HumanoidStability::displayBoundingBox(const Eigen::Affine3d &translation) const
299 | {
300 | if (!visual_tools_)
301 | {
302 | ROS_WARN_STREAM_NAMED("stability","visual tools not loaded");
303 | return false;
304 | }
305 |
306 | geometry_msgs::Point point1;
307 | geometry_msgs::Point point2;
308 | point1.x = max_x_ + translation.translation().x();
309 | point1.y = max_y_ + translation.translation().y();
310 | point1.z = max_z_ + translation.translation().z();
311 | point2.x = min_x_ + translation.translation().x();
312 | point2.y = min_y_ + translation.translation().y();
313 | point2.z = min_z_ + translation.translation().z();
314 |
315 | return visual_tools_->publishRectangle(point1, point2, rviz_visual_tools::TRANSLUCENT);
316 | }
317 |
318 | void HumanoidStability::printVirtualJointExtremes() const
319 | {
320 | std::cout << "Virtual Joint Extremes: " << std::endl;
321 | std::cout << " min_x: " << min_x_ << std::endl;
322 | std::cout << " max_x: " << max_x_ << std::endl;
323 | std::cout << " min_y: " << min_y_ << std::endl;
324 | std::cout << " max_y: " << max_y_ << std::endl;
325 | std::cout << " min_z: " << min_z_ << std::endl;
326 | std::cout << " max_z: " << max_z_ << std::endl;
327 | }
328 |
329 | } // end namespace
330 |
--------------------------------------------------------------------------------
/src/humanoid_constraint_sampler.cpp:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Software License Agreement (BSD License)
3 | *
4 | * Copyright (c) 2014, JSK, The University of Tokyo.
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * * Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | * * Redistributions in binary form must reproduce the above
14 | * copyright notice, this list of conditions and the following
15 | * disclaimer in the documentation and/or other materials provided
16 | * with the distribution.
17 | * * Neither the name of the JSK, The University of Tokyo nor the names of its
18 | * contributors may be used to endorse or promote products derived
19 | * from this software without specific prior written permission.
20 | *
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 | * POSSIBILITY OF SUCH DAMAGE.
33 | *********************************************************************/
34 |
35 | /* Author: Dave Coleman
36 | */
37 |
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 |
44 | namespace moveit_humanoid_stability
45 | {
46 | bool HumanoidConstraintSampler::configure(const moveit_msgs::Constraints &constr)
47 | {
48 | clear();
49 |
50 | //moveit_msgs::Constraints constraints = constr; // copy to non-const
51 |
52 | ROS_DEBUG_STREAM_NAMED("sampler","Configuring humanoid constraint sampler");
53 | //std::cout << "message:\n " << constr << std::endl;
54 |
55 | // Humanoid custom constraints: define here --------------------
56 | moveit_msgs::JointConstraint jc1;
57 |
58 | // construct the joint constraints
59 | std::vector jc;
60 | for (std::size_t i = 0 ; i < constr.joint_constraints.size() ; ++i)
61 | {
62 | kinematic_constraints::JointConstraint j(scene_->getRobotModel());
63 | if (j.configure(constr.joint_constraints[i]))
64 | jc.push_back(j);
65 | }
66 |
67 | // Load visual tools
68 | if (verbose_ || true) // i don't know how to make this any better :-/
69 | {
70 | loadVisualTools();
71 | }
72 |
73 | // Configure stability checker
74 | if (!humanoid_stability_)
75 | humanoid_stability_.reset(new moveit_humanoid_stability::HumanoidStability(verbose_, scene_->getCurrentState(), visual_tools_));
76 |
77 | // If joint constriaints are provided, configure them. otherwise we will use regular random joint sampling
78 | if (jc.empty())
79 | {
80 | sampler_name_ = "No_Joint_Constraints";
81 | logDebug("No joint constraints passed to humanoid constraint sampler");
82 | is_valid_ = true; // set as configured
83 | }
84 | else
85 | {
86 | sampler_name_ = "Has_Joint_Constraints";
87 |
88 | if (!configureJoint(jc))
89 | return false;
90 |
91 | is_valid_ = true; // set as configured
92 | }
93 |
94 | // Temporary vars for loading from param server
95 | std::string whole_body_minus_left_leg = "whole_body_minus_left_leg";
96 | std::string whole_body_minus_right_leg = "whole_body_minus_right_leg";
97 | std::string left_leg = "left_leg";
98 | std::string right_leg = "right_leg";
99 | std::string left_foot = "left_foot";
100 | std::string right_foot = "right_foot";
101 |
102 | // Load other settings from yaml file
103 | static const std::string ROOT_NAME = "humanoid_stability";
104 | ros::NodeHandle nh("~");
105 | nh.getParam(ROOT_NAME + "/whole_body_minus_left_leg_name", whole_body_minus_left_leg);
106 | nh.getParam(ROOT_NAME + "/whole_body_minus_right_leg_name", whole_body_minus_right_leg);
107 | nh.getParam(ROOT_NAME + "/left_leg_name", left_leg);
108 | nh.getParam(ROOT_NAME + "/right_leg_name", right_leg);
109 | nh.getParam(ROOT_NAME + "/left_foot_name", left_foot);
110 | nh.getParam(ROOT_NAME + "/right_foot_name", right_foot);
111 |
112 | // Load the joint model groups and links
113 | whole_body_minus_left_leg_ = scene_->getCurrentState().getRobotModel()->getJointModelGroup(whole_body_minus_left_leg);
114 | whole_body_minus_right_leg_ = scene_->getCurrentState().getRobotModel()->getJointModelGroup(whole_body_minus_right_leg);
115 | left_leg_ = scene_->getCurrentState().getRobotModel()->getJointModelGroup(left_leg);
116 | right_leg_ = scene_->getCurrentState().getRobotModel()->getJointModelGroup(right_leg);
117 | left_foot_ = scene_->getCurrentState().getRobotModel()->getLinkModel(left_foot);
118 | right_foot_ = scene_->getCurrentState().getRobotModel()->getLinkModel(right_foot);
119 |
120 | logInform("%s: Humanoid Constraint Sampler initialized. Bounded: %d, Unbounded: %d", sampler_name_.c_str(), bounds_.size(), unbounded_.size());
121 | return true;
122 | }
123 |
124 | void HumanoidConstraintSampler::loadVisualTools()
125 | {
126 | // Don't load twice
127 | if (visual_tools_ != NULL)
128 | return;
129 |
130 | visual_tools_.reset(new moveit_visual_tools::MoveItVisualTools("/odom", "/humanoid_constraint_sample_markers", scene_->getRobotModel()));
131 | visual_tools_->loadRobotStatePub("/humanoid_constraint_sample_robots");
132 |
133 | // Verbose mode text display setting
134 | text_pose_.position.x = scene_->getCurrentState().getFakeBaseTransform().translation().x();
135 | text_pose_.position.y = scene_->getCurrentState().getFakeBaseTransform().translation().y();
136 | text_pose_.position.z = scene_->getCurrentState().getFakeBaseTransform().translation().z() + 2;
137 | }
138 |
139 |
140 | bool HumanoidConstraintSampler::configureJoint(const std::vector &jc)
141 | {
142 | clear();
143 |
144 | if (!jmg_)
145 | {
146 | logError("NULL planning group specified for constraint sampler");
147 | return false;
148 | }
149 |
150 | // find and keep the constraints that operate on the group we sample
151 | // also keep bounds for joints for convenience
152 | std::map bound_data;
153 | for (std::size_t i = 0 ; i < jc.size() ; ++i)
154 | {
155 | // Check that joint constraint is enabled
156 | if (!jc[i].enabled())
157 | continue;
158 |
159 | // Check that joint constraint has valid joint model
160 | const robot_model::JointModel *jm = jc[i].getJointModel();
161 | if (!jmg_->hasJointModel(jm->getName()))
162 | continue;
163 |
164 | // Get the bounds of this variable
165 | const robot_model::VariableBounds& joint_bounds = jm->getVariableBounds(jc[i].getJointVariableName());
166 |
167 | // Populate the joint info object
168 | JointInfo ji;
169 | // Check if this variable already has bounds set (for some reason_
170 | std::map::iterator it = bound_data.find(jc[i].getJointVariableName());
171 | if (it != bound_data.end())
172 | ji = it->second;
173 | else
174 | ji.index_ = jmg_->getVariableGroupIndex(jc[i].getJointVariableName()); // copy the index of the variable with respect to the joint model group
175 |
176 | // Attempt to tighten the variables bounds if applicable from the constraint
177 | ji.potentiallyAdjustMinMaxBounds(std::max(joint_bounds.min_position_, jc[i].getDesiredJointPosition() - jc[i].getJointToleranceBelow()),
178 | std::min(joint_bounds.max_position_, jc[i].getDesiredJointPosition() + jc[i].getJointToleranceAbove()));
179 |
180 | // Debug
181 | logDebug("Bounds for %s JointConstraint are %g %g", jc[i].getJointVariableName().c_str(), ji.min_bound_, ji.max_bound_);
182 |
183 | // Error check
184 | if (ji.min_bound_ > ji.max_bound_ + std::numeric_limits::epsilon())
185 | {
186 | std::stringstream cs; jc[i].print(cs);
187 | logError("The constraints for joint '%s' have no possible values for the joint: min_bound: %g, max_bound: %g. Failing.\n",
188 | jm->getName().c_str(), ji.min_bound_, ji.max_bound_);
189 | clear();
190 | return false;
191 | }
192 |
193 | // Save this new joint info
194 | bound_data[jc[i].getJointVariableName()] = ji;
195 | }
196 |
197 | // Copy our larger bound data structure into a more compact one
198 | for (std::map::iterator it = bound_data.begin(); it != bound_data.end(); ++it)
199 | bounds_.push_back(it->second);
200 |
201 | // get a separate list of joints that are not bounded; we will sample these randomly
202 | const std::vector &joints = jmg_->getJointModels();
203 | for (std::size_t i = 0 ; i < joints.size() ; ++i)
204 | if (bound_data.find(joints[i]->getName()) == bound_data.end() &&
205 | joints[i]->getVariableCount() > 0 &&
206 | joints[i]->getMimic() == NULL)
207 | {
208 | // check if all the vars of the joint are found in bound_data instead
209 | const std::vector &vars = joints[i]->getVariableNames();
210 | if (vars.size() > 1)
211 | {
212 | bool all_found = true;
213 | for (std::size_t j = 0 ; j < vars.size() ; ++j)
214 | if (bound_data.find(vars[j]) == bound_data.end())
215 | {
216 | all_found = false;
217 | break;
218 | }
219 | if (all_found)
220 | continue;
221 | }
222 | unbounded_.push_back(joints[i]);
223 | // Get the first variable name of this joint and find its index position in the planning group
224 | uindex_.push_back(jmg_->getVariableGroupIndex(vars[0]));
225 | //logInform("Adding variable index %d for joint index %d",jmg_->getVariableGroupIndex(vars[0]), i);
226 | }
227 |
228 | values_.resize(jmg_->getVariableCount());
229 |
230 | return true;
231 | }
232 |
233 | bool HumanoidConstraintSampler::sample(robot_state::RobotState &robot_state, const robot_state::RobotState & /* reference_state */,
234 | unsigned int max_attempts)
235 | {
236 | if (!jmg_)
237 | logError("no joint model group loaded");
238 |
239 | if (!is_valid_)
240 | {
241 | logWarn("HumanoidConstraintSampler not configured, won't sample");
242 | return false;
243 | }
244 |
245 | //logWarn("%s: HumanoidConstraintSampler SAMPLING -----------------------------",sampler_name_.c_str());
246 |
247 |
248 |
249 | if (robot_state.getFixedFoot() == left_foot_)
250 | {
251 | whole_body_minus_fixed_leg_ = whole_body_minus_left_leg_;
252 | fixed_leg_ = left_leg_;
253 | }
254 | else if (robot_state.getFixedFoot() == right_foot_)
255 | {
256 | whole_body_minus_fixed_leg_ = whole_body_minus_right_leg_;
257 | fixed_leg_ = right_leg_;
258 | }
259 | else
260 | {
261 | ROS_ERROR_STREAM_NAMED("temp","Could not match a foot link with the chosen fixed on in RobotState. rosparam may be misconfigured to your URDF");
262 | }
263 |
264 | max_attempts = 100000; // TODO this might be a bad hack
265 |
266 | for (std::size_t attempt = 0; attempt < max_attempts; ++attempt)
267 | {
268 | if (verbose_)
269 | logInform("Sampling attempt number %d for group %s", attempt, jmg_->getName().c_str() );
270 |
271 | if (!ros::ok())
272 | return false;
273 |
274 | if (verbose_)
275 | visual_tools_->deleteAllMarkers();
276 |
277 | // Decide how to sample the joints
278 | bool use_constraint_sampling = false;
279 | // Generate simple movement states
280 | if (false)
281 | {
282 | double lleg_position[1];
283 | lleg_position[0] = robot_state.getJointPositions("LLEG_JOINT1")[0] + 0.01;
284 | robot_state.setJointPositions("LLEG_JOINT1", lleg_position);
285 |
286 | // Update with leg fixed
287 | robot_state.updateStateWithFakeBase();
288 | use_constraint_sampling = true;
289 | }
290 | else if (bounds_.size() > 0)
291 | {
292 | if (verbose_)
293 | ROS_INFO_STREAM_NAMED("sampler","Sampling joints using joint constraints");
294 | use_constraint_sampling = true;
295 |
296 | // Calculate random position of robot
297 | // \todo: don't sample virtual joint orientation and the legs to save time
298 | if (!sampleJoints(robot_state))
299 | {
300 | logError("Unable to sample joints");
301 | return false;
302 | }
303 |
304 | // Update with leg fixed
305 | robot_state.updateStateWithFakeBase();
306 | }
307 | else
308 | {
309 | //ROS_INFO_STREAM_NAMED("temp","Sampling joints using robot state random variables");
310 | // Generate random state for leg only
311 | robot_state.setToRandomPositions(fixed_leg_);
312 |
313 | // Update only the virtual joint and the leg we just updated
314 | robot_state.updateSingleChainWithFakeBase();
315 | }
316 |
317 | if (!humanoid_stability_->isApproximateValidBase(robot_state))
318 | {
319 | if (verbose_)
320 | {
321 | ROS_WARN_STREAM_NAMED("sampler","Sample outside VIRTUAL JOINT constraints");
322 | visual_tools_->publishText(text_pose_, "OUTSIDE virtual joint bounding box", rviz_visual_tools::RED, rviz_visual_tools::LARGE);
323 | ros::Duration(1.1).sleep();
324 | }
325 |
326 | continue; // stop checking
327 | }
328 |
329 | // Is Valid
330 | if (verbose_)
331 | {
332 | visual_tools_->publishText(text_pose_, "Within virtual joint bounding box", rviz_visual_tools::WHITE, rviz_visual_tools::LARGE);
333 | visual_tools_->publishRobotState(robot_state);
334 | ros::Duration(1.1).sleep();
335 | }
336 |
337 | if (!use_constraint_sampling)
338 | {
339 | // Generate remainder of body random state
340 | robot_state.setToRandomPositions(whole_body_minus_fixed_leg_);
341 | robot_state.update(true); // update entire robot using previously computed virtual joint tranform
342 | }
343 |
344 | if (verbose_)
345 | {
346 | visual_tools_->publishRobotState(robot_state);
347 | }
348 |
349 | // Check if the free foot is above ground
350 | if (!humanoid_stability_->isApproximateValidFoot(robot_state))
351 | {
352 | if (verbose_)
353 | {
354 | ROS_WARN_STREAM_NAMED("sampler","Sample outside FREE FOOT ground constraint ");
355 | visual_tools_->publishText(text_pose_, "OUTSIDE free foot ground constraint", rviz_visual_tools::RED, rviz_visual_tools::LARGE);
356 | ros::Duration(1.1).sleep();
357 | }
358 |
359 | continue; // stop checking
360 | }
361 |
362 | // Check COM balance constraints --------------------------------------------------------------
363 | if (!humanoid_stability_->isValidCOM(robot_state))
364 | {
365 | if (verbose_)
366 | {
367 | ROS_WARN("Pose is NOT stable");
368 | visual_tools_->publishText(text_pose_, "NOT stable from center of mass", rviz_visual_tools::RED, rviz_visual_tools::LARGE);
369 | ros::Duration(1.1).sleep();
370 | }
371 | continue;
372 | }
373 |
374 | if (verbose_)
375 | ROS_INFO("Pose is stable");
376 |
377 | bool check_verbose = false;
378 | if (!scene_->isStateValid(robot_state, "", check_verbose)) // second argument is what planning group to collision check, "" is everything
379 | {
380 | if (verbose_)
381 | {
382 | ROS_ERROR_STREAM_NAMED("sampler","Pose not valid (self or enviornment collision)");
383 | visual_tools_->publishText(text_pose_, "NOT valid from self or env collision", rviz_visual_tools::RED, rviz_visual_tools::LARGE);
384 | ros::Duration(1.1).sleep();
385 | }
386 | continue;
387 | }
388 |
389 | // Find min/max
390 | /*min_x_ = std::min(vjoint_positions[0], min_x_);
391 | max_x_ = std::max(vjoint_positions[0], max_x_);
392 |
393 | min_y_ = std::min(vjoint_positions[1], min_y_);
394 | max_y_ = std::max(vjoint_positions[1], max_y_);
395 |
396 | min_z_ = std::min(vjoint_positions[2], min_z_);
397 | max_z_ = std::max(vjoint_positions[2], max_z_);*/
398 |
399 | if (verbose_)
400 | {
401 | visual_tools_->publishText(text_pose_, "Sample VALID!", rviz_visual_tools::WHITE, rviz_visual_tools::LARGE);
402 | ros::Duration(3.0).sleep();
403 | }
404 |
405 | ROS_DEBUG_STREAM_NAMED("sampler","Passed - valid sample found on attempts " << attempt);
406 |
407 | return true;
408 | } // for attempts
409 |
410 | ROS_DEBUG_STREAM_NAMED("sampler","Aborted - ran out of attempts (" << max_attempts << ")");
411 |
412 | return false;
413 | }
414 |
415 | bool HumanoidConstraintSampler::sampleJoints(robot_state::RobotState &robot_state)
416 | {
417 | // sample the unbounded joints first (in case some joint varipables are bounded)
418 | std::vector v;
419 | for (std::size_t i = 0 ; i < unbounded_.size() ; ++i)
420 | {
421 | v.resize(unbounded_[i]->getVariableCount());
422 |
423 | if (false)
424 | logInform("%s: UNCONSTRAINED: Joint number %d named %s with variables %d", sampler_name_.c_str(),
425 | i, unbounded_[i]->getName().c_str(),v.size());
426 |
427 | unbounded_[i]->getVariableRandomPositions(random_number_generator_, &v[0]);
428 |
429 | for (std::size_t j = 0 ; j < v.size() ; ++j)
430 | {
431 | values_[uindex_[i] + j] = v[j];
432 | }
433 | }
434 |
435 | // enforce the constraints for the constrained components (could be all of them)
436 | for (std::size_t i = 0 ; i < bounds_.size() ; ++i)
437 | {
438 | if (false)
439 | logInform("%s: CONSTRAINED: Joint number %d named %s bounds [%f,%f]", sampler_name_.c_str(), bounds_[i].index_,
440 | jmg_->getVariableNames()[ bounds_[i].index_ ].c_str(),
441 | bounds_[i].min_bound_, bounds_[i].max_bound_);
442 |
443 | values_[bounds_[i].index_] = random_number_generator_.uniformReal(bounds_[i].min_bound_, bounds_[i].max_bound_);
444 | }
445 |
446 | robot_state.setJointGroupPositions(jmg_, values_);
447 |
448 | return true;
449 | }
450 |
451 | bool HumanoidConstraintSampler::project(robot_state::RobotState &robot_state,
452 | unsigned int max_attempts)
453 | {
454 | return sample(robot_state, robot_state, max_attempts);
455 | }
456 |
457 | void HumanoidConstraintSampler::clear()
458 | {
459 | ConstraintSampler::clear();
460 | bounds_.clear();
461 | unbounded_.clear();
462 | uindex_.clear();
463 | values_.clear();
464 | }
465 |
466 | void HumanoidConstraintSampler::setVerbose(bool verbose)
467 | {
468 | // Load visual tools
469 | if (verbose)
470 | {
471 | loadVisualTools();
472 | }
473 |
474 | humanoid_stability_->setVerbose(verbose);
475 | }
476 |
477 |
478 | } //namespace
479 |
--------------------------------------------------------------------------------