Trajectory Planner using Ruckig Lib

More
11 Nov 2023 09:02 #285080 by ihavenofish
My thought is for any transition blended with g64, jerk control can be disabled, and then reenabled for any move that does not blend. I assume there is some what to determine which transitions get blended and nix them from the function.

Jerk limited blending can come later, as I assume it is a MUCH harder thing to do. SOME jerk control is better than no jerk control, so don't get sucked into adding it for every feature. That is why I think a lot of past efforts failed.
The following user(s) said Thank You: Grotius

Please Log in or Create an account to join the conversation.

More
13 Nov 2023 10:38 #285247 by Grotius
@Grotius - I am guessing that the TP is not doing any kind of blending on these corners and using G64 to generate any intermediate points to soften the change in direction.  The ruckig lib does not seem to do that blending for us.  We ask for postion x,y,z and it gives us the jerk constrained set of points and accerl/vel to get there. If we want some smoothing to happen I presume the TP needs to do that before feeding target states to ruckig.  A bit of a laymans description but hopefully makes some sense.

No blending is done. Blending could be done later on. For plasma i never used blending, always followed the exact path.

Ruckig is given a target position. When it's running to the target position, the velocity max may be modified.
This is like moving the velocity slider in axis.

When segments are colineair within 10 degrees (this is a path rule), the target position
is the sum of the colineair segments. So you can change the pathrule's yourself in the source file at the moment.

When user request's a pause, ruckig is changed from position mode to velocity mode and will run to velocity=0.
I think the pause behaviour at sharp corners could be limited by using different jerk & acceleration values.
In theory the velocity end should be 0 at a 90 degrees corner. Using a velocity end can be done later on.

We don't ask for a xyz position. The planner is just one dof(1) for target position. The xyz is the outcome of 0-1% path progress.

Currently I can not run the file more than once.
When the program is finished in axis, you can run it again with pressing the "arrow-right" button (right side from start), then press "pause-resume."

I think the video is ok for now.
The following user(s) said Thank You: tivoi

Please Log in or Create an account to join the conversation.

More
13 Nov 2023 18:22 #285290 by Joco

We don't ask for a xyz position. The planner is just one dof(1) for target position. The xyz is the outcome of 0-1% path progress

Think I need a little help with this line. I have been investing time looking at ruckig example code, the standard planner and the skynet scurve planner to get my head around the code base so I can try some things.

1. “We don’t ask for xyz powition” - which flows on to the dof comment.  Given we are working in 3d space how does that work? It looked like ruckig was sorting all that out based on an a 3d space target and on each time slice it returned a new progression in 3d to that target and a return status of Done or Working.

2. “… the outcome of 0-1% path  progress” - is this reflecting the time slice element? I can recall a constant of 0.001 being aet that was (i thought) something to do with that.

On the topic of the pauses - given the difference in morion behaviour between a “square” with a small chamfer or arc replacing the 90deg corner v’s a  pure square with true 90deg corner, there are some choices.
a. The user needs to design geometry to achieve desired behaviour from the planner.
b. The CAM path software drives paths that avoid hard corners. e.g loop or triangle over cutting  on external corners
c. Path following tolerance between geometry elements allows for some blending and thus on the fly addition of new target points within tolerances that soften harsh transitions which would otherwise introduce these pauses.

a and b are probably the more correct approach but c could be a nice back stop.   It would be interesting to know what the expectation is on commercial machines with these types of scurve planners already in place. 

Cheers - J
The following user(s) said Thank You: Grotius

Please Log in or Create an account to join the conversation.

