LinuxCNC / linuxcnc

LinuxCNC controls CNC machines. It can drive milling machines, lathes, 3d printers, laser cutters, plasma cutters, robot arms, hexapods, and more.
http://linuxcnc.org/
GNU General Public License v2.0
1.82k stars 1.17k forks source link

Limits look ahead accounting for limits changes from ini.axis pins #573

Open grandixximo opened 5 years ago

grandixximo commented 5 years ago

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.

andypugh commented 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?

grandixximo commented 5 years ago

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

robEllenberg commented 5 years ago

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.

grandixximo commented 5 years ago

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.

andypugh commented 5 years ago

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

grandixximo commented 5 years ago

That would work very well

robEllenberg commented 5 years ago

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.

andypugh commented 5 years ago

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

robEllenberg commented 5 years ago

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.

andypugh commented 5 years ago

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

robEllenberg commented 5 years ago

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.

andypugh commented 5 years ago

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

andypugh commented 5 years ago

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

robEllenberg commented 5 years ago

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

mozmck commented 5 years ago

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.

grandixximo commented 5 years ago

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

robEllenberg commented 5 years ago

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