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

Nav2 Velocity Smoother #2633

Closed
vinnnyr opened this issue Oct 20, 2021 · 40 comments
Closed

Nav2 Velocity Smoother #2633

vinnnyr opened this issue Oct 20, 2021 · 40 comments

Comments

@vinnnyr
Copy link
Contributor

vinnnyr commented Oct 20, 2021

#2631 will remove acceleration / deceleration limits from RPP due to some issues. With the idea that these kind of things should be handled by a downstream velocity smoother anyways.

Is there a home for a velocity smoother in Nav2, either as a tutorial, or a full implementation?

This proposed smoother could set (this list is just an initial set of ideas):

  • acceleration limit
  • deceleration limit
  • jerk limit
  • velocity deadband (do not command a velocity between x1 m/s and x2 m/s)
@vinnnyr
Copy link
Contributor Author

vinnnyr commented Oct 20, 2021

On another note, I am not sure why this issue did not pre-populate with the issue template -- perhaps bc I am using the iOS app... Apologies, I will edit to fit the template soon as possible.

@SteveMacenski
Copy link
Member

https://github.com/yujinrobot/yujin_ocs/tree/devel/yocs_velocity_smoother this is what I've used in previous projects in ROS 1, but not sure if this or another (better) version is available in ROS 2. I think its a fabulous idea for us to have a reference on in Nav2. Do you have any suggestions of options or techniques? Applying kinematic constraints isn't rocket science (see code I linked above) but not sure if there's some additional ideas.

Also, adding in a "if no command after X time, send 0" in case there's poorly implemented robot base controllers without timeout sequences.

No worries on the template

@SteveMacenski
Copy link
Member

Options to look at for porting / listing features to get the best of all worlds

They all appear to be derivative though, so not much difference between them (at first glance).

@SteveMacenski
Copy link
Member

SteveMacenski commented Oct 22, 2021

Some requirements

  • Limit to kinematics of the robot platform (accel / decel, velocities, angular/linear), including min deadband
  • Timeout zero command
  • Jerk limitation, though I don't see any examples doing this (?)
  • Support X and X/Y velocity base types

@dpm-seasony
Copy link
Contributor

I've been testing https://github.com/kobuki-base/velocity_smoother with good results.

  • The kinematic limits seem to work well.
  • Timeout to zero command also works fine.
  • There doesn't seem to be any jerk limitation.
  • I have only tested with X velocity base type.

The code is mostly ready to be used in galactic, I only had to do some minor modifications to have it working.

@SteveMacenski SteveMacenski changed the title Reference Velocity Smoother Nav2 Velocity Smoother Oct 25, 2021
@SteveMacenski
Copy link
Member

SteveMacenski commented Oct 25, 2021

I wouldn't be opposed to adopting that in Nav2 (with obvious code quality / styling changes). I think the big thing would be to look over the other methods and make sure this is the "best" of them or if there are features the others have, we adopt those into the port (e.g. support omni).

Is jerk limiting important to you? I know this is a usual need for manipulation and high-speed driving. I certainly wouldn't mind adding it, but I would suspect the data in most mobile robot motors is too noisy at the speeds we run at to be meaningfully smoothed to a 3rd derivative. But I could be totally wrong and definitely not opposed if there's a need.

The steps here

  • read all implementations / methods available and come with a list of features or methods
  • Pick one to base off of and migrate to ROS 2 and styling (or just start from scratch)
  • Add in features / methods / changing data structures / etc
  • Adding test coverage, readme, and website documentation

This is honestly a nice, compact project for a student or company that had a need for such a thing and wanted to help make the contribution. This is also something I could commit to working on at some point next year (or over the holidays as a toy project on the plane rides home) if there wasn't external contributor interest. I think this is a good add for Nav2 to bring more basic navigation capacity 'in house'.

@vinnnyr
Copy link
Contributor Author

vinnnyr commented Oct 26, 2021

Yeah Jerk Limiting is important for us, although not as important as the deadband issue.

I would suspect the data in most mobile robot motors is too noisy at the speeds we run at to be meaningfully smoothed to a 3rd derivative

