Open grandixximo opened 5 years ago
I think that this might be harder to do than it appears. Currently a continuous jog is actually planned as a single continuous move to the axis (or joint) limit. This is how the move stops at the end of travel automatically. When the jog button is released the move is aborted, and the joint(s) decelerate to a stop according to their accel limits. Changing the end-stop position would require the motion to be re-planned, which would probably necessitate an immediate abort and stop, and then for a new move to be started.
What is the application for this requirement? Would a stop and re-start work?
Applications can vary, let's say a tool change that I can only reach from a certain spot, or for managing axis limits of non Trivkins machines like a scara, it's possible to manage with simple Hal components, but the management doesn't work properly if the jog direction is switched too quickly
For the tool changer application, I think it would be more robust to be able to define more complex collision geometry. Instead of just having one overall min / max for each axis, we could define multiple bounding boxes, which combined would define that allowable region for the tool. The same could be done for permanent fixtures (vises, rotary tables, table-mounted toolsetters).
It would be easy to check if the tool position is inside one of the allowed regions (and therefore within limits). However, planning a collision-free path would be harder (but doable); imagine a "U" shaped allowed region, and planning a path between the tips of the "U". The end points would be within limits, but the middle would not.
@grandixximo would this cover your use cases? If so, I'd like to move towards that approach long term, even if we need a stopgap solution using INI pins for now.
Yes exactly, a scara would have a donut shaped limit, where you can't pass from the middle, it would be awesome to be able to be able to define a shape like that or a "U" shaped limit area, where you should know to stop on the tips of the U and not collide.
On Thu, 30 May 2019 at 22:03, Robert W. Ellenberg notifications@github.com wrote:
For the tool changer application, I think it would be more robust to be able to define more complex collision geometry. Instead of just having one overall min / max for each axis, we could define multiple bounding boxes, which combined would define that allowable region for the tool. The same could be done for permanent fixtures (vises, rotary tables, table-mounted toolsetters).
I would suggest the option of an STL limits file. It's pretty easy to check for inside / outside an STL (and is very much a solved problem already). And the normal bounding box is trivial to generate an STL for (even by hand)
-- atp
That would work very well
After a bit of searching, it looks like libccd is the defacto standard for collision detection (used by OpenDE, Bullet Physics, FCL in ROS), which can handle triangle meshes as long as they are convex (non-convex objects could be decomposed into multiple convex ones). Triangle meshes in the form of STL files would definitely be convenient for a user, since they can just model something in CAD and save to STL.
My concern with STL as a base format is that it only lets you define one object. It would be nice to combine multiple objects sometimes, e.g. a vise model as STL, a bounding box for overall limits, a bounding box for a tool changer, etc. For that purpose, something like URDF or VRML is a better fit.
Some other concerns with trimesh collision objects:
TLDR: trimeshes are easy on the user and powerful (complex geometry), but it would be nice to have primitives too for speed and reliability.
On Fri, 31 May 2019 at 14:54, Robert W. Ellenberg notifications@github.com wrote:
My concern with STL as a base format is that it only lets you define one object. It would be nice to combine multiple objects sometimes, e.g. a vise model as STL, a bounding box for overall limits, a bounding box for a tool changer, etc. For that purpose, something like URDF http://wiki.ros.org/urdf or VRML https://en.wikipedia.org/wiki/VRML is a better fit.
I think you are looking at this backwards. Inside the STL defines a valid position. Outside an invalid one. A machine can't have a valid region with non-contiguous volumes as that implies there is no way from one place to another.
-- atp
Sorry, I wasn't clear, you are correct that multiple non-contiguous volumes don't make sense. However, a non-convex volume (e.g. a U-shape) needs to be decomposed into convex volumes to check if a point is in the interior, at least to use the fast algorithms like GJK (which is what libccd does). It's true that our goals is the opposite of a typical collision-check (in that a position is good only if it's "colliding" with a workspace volume), but the algorithm should work just as well.
On Fri, 31 May 2019 at 16:29, Robert W. Ellenberg notifications@github.com wrote:
Sorry, I wasn't clear, you are correct that multiple non-contiguous volumes don't make sense. However, a non-convex volume (e.g. a U-shape) needs to be decomposed into convex volumes to check if a point is in the interior, at least to use the fast algorithms like GJK https://en.wikipedia.org/wiki/Gilbert%E2%80%93Johnson%E2%80%93Keerthi_distance_algorithm (which is what libccd does). It's true that our goals is the opposite of a typical collision-check (in that a position is good only if it's "colliding" with a workspace volume), but the algorithm should work just as well.
I think that our check, though, is exactly the same as the "plastic or air" test that a 3D printer slicer performs. And I think that is just "do I intersect an odd or even number of faces as I travel from here to infinity (and beyond) in an arbitrary direction"
-- atp
That's true, it is the same problem. Do you know of any examples of this algorithm we could look at? I'm curious how efficient it is compared to collision-check algorithms.
On Fri, 31 May 2019 at 18:20, Robert W. Ellenberg notifications@github.com wrote:
That's true, it is the same problem. Do you know of any examples of this algorithm we could look at? I'm curious how efficient it is compared to collision-check algorithms.
I didn't find any with a quick search. But here is one way (I did once write a slicer....)
Let's arbitrarily choose to shine a ray straight up (+Z) from our point of interest.
1) Find all faces where the XY of the point lies inside the triangle formed by the XY of each face vertex. 2) Of those, reject those with all vertices where Z < the point Z 3) Count and then clear from the list all those with all Z > point Z 4) For any remaining faces there is some maths needed to work out whether the projection of the point to the triangular face lies above or below the point, but I can't imagine there would ever be more than a couple of faces that needed that level of analysis.
For interest, the analagous code for my slicer was: Make a list of all faces Reject all those which have all vertices above or below the current plane. Make a list of line segments from the intersection of the plane with two edges of the triangle Assemble the line segments into a closed curve.
I did it in octave, which automatically iterates through lists, but it looked like this (leaving out the assembling of the line segments in the C list into a closed curve)
for z = max(z, zmin):thickness:zmax
disp(z)
I1 = find(sum((Z>z),2) == 1); % Index of faces with 1 vertex
greater than z I2 = find(sum((Z>z),2) == 2); % index of faces with 2 > z
C = [];
for a = 1:length(I1)
[zs i] = sort(Z(I1(a),:)) ;% put biggest Z last, and store
order xs = X(I1(a),i); ys = Y(I1(a),i);
x1 = xs(1)+(xs(3)-xs(1))*(z-zs(1))/(zs(3)-zs(1));
x2 = xs(2)+(xs(3)-xs(2))*(z-zs(2))/(zs(3)-zs(2));
y1 = ys(1)+(ys(3)-ys(1))*(z-zs(1))/(zs(3)-zs(1));
y2 = ys(2)+(ys(3)-ys(2))*(z-zs(2))/(zs(3)-zs(2));
C = [C; x1 y1 x2 y2];
end
for a = 1:length(I2)
[zs i] = sort(Z(I2(a),:)) ;% put biggest Z last, and store
order xs = X(I2(a),i); ys = Y(I2(a),i);
x1 = xs(2)+(xs(1)-xs(2))*(z-zs(2))/(zs(1)-zs(2));
x2 = xs(3)+(xs(1)-xs(3))*(z-zs(3))/(zs(1)-zs(3));
y1 = ys(2)+(ys(1)-ys(2))*(z-zs(2))/(zs(1)-zs(2));
y2 = ys(3)+(ys(1)-ys(3))*(z-zs(3))/(zs(1)-zs(3));
C = [C; x1 y1 x2 y2];
end
-- atp
On Fri, 31 May 2019 at 22:56, Andy Pugh andy@bodgesoc.org wrote:
1) Find all faces where the XY of the point lies inside the triangle formed by the XY of each face vertex.
http://blackpawn.com/texts/pointinpoly/default.html
Bear in mind that the typical machine envelope wouldn't (or shouldn't) be a 20,000,000 face solid model, it will be a 12-face cuboid. One could set a limit. No more than 1000 faces maybe.
It occurs to me that an initial filter might be to determine if the point in XY space lies in the circumcircle of the triangle.
-- atp
@andypugh That does look easy enough to implement, and for small poly counts the overhead of repeated list searches is less important. Of course, I'd want to be careful about boundary conditions (and do pre-processing / mesh checks to avoid degenerate solid). It would also be useful on load to do a quick search through the work envelope to make sure there aren't isolated islands.
Does this generalize to more dimensions (i.e. if we wanted to include ABC to avoid collisions with a tilting head and a vise)?
Are machine limits the place to do collision avoidance with a vise/fixture etc? Isn't that normally done in CAM? I don't have the experience to know, but that's how it seems it might be.
It would be nice to be able to not hit the vise while jogging by mistake, but I was also hoping for a more advanced limit definition for non trivkins machine, like scara puma or 5 axis machines, to be able to jog them more safely near the limits would be a great achievement
@mozmck that's a good point, there's probably diminishing returns trying to model every little detail of a fixture in the machine limits. For a hobby user that's always swapping fixtures, it wouldn't really make sense to model the vise as part of machine limits. For a more specialized setup all-but-permanent vises and chucks on the table, maybe it would?
As I think about it more, I like @andypugh's suggestion of a single STL file (along with coordinate offsets in the INI file). The raycast algorithm looks straightforward enough (and we could lean on a linear algebra library if necessary). For mesh import / cleanup, we could use trimesh2 or something similar.
We could always add support for more complex stuff (e.g. URDF models) later if the need arises.
This is a feature request, with the ability to change limits from the ini pins with hal, the axis limits can be changed while jogging, right now you need to stop the jog and move again to plan the jog with the new limit, it would be cool if the jog would take account of the new limit as it jogs in real time without having to stop.