Skip to content
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

Merged
merged 8 commits into from
Jul 28, 2017
Merged

Modify ikfast_template for getPositionIK single solution results #537

merged 8 commits into from
Jul 28, 2017

Conversation

nsnitish
Copy link
Contributor

@nsnitish nsnitish commented Jun 22, 2017

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?

@davetcoleman
Copy link
Member

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/

Copy link
Member

@davetcoleman davetcoleman left a 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
Copy link
Member

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;
Copy link
Member

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?

Copy link
Contributor Author

@nsnitish nsnitish Jun 26, 2017

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.

Copy link
Member

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?

Copy link
Contributor Author

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;
Copy link
Member

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)
Copy link
Member

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);
Copy link
Member

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;
Copy link
Member

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
Copy link
Contributor

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;
}

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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

@nsnitish
Copy link
Contributor Author

nsnitish commented Jun 30, 2017

@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;
}
}
Copy link
Contributor

@jrgnicho jrgnicho Jun 30, 2017

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.

@nsnitish
Copy link
Contributor Author

@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)
Copy link
Contributor

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)
Copy link
Contributor

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?

Copy link
Contributor Author

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.

@v4hn
Copy link
Contributor

v4hn commented Jul 4, 2017 via email

@nsnitish
Copy link
Contributor Author

nsnitish commented Jul 4, 2017

@v4hn! This PR is specifically meant for getPositionIK. Harmonize function has been already discussed in detail in pull#53. We can further discuss this in some other PR.

@jrgnicho
Copy link
Contributor

jrgnicho commented Jul 4, 2017

@nsnitish I'm OK with merging these changes, lets see what the other reviewers say, thanks for the contribution.

@shaun-edwards
Copy link

@davetcoleman, @v4hn, can this be merged?

@v4hn v4hn changed the title Modifeid ikfast_template for getPositionIK single solution case Modify ikfast_template for getPositionIK single solution results Jul 11, 2017
Copy link
Member

@davetcoleman davetcoleman left a 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
Copy link
Member

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;
Copy link
Member

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;
Copy link
Member

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++)
Copy link
Member

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
Copy link
Member

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)?

Copy link
Contributor

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

Copy link
Contributor

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. :)

@davetcoleman
Copy link
Member

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
Copy link
Contributor

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

@nsnitish
Copy link
Contributor Author

Is the PR for fixing the harmonize function already available, or just in the old moveit_ikfast repo?

@davetcoleman! There isn't any that I know. But PR#53 was closed without resolving the issue.

@nsnitish
Copy link
Contributor Author

@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
Copy link
Contributor

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

Copy link
Member

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

Copy link
Member

@davetcoleman davetcoleman left a 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
Copy link
Member

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

@nsnitish
Copy link
Contributor Author

@davetcoleman !

Looks great except the one struct rename, thanks!!

Already did it in latest commit

@davetcoleman davetcoleman merged commit 45c587d into moveit:kinetic-devel Jul 28, 2017
@davetcoleman
Copy link
Member

Hurray!

@Jmeyer1292
Copy link

@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:

  • We should REALLY try to avoid dynamic mem allocations in these low level IK calls. It's true the library is fast, but this can be a real burden when you do a lot of them.
  • This only appears to apply for 6 DOF robots (e.g. one w/o free parameters). I realize this may be out of your scope, but still.

130s pushed a commit to 130s/moveit-2 that referenced this pull request Aug 7, 2017
…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
@v4hn
Copy link
Contributor

v4hn commented Aug 9, 2017

We should REALLY try to avoid dynamic mem allocations in these low level IK calls. It's true the library is fast, but this can be a real burden when you do a lot of them.

I agree. Do you have concrete proposals to change current upstream?

This only appears to apply for 6 DOF robots (e.g. one w/o free parameters). I realize this may be out of your scope, but still.

I have not worked with >6DOF arms myself. Could you elaborate on this statement please?

@davetcoleman
Copy link
Member

This only appears to apply for 6 DOF robots (e.g. one w/o free parameters). I realize this may be out of your scope, but still.

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.

@Jmeyer1292
Copy link

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.

@davetcoleman
Copy link
Member

I've created an issue for memory allocation in IK solvers: #629

130s pushed a commit to 130s/moveit-2 that referenced this pull request Dec 18, 2017
…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
JafarAbdi pushed a commit to JafarAbdi/moveit that referenced this pull request Mar 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants