-
Notifications
You must be signed in to change notification settings - Fork 957
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modify ikfast_template for getPositionIK single solution results #537
Conversation
Please fix the formatting issues so that it passes the test. Note we have an auto-formatter available: http://moveit.ros.org/documentation/contributing/code/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a good contribution, thanks so much! I'd like someone else to review it also - perhaps @gavanderhoorn can weight in?
@@ -180,7 +180,7 @@ class IKFastKinematicsPlugin : public kinematics::KinematicsBase | |||
* @return True if a valid solution was found, false otherwise | |||
*/ | |||
|
|||
// Returns the first IK solution that is within joint limits, this is called by get_ik() service | |||
// Returns the IK solution that is within joint limits closest to ik_seed_state, this is called by get_ik() service |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is legacy code that you aren't involved in, but could you remove the comment ", this is called by get_ik() service" - that is referring to some really old code that no longer exists
} | ||
return dist_sqr; | ||
return dist_abs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you elaborate in your PR description what these changes are for? was this harmonize()
function not being used previously? was it this broken?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add the comment explaining this. Actually, this function harmonize wasn't written correctly. I think the the solution output from solve(frame, vfree, solutions) as well as seed input can be something out of range (not between -pi to pi). So, this function transforms the solution in the range(-pi to pi) and finds its L1 norm from the transformed seed value.
Originally, this function was not being used. But I found it useful in my implementation. So, I finally modified this because it was running on wrong definition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nsnitish: could you take a look at moveit/moveit_ikfast#53?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exactly what I am talking about. It had wrong definition. Now it makes more sense and I have also added a new PR which tests for the getPositionIK call for closest solution to seed. So, Indirectly this test is testing the harmonize function as well. But adding an explicit test for this can be helpful.
// Among the solutions under limits, find the one that is closest to ik_seed_state | ||
if (solutions_obey_limits.size() != 0) | ||
{ | ||
double mindist = DBL_MAX; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in moveit we prefer std::numeric_limits<double>::max()
int minindex = -1; | ||
std::vector<double> sol; | ||
|
||
for (size_t i = 0; i < solutions_obey_limits.size(); ++i) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::size_t please
{ | ||
sol = solutions_obey_limits[i]; | ||
double dist = harmonize(ik_seed_state, sol); | ||
ROS_INFO_STREAM_NAMED("ikfast", "Dist " << i << " dist " << dist); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should probably be ROS_DEBUG
right?
if (solutions_obey_limits.size() != 0) | ||
{ | ||
double mindist = DBL_MAX; | ||
int minindex = -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you make these variables use underscore e.g. min_index
?
getSolution(solutions, s, solution); | ||
error_code.val = moveit_msgs::MoveItErrorCodes::SUCCESS; | ||
return true; | ||
// All elements of thi solution obey limits |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo "// All elements of thi solution obey limits`"
error_code.val = moveit_msgs::MoveItErrorCodes::SUCCESS; | ||
return true; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd approach this by sorting the solutions in ascending order using sort and returning the first element from the sorted solutions vector. This could be useful in the getPositionIK
that returns multiple solutions. This is only a suggestion, I'm OK with your method too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @jrgnicho ! What are the expectations from the getPositionIK call for multiple solutions? Am I being over-concerned about scanning the list of solutions in O(n) and not sorting them in n*logn?
I mean does this complexity make any difference? Because this was the only reason I didn't try sorting the elements. If it doesn't matter, I think your approach will be really beneficial and I will do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we're only going to be sorting a handful of solution I don't think the performance hit is of much concern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the sort for solutions for getPositionIK with single solution but haven't modified the getPositionIK that returns multiple solutions. Lets leave this for some other PR
@davetcoleman @gavanderhoorn @shaun-edwards Can you please have a look and review? |
dists[j] = dists[j + 1]; | ||
dists[j + 1] = temp_dist; | ||
swap_flag = true; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think your sorting code would look cleaner if you were to use the sort algorithm with a predicate function that compares the distances of each argument to the seed. This will do though.
@davetcoleman! According to this PR, the getPositionIK gives the solution between (-pi to pi). A robust implementation will have solutions between the joint bounds. I am thinking to further work on it. Should I file a different PR for that when I am done or is it worth adding it to this PR Itself? |
{ | ||
ss[i] -= 2 * M_PI; | ||
} | ||
while (ss[i] < -1 * M_PI) | ||
while (ss[i] < 2 * M_PI) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be -2?
{ | ||
ss[i] += 2 * M_PI; | ||
} | ||
while (solution[i] > M_PI) | ||
while (solution[i] > 2 * M_PI) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this while loop a repeat of the while loop at the top?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initially when I filed this PR, I had modified the harmonize function to be used in getPositionIK but I modified getPositionIK to remove its dependency on harmonize function. In current commit, It is the original harmonize function which is not in good condition as referred in pull#53.
So, harmonize isn't part of this PR anymore. It will be good if you can review the current commit.
On Mon, Jul 03, 2017 at 02:24:19PM -0700, nsnitish wrote:
Initially when I filed this PR, I had modified the harmonize function to be used in getPositionIK
but I modified getPositionIK to remove its dependency on harmonize function.
why did you do that? If the harmonize function does not work correctly (and I guess that's the case...)
this should be fixed too, right?
|
@nsnitish I'm OK with merging these changes, lets see what the other reviewers say, thanks for the contribution. |
@davetcoleman, @v4hn, can this be merged? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really glad this is getting fixed... its been a documented bug since at least 2013!
https://sourceforge.net/p/usarsimros/wiki/IKFast/
return false; | ||
} | ||
|
||
// Check if seed is in bound |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great error checking!
@@ -1019,11 +1040,15 @@ bool IKFastKinematicsPlugin::getPositionIK(const geometry_msgs::Pose& ik_pose, c | |||
|
|||
IkSolutionList<IkReal> solutions; | |||
int numsol = solve(frame, vfree, solutions); | |||
std::vector<std::vector<double>> solutions_obey_limits; | |||
std::vector<double> dists; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you use a more descriptive var name here like dists_from_seed
?
@@ -1019,11 +1040,15 @@ bool IKFastKinematicsPlugin::getPositionIK(const geometry_msgs::Pose& ik_pose, c | |||
|
|||
IkSolutionList<IkReal> solutions; | |||
int numsol = solve(frame, vfree, solutions); | |||
std::vector<std::vector<double>> solutions_obey_limits; | |||
std::vector<double> dists; | |||
bool solution_found = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than this extra bool, why not just check !solutions_obey_limits.empty()
?
} | ||
|
||
// Check if seed is in bound | ||
for (unsigned int i = 0; i < ik_seed_state.size(); i++) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use std::size_t
per moveit style guidelines
@@ -1060,13 +1093,41 @@ bool IKFastKinematicsPlugin::getPositionIK(const geometry_msgs::Pose& ik_pose, c | |||
ROS_DEBUG_STREAM_NAMED("ikfast", "No IK solution"); | |||
} | |||
|
|||
// Sort the solutions under limits and find the one that is closest to ik_seed_state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i believe this is bubble sort O(n^2)... the worse case performance? how about wrap the dists
and solutions_obey_limits
into a common struct
, then use std::sort for a clean and optimal O(nlogn)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this isn't even correct bubble sort: The swap_flag
is never read. You could add a while (swap_flag)
around the whole thing, making it O(n^3). Alternatively, Wikipedia has an O(n^2) implementation of bubble sort. But I think I like the std::sort suggestion best. g
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On second thought, the implementation might be correct, and swap_flag
was only intended as an optimization... anyway, why waste brain cycles, let's just use std::sort. :)
Is the PR for fixing the harmonize function already available, or just in the old moveit_ikfast repo? |
@@ -1060,13 +1093,41 @@ bool IKFastKinematicsPlugin::getPositionIK(const geometry_msgs::Pose& ik_pose, c | |||
ROS_DEBUG_STREAM_NAMED("ikfast", "No IK solution"); | |||
} | |||
|
|||
// Sort the solutions under limits and find the one that is closest to ik_seed_state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this isn't even correct bubble sort: The swap_flag
is never read. You could add a while (swap_flag)
around the whole thing, making it O(n^3). Alternatively, Wikipedia has an O(n^2) implementation of bubble sort. But I think I like the std::sort suggestion best. g
@davetcoleman! There isn't any that I know. But PR#53 was closed without resolving the issue. |
@davetcoleman ! Please have a look. |
ROS_DEBUG_STREAM_NAMED("ikfast", "Found " << numsol << " solutions from IKFast"); | ||
|
||
// struct for storing and sorting solutions | ||
struct limit_obeying_sol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This struct name may not be following the naming convention
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to LimitObeyingSol
as name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great except the one struct rename, thanks!!
ROS_DEBUG_STREAM_NAMED("ikfast", "Found " << numsol << " solutions from IKFast"); | ||
|
||
// struct for storing and sorting solutions | ||
struct limit_obeying_sol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to LimitObeyingSol
as name
Already did it in latest commit |
Hurray! |
@nsnitish Thanks for taking up the torch on this issue. I realize it's too late but I'd thought I would throw in some thoughts:
|
…eit#537) * Modifeid ikfast_template for getPositionIK single solution case * Corrected the harmonize definition * Formated according to style guide and few typos * Sort the solutions before returning closest * Removed the dependency of getPositionIK from harmonize * Removed the dependency of getPositionIK from harmonize * Used std::sort for solution sorting * Changed struct name for storing and sorting the solutions
I agree. Do you have concrete proposals to change current upstream?
I have not worked with >6DOF arms myself. Could you elaborate on this statement please? |
IKFast is limited to 6dof or less, but the MoveIt! plugin for IKFast will iteratively search the 7th joint for a solution if you have 7dof robot. |
I understand that. I was attempting to make a point about how the function changed is only called in the event we don't have the 7th axis. Though you are correct that the default behaviour, OPTIMIZE_MAX_JOINT, will produce equivalent results because of the search. I overlooked that when I made my comment earlier. You'll still get flips if you use the other behaviour, however, not that its likely. |
I've created an issue for memory allocation in IK solvers: #629 |
…eit#537) * Modifeid ikfast_template for getPositionIK single solution case * Corrected the harmonize definition * Formated according to style guide and few typos * Sort the solutions before returning closest * Removed the dependency of getPositionIK from harmonize * Removed the dependency of getPositionIK from harmonize * Used std::sort for solution sorting * Changed struct name for storing and sorting the solutions
Description
IKfast moveit plugin is expected to return the solution (when called with getPositionIK(ik_pose, ik_seed_state, solution, error_code,options)) which is closest solution to the ik_seed_state. Originally, the code was returning the first solution it could find. Modified the template to return the closest solution satisfying the joint limits after harmonizing it(returning the solution between -pi to pi).
@shaun-edwards! Can you please have a look?