More
13 Nov 2023 18:47 - 13 Nov 2023 18:56 #285299 by TheRoslyak
Hello everyone.
I decided to join the discussion. I'm currently trying to construct a trajectory with acceleration and deceleration, but I'm burnt out for today. Generally, I wanted to know what advantages this library offers. Let's say I'm trying to divide a segment into 7 parts. First, I divide it into 3 parts: acceleration, constant motion, and deceleration. Then I take the acceleration or deceleration segment and divide it into 3 parts: initial jerk, linear segment, and final jerk. Accordingly, with zero jerk, the time for this segment equals speed divided by acceleration. At 100% jerk, this time is twice as long, and consequently, I have no linear segment. With this logic, I'm trying to build the graphs. I will show part of the code for now. I can upload the entire project later. I have the following questions: How is the use of this library better than the approach I've described above? And the second point, what parameters can I set using this library, apart from speed, acceleration, and the magnitude of jerk? Is it possible to change the duration of the jerk? Can these values be set separately for the acceleration and deceleration phases?
MotionData SCurveTp::calculateMotion(double maxSpeed, double acceleration, double jerkTimePercentage) {
    MotionData data;
    double distance = 100.0; // Total driving distance

    // Calculation of the total acceleration and deceleration time without taking into account jerk
    double baseTimeAcceleration = maxSpeed / acceleration;
    double jerkTime = baseTimeAcceleration * (jerkTimePercentage / 100.0);

    // Total time for acceleration and deceleration phase including jerk
    double totalTimeAcceleration = baseTimeAcceleration + 2 * jerkTime;
    double totalTimeDeceleration = totalTimeAcceleration;

    // Calculation of time and distance for the constant speed phase
    double distanceAcceleration = 0.5 * acceleration * pow(totalTimeAcceleration - jerkTime, 2) + acceleration * jerkTime * (totalTimeAcceleration - 0.5 * jerkTime);
    double distanceDeceleration = distanceAcceleration;
    double distanceConstantSpeed = distance - (distanceAcceleration + distanceDeceleration);
    double timeConstantSpeed = distanceConstantSpeed / maxSpeed;

    // Total driving time
    double totalTime = totalTimeAcceleration + timeConstantSpeed + totalTimeDeceleration;

    double currentSpeed = 0.0, currentPosition = 0.0, currentAcceleration = 0.0, currentJerk = 0.0;
    double timeStep = 0.01; // Time step




    for (double t = 0; t <= totalTime; t += timeStep) {
        // Determining the current phase of movement
        if (t < jerkTime) {
            currentJerk = acceleration / jerkTime;
            currentAcceleration += currentJerk * timeStep;
        } else if (t < totalTimeAcceleration - jerkTime) {
            currentJerk = 0;
            currentAcceleration = acceleration;
        } else if (t < totalTimeAcceleration) {
            currentJerk = -acceleration / jerkTime;
            currentAcceleration += currentJerk * timeStep;
        } else if (t < totalTimeAcceleration + timeConstantSpeed) {
            currentJerk = 0;
            currentAcceleration = 0;
            currentSpeed = maxSpeed;
        } else if (t < totalTime - totalTimeDeceleration + jerkTime) {
            currentJerk = -acceleration / jerkTime;
            currentAcceleration += currentJerk * timeStep;
        } else if (t < totalTime - jerkTime) {
            currentJerk = 0;
            currentAcceleration = -acceleration;
        } else {
            currentJerk = acceleration / jerkTime;
            currentAcceleration += currentJerk * timeStep;
        }
        // Calculate speed and position


        currentSpeed += currentAcceleration * timeStep;
        currentPosition += currentSpeed * timeStep;

        // Speed ​​and Position Limit
        if (currentSpeed > maxSpeed) currentSpeed = maxSpeed;
        if (currentSpeed < 0) currentSpeed = 0;
        if (currentPosition > distance) currentPosition = distance;

        // Adding data to lists
        data.trajectory.append(QPointF(t, currentPosition));
        data.velocity.append(QPointF(t, currentSpeed));
        data.acceleration.append(QPointF(t, currentAcceleration));
        data.jerk.append(QPointF(t, currentJerk));
    }
    double t=totalTime;
    // If the total time is less than the maximum time, fill in the remaining time
    while (t < 100.0) {
        currentSpeed = (t >= totalTime) ? 0.0 : currentSpeed; // Speed ​​0 after end of movement
        currentAcceleration = (t >= totalTime) ? 0.0 : currentAcceleration; // Acceleration 0 after end of movement
        currentJerk = (t >= totalTime) ? 0.0 : currentJerk; // Jerk 0 after movement ends

        data.trajectory.append(QPointF(t, currentPosition));
        data.velocity.append(QPointF(t, currentSpeed));
        data.acceleration.append(QPointF(t, currentAcceleration));
        data.jerk.append(QPointF(t, currentJerk));

        t += timeStep;
    }
    return data;
}
For now, I'll upload part of the code. I can upload the full project tomorrow. Maybe someone will be able to comment on it
Last edit: 13 Nov 2023 18:56 by TheRoslyak.
The following user(s) said Thank You: Grotius

Please Log in or Create an account to join the conversation.

More
13 Nov 2023 19:59 #285310 by Grotius
@Joco,

1. “We don’t ask for xyz powition” - which flows on to the dof comment.  Given we are working in 3d space how does that work? It looked like ruckig was sorting all that out based on an a 3d space target and on each time slice it returned a new progression in 3d to that target and a return status of Done or Working.

It's in fact made as simple as possible.

Given a trajectory of just one line segment:
startpos xyz : 0,0,0
endpos xyz : 100,0,0

total calculated lenght xyz : 100

The trajectory planner then starts the ruckig with the following inputs:
curpos=0
tarpos=100
After the planner  is started, it gives for every 0.001 seconds a new position, vel, acc until tarpos is reached, this
is ruckig::finished flag = 1.

Line interpolation 0-1 in 3d space:
if the curpos=50, this is 50/100=0.5 progress of traject lenght.

2. “… the outcome of 0-1% path  progress” - is this reflecting the time slice element? I can recall a constant of 0.001 being aet that was (i thought) something to do with that.
I made the sum off all segments paths a progress between 0 and 1.
So the 3d coordinates of the tp are somewhere between the interpolation of 0 and 1 progress.
This makes the conversion from current tp to 3d coordinates very easy.

On the topic of the pauses - given the difference in morion behaviour between a “square” with a small chamfer or arc replacing the 90deg corner v’s a  pure square with true 90deg corner, there are some choices.
a. The user needs to design geometry to achieve desired behaviour from the planner.
b. The CAM path software drives paths that avoid hard corners. e.g loop or triangle over cutting  on external corners
c. Path following tolerance between geometry elements allows for some blending and thus on the fly addition of new target points within tolerances that soften harsh transitions which would otherwise introduce these pauses.


a. The behaviour of the planner lies in it's applied path rules. There are now a few applied path rules, like,
  • stop at g0, looking 10 lines ahead.
  • colinear segments within 10 degrees, full trottle ahead, looking that path rule ahead for 10 lines.
b. I think not relevant. Hard corners are normal.
c. This should be implemented as blending. Create blending is not that difficult. It's not handy to do now.
Usage of a ve (velocity end) on 90 degrees corners, could be implemented as a acceptable inertia tollerance
on the machine body and moving parts with max_gforce as input value.

It would be interesting to know what the expectation is on commercial machines with these types of scurve planners already in place. 
Yes, more info is alway's welcome.

@TheRoslyak,
It's quite difficult to get a nice algo going for all circumstances.
You can look at sigmoid or scurve algo's.
If your algo is running, you could show a print of the produced curve, wich is always interesting.

@All,
Currently almost finished the hal integration of the latest ruckig-dev code.
Made a c interface for it.

Soon going to test some waypoints using vo and ve values > 0.
This all is tested in a new hal component called : Cyberdyne

Git is updated.
The following user(s) said Thank You: Joco

Please Log in or Create an account to join the conversation.

More
13 Nov 2023 21:28 #285313 by TheRoslyak
Hi Grotius, Best regards
Tomorrow I'll upload the entire project and its images. Generally, I'm not very satisfied with the final result. It works, of course, but with some set of parameters, it doesn't work quite as I would like. Perhaps this library already has solutions and other aspects that I'm unaware of. For now, briefly, I'm interested in how this library saves time. Does it find the ideal trajectory in the shortest possible time by some esoteric aspects? :)

Please Log in or Create an account to join the conversation.

More
13 Nov 2023 22:57 #285321 by Grotius
@TheRoslyak,

I'm interested in how this library saves time.
It does not save time. Trapezium has the same trajectory time, normally.

Does it find the ideal trajectory in the shortest possible time by some esoteric aspects? :)
Yes, it does. It's doing a good job.
The following user(s) said Thank You: tommylight

Please Log in or Create an account to join the conversation.

More
14 Nov 2023 02:33 #285329 by Joco
@Grotius,

I think you are gonna have to spell things out a bit more for me.  Or point me towards some reading that will achieve the same thing.

"Given a trajectory of just one line segment:
startpos xyz : 0,0,0
endpos xyz : 100,0,0

total calculated lenght xyz : 100

The trajectory planner then starts the ruckig with the following inputs:
curpos=0
tarpos=100"

What I do not understand is how it works when you have a start point of 10,33,55 and an end point of 100,15,25 how is that getting simplified into a single axis?
Or have you dropped things in your example and the inputs are really
curpos=0,0,0
tarpos=100,0,0


"After the planner  is started, it gives for every 0.001 seconds a new position, vel, acc until tarpos is reached, this
is ruckig::finished flag = 1."

I understand the finished/working flag and the call frequency.  the 0.001 seconds make sense.

"I made the sum off all segments paths a progress between 0 and 1.
So the 3d coordinates of the tp are somewhere between the interpolation of 0 and 1 progress.
This makes the conversion from current tp to 3d coordinates very easy."

So are you just dividing the current rolling total of a number of segments by the sum of them all.  i.e effectively a percentage completed?
I presume segment paths are all vectors of x,y,z in this instance?

Thanks - J.
 

Please Log in or Create an account to join the conversation.

More
14 Nov 2023 11:35 #285364 by Grotius
What I do not understand is how it works when you have a start point of 10,33,55 and an end point of 100,15,25 how is that getting simplified into a single axis?

Ok, hold on :

1. A function that the interpreter calls, to fill our gcode buffer (std::vector).
Here we get the 3d startpoint & 3d endpoint, and some other data, like speed.
Also we calculate the 3d path lenght between start- & endpoint to store in our buffer. (std::vector).
In fact we know enough now, to go further on. After the function call's of the interpreter stop's, our program
may begin it's path.
interpreter calls this function to give us the gcode

2. The function call to calculate line lenght. to store in our std::vector.
pathlenght for the 3d line

3. In c++ we call this adding the line to our vector, push_back on the queueu.
I don't use any c style vectors in the code, i use c++ to store data. The c++ std::vector is quite easye to handle.
add the line to the vector, cq gcode queue

4. Ruckig looks in the std::vector buffer and just start's with the first element. When the first element scurve is
done, second element is processed.
ruckig update function

5. The gui needs to know what position we are. The gui is using this function to determine the 3d position.
It's given the traject lenght and it's given where we are on the traject between 0-1.
Then the function can calculate wich segment & segment progress along. This exact point is then interpolated 3d
with  this function.
gui update function that gives the tp loctation in 3d


I presume segment paths are all vectors of x,y,z in this instance?
Point 1. For every item, line or arc, i call them segments in this case. The segments is a paper that holds multiple
data, like startpoint, endpoint, radius, speeds, abc, uvw data, etc.
So you can ask the segment, for one of these values.

So the ruckig doesn't know anything about 3d coordinates. It's only aware of colineair points where it has to go to.
These colineair points, are the endpoints of pathlenghts, stacked after each other.

we know:
line a {0,0,0},{100,0,0}
line b {100,0,0},{-100,0,0}
line c {-100,0,0},{1000,0,0}

ruckig knows:
0
100
300
1400

Ruckig gives the 0-1% progress for the item nr a,b or c.
Interpolate that 3d and done.



 
The following user(s) said Thank You: tommylight, Joco

Please Log in or Create an account to join the conversation.

More
14 Nov 2023 19:57 - 14 Nov 2023 20:00 #285414 by Grotius
Hi All.

Until now the trajectory planner didn't use velocity ends.

This is because of a ruckig online trajectory calculation problem.
Using ruckig inside the so called control loop, it refuses to finish at a given velocity end value.
It misses the point completely and goes in bouncing mode.
So that's why we coded no velocity end's other than zero 0.
The issue could be on purpose to avoid people to use waypoint's. I don't know. I planned to hack ruckig within
a few hours to solve the problem.

To get it running, i did some research yesterday and today, i managed to get it going using velocity ends.

All build in a seperate linuxcnc hal module, so everyone can play with it.

It uses the latest ruckig-dev source code. That's now added to the repository inside the ~/vendor dir.

The procedure is now little different then we used to do.
The trajectory is calculated in a offline manner, and used in a online manner, this works.
So if a interupt is done, like a velocity max change, we trigger this event, and new trajectory is calculated on the fly.

cyberdyne.c component
The component can be used in auto mode, then it run's a few waypoints, but also manual mode, with hal inputs are possible.

Test video using waypoints and velocity ends :

Last edit: 14 Nov 2023 20:00 by Grotius.

Please Log in or Create an account to join the conversation.

Time to create page: 0.130 seconds
Powered by Kunena Forum