I don't think this is an issue because the velocity smoother is being applied to the commanded velocities, not the measured ones from the robot. In theory you won't have to take 3rd derivatives of noisy mobile base motor data, or am I missing something?

@SteveMacenski
Copy link
Member

Aren't most of those taking odometry messages https://github.com/kobuki-base/velocity_smoother/blob/devel/src/velocity_smoother.cpp#L161 to check and limit the next velocity command by? That would make most sense to me.

@wilcobonestroo
Copy link
Contributor

Aren't most of those taking odometry messages https://github.com/kobuki-base/velocity_smoother/blob/devel/src/velocity_smoother.cpp#L161 to check and limit the next velocity command by? That would make most sense to me.

I see that the Kobuko package has 3 options for input: none, odometry and commanded velocities. Odometry makes sure that the new cmd_vel value is within bounds compared to the currently estimated odometry. The commanded velocities looks at the previous cmd_vel that was send and assumes that the robot follows these commands. I don't understand the none option yet, but I will have a look at their code to see what it actually does. I think it makes sense to at least have the options for odom and for commanded velocities as input.

In the three implementations mentioned above I only see speed limits and acceleration limits. I think we can add jerk limits as an option.

@vinnnyr Can you describe some use cases or scenarios where you use the deadband issue? E.g. what are typical values? Is there one band or multiple? What should happen if the orginal cmd_vel is in the deadband?

I can pick up this issue and work on a nav2 velocity smoother. Should I put it in its own package or add it to an existing one? What would be a good name for the package? Simply nav2_velocity_smoother? There is another folder called nav2_smoother

@vinnnyr
Copy link
Contributor Author

vinnnyr commented Feb 4, 2022

Jerk Limits

  • Yeah so I can concede that jerk limits when in odometry mode might not make a lot of sense due to localization noise.

Deadband

The velocity smoother in the version of Regulated Pure Pursuit (RPP) was in odometry mode.
The deadband issue was inspired by issues we were fighting with RPP on a robot. We would give RPP a reasonable acceleration limit, but since that robot did not have a lot of control regime in the low end of velocity inputs, getting the robot to start would be tough.

If given a reasonable acceleration limit ( that we would have wanted enforced when the robot was at speed), we would enter this situation.

delta_t = 0.1
max_acc = 1.0

# loop 0
current_velocity = 0.0
# max_allowed_velocity = current_velocity + delta_t * max_acc
max_allowed_velocity = 0.1
cmd_velocity = 0.1

# loop 1
current_velocity = 0.01
max_allowed_velocity = 0.11
cmd_velocity = 0.11

# loop 2
current_velocity = 0.01
max_allowed_velocity = 0.11
cmd_velocity = 0.11 #and so on

Where loop 2 onwards, we were stuck at commanding a velocity the robot would have never been able to move.

I think in our use case, a deadband from (0.0, 0.5] for cmd_vel would have been useful (linear.x). In my use case, I do not think multiple deadbands would have been needed.

What should happen if the orginal cmd_vel is in the deadband?

Hm , this is a tough issue to generalize. In essence, I want the smoother to either command 0.0 or 0.5. Maybe this would just be something of this sorts: "if my current velocity is in the deadband range, do not apply the acceleration limit based on odom, but rather apply the acceleration limit based only on cmd, or maybe do not apply the acceleration limit at all"

@wilcobonestroo
Copy link
Contributor

That helps understanding the deadband issue 😄 So there should probably be several options for the behavior in the band.

Do you think we should include jerk for the commanded velocity mode? Or can we completely drop the jerk issue?

Ps. I started working on the boilerplate code and reading the parameters: https://github.com/wilcobonestroo/navigation2/tree/add-velocity-smoother

@SteveMacenski
Copy link
Member

SteveMacenski commented Feb 4, 2022

In the three implementations mentioned above I only see speed limits and acceleration limits.

Some only handle X, one of the things to make sure is that it supports omni robots in the Y velocity / acceleration direction. Its more about the implementation details that some have bells and whistles others are lacking in.

Should I put it in its own package or add it to an existing one?

nav2_velocity_smoother sounds good to me!

Do you think we should include jerk for the commanded velocity mode? Or can we completely drop the jerk issue?

I think for a first-release we can not include jerk, but if @vinnnyr wanted to come in after and include it, that PR would be easily merged. After the bulk is in place, adding a couple new parameters and a new constraint would be a trivial PR to review and merge.

@wilcobonestroo
Copy link
Contributor

wilcobonestroo commented Feb 5, 2022

Hmmm... I had never thought about omni robots and the y-velocity. In the implementation from Care-O-bot (cob) they treat the x and y as independent things to control. I.e. they simply apply the rules for linear speed and acceleration to both components. So, in theory you can have a total combined linear speed larger than the max linear speed (e.g. when both x and y are at their max). Is this what you also had in mind?

Another question: what is the logical way to have this node running? I was thinking to listen to the original cmd_vel topic and in the callback immediately publish the smoothed version. There can be a timer-based check to see if there are messages coming in or not. In the other implementations, I also see an approach where the smoother has his own timer (and thus his own publish rate). Velocity message that arrive are cached and processed at the speed of the internal timer. I don't see the benefits of this. I think it only adds latency in the messages and more complexity in the code. So, I was thinking in the direction of reacting to incoming Twist messages on cmd_vel. In the meanwhile, odom messages can be cached to determine the best odom estimate once a Twist message arrives. What do you think?

@wilcobonestroo
Copy link
Contributor

I have some initial smoothing attempts going on 😄

Screenshot from 2022-02-06 16-52-50

@SteveMacenski
Copy link
Member

SteveMacenski commented Feb 7, 2022

they treat the x and y as independent things to control

That would be fine to do, so you could make some functions that take in the min/max values (or probably a struct containing them) and then pass in each axis into them separately to smooth independently. Would be nice actually to have that abstracted architecturally.

I'm not sure the best way off hand to deal with a maximum velocity that is higher than that of the sum of the components. I think that's also the role of the local trajectory planner. This is smoothing out the values, which I agree would be helpful to enforce the constraints. Though enforcing each direction's constraints seems good enough to me unless there's a clear way of doing that demonstrated by another method linked above.

I was thinking to listen to the original cmd_vel topic and in the callback immediately publish the smoothed version. There can be a timer-based check to see if there are messages coming in or not.

It looks like they all do that in one way or another (timer, while loop, etc). I figure there must be a reason for that? Regularity of the intervals? So that it can be run at a faster rate than local trajectory planner is executing at in order to have a smooth interpolation to "ramp" commands by the regular interval samples? <-- that sounds about right

@wilcobonestroo
Copy link
Contributor

wilcobonestroo commented Feb 8, 2022

I have also been playing around some more. I assumed that I would always get a continuous stream of cmd_vel messages. However, they immediately stop once the goal has been reached. Using the deceleration constraints you need to make it stop slowly. So, I need to have the node running on its own timer anyway. Moreover, smoothly interpolating by having a higher rate is the best reason for having it that way.

@wilcobonestroo
Copy link
Contributor

Screenshot from 2022-02-11 11-46-40

The behavior is now like this. The ramp-up and ramp-down seem ok to me. What should be the behavior at the top? Currently, it is almost following the noisy behavior of the input, because this is within the acceleration limits. Is this behavior ok?

@wilcobonestroo
Copy link
Contributor

Screenshot from 2022-02-11 12-32-21

I can also do something like this with a buffer for the cmd_vel messages. As with all smoothing you get some delay in the signal.

@SteveMacenski
Copy link
Member

What should be the behavior at the top? Currently, it is almost following the noisy behavior of the input, because this is within the acceleration limits. Is this behavior ok?

Yeah, but I'd test with setting the max accels to something lower to see what happens if those little variations are invalid (so it should be smoothed out). Actually, that should be more or less what you show with the buffer.

The buffer is an interesting idea. I don't think that should be the default behavior but I'd be fine with that a parameterized option.

@SteveMacenski
Copy link
Member

How's this going?

@SteveMacenski
Copy link
Member

@wilcobonestroo any update?

@wilcobonestroo
Copy link
Contributor

Most functionality is in place. I have to remove some buffering code. Moreover, I did not include the deadband yet and I don’t know how (or where) to write the documentation. I will try to finish it this weekend and make a PR. Code is at: https://github.com/wilcobonestroo/navigation2/tree/add-velocity-smoother

@SteveMacenski
Copy link
Member

Awesome! If you need any help, let us know. Between me, @AlexeyMerzlyakov and @padhupradheep, you've got resources

@wilcobonestroo
Copy link
Contributor

wilcobonestroo commented Apr 19, 2022

Could someone give me some feedback on this code for this issue? @SteveMacenski , @AlexeyMerzlyakov or @padhupradheep?

@jwallace42
Copy link
Contributor

@wilcobonestroo can you put in a pr? Then I can take a look :)!

@SteveMacenski
Copy link
Member

Hi,

I'm back from PTO now and will take a look tomorrow or the next day. I haven't taken a look at this yet, but I did want to point you to ruckig that's being used in #2816. I think there's some natural synergies here to use that for this work potentially. I know it would be a near total rewrite regardless of what you've done so far, so I just want to bring it up, but it is not a requirement to use it. Its being used in MoveIt2 and likely to be added to RPP so if we do other kinematics "stuff" it might be good to use to be consistent with other ecosystem projects.

Steve

@SteveMacenski
Copy link
Member

SteveMacenski commented May 2, 2022

@wilcobonestroo in terms of feedback

  • Make sure to have this be a component node (register it) so that we can load this into the component container on launch, not only as a standalone server
  • The all-caps chars are only used on get/set of variables, I think just having the string in the get/set line would be good. I don't have a strong preference about it, but that is what we do in other nodes
  • Private -> Protected for class so someone can use this as a base class to add some capability later without forking
  • Use nav2_util's declare_parameter_if_not_declared and declare in the configure method, not constructor, per Lifecycle node conventions
  • Create subs / pubs in activate function (or configure if they are lifecycle pub/subs and activate them in activate callback), per lifecycle conventions
  • You can probably template the get parameter wrappers you wrote so you have 1 implementation that supports all the types
  • param_subscriber_ is unused
  • In header, all functions before all member variables
  • No need for \n at the end of log lines
  • I dont think your parameter_update_callback does anything
  • shutdown / cleanup callbacks need to do the opposite of the configure / activate functions. See other nodes for examples
  • Timer should not start until activate
  • If you dont activate your network interfaces until activate then you dont need to check PRIMARY_STATE_ACTIVE in the callbacks.
  • You should always smooth Y, if its always just 0s then it should just do no work
  • I dont think you need a separation between positive and negative velocities. If you compute from the speed/last command the band of acceptable velocities from the min / max acceleration applied to it, then you can threshold.
  • If your timer runs at a constant rate, why not use that for dt? Storing the last messages / runs really add any meaningfully improved performance / change?
  • I don't see a timeout / deadband logic
  • Overall, maybe the ruckig library would be nice to use, this should also smooth based on jerk as well (ideally) though we don't have input measurements of acceleration so I'm not sure we should try to attempt it. Integrating is usually pretty stable, but taking numerical derivatives is not

@vinnnyr how do you feel about jerk ( see last comment)

@AlexeyMerzlyakov
Copy link
Collaborator

AlexeyMerzlyakov commented May 7, 2022

My 5 cents into review:

  • I am not sure that MAXIMUM_LINEAR_VELOCITY_X...DEADBANDS static variables are suitable solution for declaring names of parameters. Usually these kind of variables are using to declare some global constants using in whole module or even by other modules (see nav2_costmap_2d/include/nav2_costmap_2d/costmap_filters/filter_values.hpp and nav2_util/include/nav2_util/occ_grid_values.hpp for reference). So, why don't just make something like inside class header:
    const char maximum_linear_velocity_x_param_name_ = "maximum_linear_velocity";
    ...
    const char deadbands_param_name_ = "deadbands";
    
  • When using declare_parameter() API without default value (e.g. declare_parameter(MAXIMUM_LINEAR_ACCELERATION_Y, rclcpp::ParameterType::PARAMETER_DOUBLE);), it will throw an error in case if parameter is not set. Therefore, further usage of get_*_parameter() routines doesn't make sense: at the point when we will reach these routines, parameters will have a value. In this case the code be simplified to something like:
    // declare_parameter(param_name, default_value);
    // OR better as Steve mentioned:
    declare_parameter_if_not_declared(node, param_name, default_value);
    ...
    maximum_linear_velocity_x_ = get_double_parameter(param_name).as_double();
    
  • All subscribers/publishers should be created during on_configure() stage and resetted at on_cleanup()
  • It is better use rclcpp_lifecycle::LifecyclePublisher for publishers
  • Dynamic parameters callbacks handler to set in on_activate() stage, and reset on on_deactivate()
  • RCLCPP_INFO() in frequently calling VelocitySmoother::get_new_speed() calculation method will cause a garbage in output. It is better to change it to RCLCPP_DEBUG()
  • Revision of timer_callback() and get_new_speed(): it looks like double new_speed should be double new_speed_x and
    new_setpoint = current_speed - acceleration;
    new_setpoint = std::max(std::max(new_setpoint, set_speed), -max_speed);
    
    could be optimized to ->
    new_setpoint = std::max(std::max(current_speed - acceleration, set_speed), -max_speed);
    
  • I can not find any angular twist smoothing logic for last_send_cmd_vel_. It looks like it was built into the module design since we have maximum_angular_velocity_ / maximum_angular_acceleration_ / maximum_angular_deceleration_ parameters, but never used them. Also, it looks like angular component of input velocity (be it odom or cmd_vel inputs) is never being passed to outer smoothed last_send_cmd_vel_ velocity.

@SteveMacenski
Copy link
Member

SteveMacenski commented May 20, 2022

I started to play with this using ruckig just to see how / if it would work. See branch: https://github.com/ros-planning/navigation2/tree/vel_smoother. Its still in development and incomplete. It brings up a few questions I'm still working through

  • How do we set the current acceleration / jerk in the process? We don't have access to that information reliably unless we numerically differentiate the odometry which is unstable for closed-loop feedback
  • --> however, it does work if we do open loop feedback (e.g. we assume the last timestep we met the required state and so we can store the last iteration's velocity/acceleration/jerk to use as the "current" in the next timestep). That would get around the numerical differentiation of odometry for closed loop feedback, but then would we be unable to support closed loop feedback?
  • How do we set the target acceleration when given an input twist, or should we? I think the target would be 0 as a safe default (we want to hit this speed), but not entirely truthful of what the future may hold. But I suppose that might be OK, this node can't be predictive.
  • For setting the current acceleration / jerk, I suppose we could set them all to 0 across the board and then the trajectory generated would assume the extremes for starting/stopping the trajectory. So for closed-loop set them all to 0-s since we can't estimate them reliably?

So it might be that a more manual approach is more appropriate for us, like what @wilcobonestroo is working on? Though in doing so, I don't think its reasonable to try to limit jerk if our own inputs and outputs are just Twist and Odometry, we don't have any acceleration information, let alone jerk. We can certainly set limits on acceleration manually (e.g. v1 = v0 + a_limits * t) and threshold within limits, but that's not as smooth as generating a trajectory if new discontinuous commands come in. Jerk is another derivative on top of that which would not be numerically stable to compute based on velocities.

@AndyZe over at PickNik is using Ruckig for MoveIt2, maybe he has some thoughts to share? Our aim is to add a velocity smoother to Nav2 to take in cmd_vel from the stack and smooth them before throwing into the robot hardware controllers for execution. I like the idea of off-boarding as much as I can to external libraries, especially if they're used elsewhere in the ecosystem. Do you think we should stick to ruckig?

@AndyZe
Copy link
Contributor

AndyZe commented May 20, 2022

I don't have any magic answers but it sounds like you're asking the right questions. Tough problem.

We don't have access to that information reliably unless we numerically differentiate the odometry which is unstable for closed-loop feedback

If you end up numerically differentiating, here's a decent way to do it:

  • Calculate the derivative. It could be a simple Euler calculation like accel = v(i+1) - v(i) / delta_t
  • Filter from beginning to end with a low-pass filter
  • Then filter from end to beginning with the same filter
  • To filter forwards then backwards removes the phase delay from filtering

it does work if we do open loop feedback (e.g. we assume the last timestep we met the required state and so we can store the last iteration's velocity/acceleration/jerk to use as the "current" in the next timestep).

I tried this 2 ways:

  • Feed the previous Ruckig output state as current state input for the next iteration. It worked reasonably well.
  • Feed the "nominal target state" from the previous iteration as current state input for the next iteration. Hardware tracking accuracy seemed better when doing it this way. I don't understand why -- I thought they would be almost identical.

For setting the current acceleration / jerk, I suppose we could set them all to 0 across the board and then the trajectory generated would assume the extremes for starting/stopping the trajectory. So for closed-loop set them all to 0-s since we can't estimate them reliably?

My intuition says that won't work very well. I think the motion will be slower than you expect. I could be wrong, though

@SteveMacenski
Copy link
Member

SteveMacenski commented May 20, 2022

I don't actually understand the difference between the 2 methods you mentioned, can you elaborate on the second point? (1) would be setting the new_{velocity, acceleration, pose} from the output as the input of the next iteration. I'm not sure what (2) entails. There's also pass_to_input method that appears in the demos but never in the documentation that you could see in my branch I have open questions around precisely its nature (which might be what you're referring to).

My intuition says that won't work very well. I think the motion will be slower than you expect. I could be wrong, though

As well. Though if we do a trivial v min / max = v0 +/- a * t calculation for thresholding, it's not really taking the current acceleration into account either. I need to do some thinking on that, but that feels analogous to the ruckig setting all current accelerations to 0.

I feel like this shouldn't be a technology mismatch, but might end up being. Traditionally in the ROS navigation ecosystem, we've just taken some $v_i$ and used basic kinematics to find the guard rails of $v_{min}$ and $v_{max}$ based on the set acceleration min/max and threshold it. Nothing fancy.

The 2 major uses cases of it are:

  • Setting the update rate to roughly the same as the trajectory planner rate (thing making cmd_vels), so 1 velocity command in = 1 velocity command out, with guard rails applied essentially.
  • Setting the update rate to higher than the controller rate, so 1 velocity command in = N velocity commands out, somewhat applying a smoothing trajectory since each dt its called will update the velocity towards the commanded velocity by the acceleration profile.

For the second case, generating a true trajectory sounds awesome so that we can get an optimal profile to work with. But for the first, I don't think generating a trajectory would be any worse than just thresholding.

Since we have a constant stream of these cmd_vel's coming out of the trajectory planner at a relatively consistent rate (and with algorithms that pre-apply varying levels of feasibility constraints) the target setpoint for the velocity is constantly changing but we don't know what the future holds to be able to meaningfully set target acceleration setpoints. But having a target acceleration of 0 seems rational to me, since that means that we achieved the goal velocity and are using it as steady state.

I'm also now thinking if, for illustration purposes, we had a trajectory planner giving us a cmd_vel at 1hz and we have a smoother at 100hz. Would we rather smoothly and slowly, below the kinematic limits of the robot's acceleration, wait the full 1s to get to the target speed, or get there as quickly as possible and maintain state.

--> I'm thinking the latter, which might then argue against using any kind of trajectory libraries, since we would want to use the full limits available to us vs moving below it to use the full time available (is that an option in ruckig? I don't think so). Navigation assumes instantaneous response, so the closer to that we can give, the better performance of tracking would be. The 1hz / 100hz is a drastic example, a more typical set up would be 20-50hz / 20-100hz, so the results would be significantly less noticable.

@wilcobonestroo what do you think about that?


@vinnnyr what are your thoughts on jerk limiting, how are you measuring acceleration so that you wouldn't be double differentiating noisy velocity data? What is/was your game plan there? It seems to me like that would probably need to be handled at the trajectory planner or hardware controller level so that either (1) you can make trajectories that are themselves already jerk limited or (2) you have access to raw data in the low levels that might be able to better estimate acceleration / jerk.

@SteveMacenski
Copy link
Member

SteveMacenski commented May 21, 2022

Well another thing to point out is that these all assume independent X, Y, and Theta velocity channels. Something Yocs does is constraining other channels when one is too high so that the velocity follows the vector previously created, just scaled down https://github.com/kobuki-base/velocity_smoother/blob/devel/src/velocity_smoother.cpp#L263-L296. I think this is a good idea. Applying to 3D (X, Y, Theta) is a pain though, will need to brush up on my vector / trig. I will say though the few examples of 3D velocity smoothers have removed that feature which is telling. Nice to know other smart people than me also had to think twice if it was worth going into that level of detail 😉

@AndyZe
Copy link
Contributor

AndyZe commented May 21, 2022

so that you wouldn't be double differentiating noisy velocity data?

Small correction here: Ruckig doesn't care what the current jerk of the robot is. It's not an input to Ruckig. So you only have to differentiate once to calculate acceleration.

I don't actually understand the difference between the 2 methods you mentioned, can you elaborate on the second point?

The second point means:

  • You have target_state(i) at iteration i. This is the nominal, desired state at iteration i.
  • At iteration i+1, you use target_state(i) as the "current state" of the robot, for input into Ruckig. Basically, you assume that it reached the previous target state perfectly.

It's really similar to Point 1 except you're not using the Ruckig output, you're using the target state that you provided originally. It should be an almost perfect match, which is why I was confused to see different behavior on our hardware.

@SteveMacenski
Copy link
Member

Thanks for the clarification!

@AndyZe
Copy link
Contributor

AndyZe commented May 22, 2022

If it would help, I can write some of this. Maybe the velocity differentiation part and/or the Ruckig part itself. My problem is, I have no idea where things go in the Nav2 codebase.

@SteveMacenski
Copy link
Member

SteveMacenski commented May 23, 2022

I think from my current looking, ruckig is not the best choice for us unfortunately for this project 😦 which I'm disappointed by since it looks like it could really streamline some things. However we want to (1) use the maximum kinematic limits possible to achieve velocities ASAP and maintain them vs using the full time allotted and (2) be able to proportionately bound the velocities of the axes so that we maintain the same (or as similar as possible) commanded direction.

From that, ruckig doesn't quite make sense for our application. However, I think it would be really interesting to see if we could use ruckig in the trajectory planners or smoothers to work with theoretical trajectories being generated versus involvement of real data. If we're using it for trajectories generated via other methods, then we should have acceleration and other information we can meaningfully use versus live / noisy data.

An area I could see ruckig being really nice for is if we had a post-trajectory planning step to take trajectories from local planners and smoothed them out using ruckig. Although, for the frequency that the local planners are updated at, this might be overkill, but I think its the most appropriate place for it in the mobile robot stack (which would be relatively analog to MoveIt's use of it as well). I'll keep this tool in my back pocket though. If we added some machine learning or heavy sampling based trajectory planners, I think ruckig would really shine

Thanks @AndyZe for the information and help! It's really helped. Feel free to poke me if I can be helpful on the moveit side.

@SteveMacenski
Copy link
Member

#2964 is ready for testing if folks want to kick the tires!

@vinnnyr
Copy link
Contributor Author

vinnnyr commented Jun 10, 2022

I just noticed I missed the tags here when my input was requested for Jerk. So Sorry about that!!!
Now I feel like a jerk ;)
I think this question is no longer relevant, but indeed I was hoping Jerk could be handled based on cmd_vel alone rather than trying to measure acceleration based off of sensors / localization estimates.

(1) you can make trajectories that are themselves already jerk limited

@SteveMacenski
Copy link
Member

I think it makes sense to add jerk limiting to the trajectory planners perhaps to get around this situation, so that way the computed trajectories generating the commands are limited by it so that the velocity smoother doesn't require to do it -- and then its based on theoretical models and not actual current sensor data so you can differentiate it to your heart's desire.

@SteveMacenski
Copy link
Member

SteveMacenski commented Jun 13, 2022

Merging imminent, thanks @vinnnyr for bringing up this gap

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants