WalkGenerators¶
In the current motion framework we provide different representations which implement the generation of walk steps for specific situations. In this documentation those generators are described.
WalkToBallAndKickGenerator¶
The WalkToBallAndKickGenerator
implemented the interface for the behavior to execute kicks in a given direction with a given precision. It is implemented by the module WalkToBallAndKickEngine
. It handles different cases before a kick is allowed to be executed and merges our two kick types, kicks from the KickEngine
and the WalkKickEngine
, together. In the following kicks from the KickEngine
will be called stand kicks and ones from the WalkKickEngine
walk kicks.
To decide whether to start a kick or to keep walking to the kick pose, we differentiate between the stand kicks and walk kicks. For stand kicks simple threshold checks for the orientation and translation of the ball are computed. For the walk kicks please refer to WalkKickEngine. In short the WalkKickEngine
implements the canStart
function to do the necessary checks. If those checks result in true
and some more additional ones too, like the ball is seen, the kick is executed.
Otherwise the WalkToBallGenerator is used to walk to the ball.
There are several other steps between concluding no kick is possible and calling the WalkToBallGenerator
:
- Special handling for the kick
ForwardSteal
. For kick places the robot is placed behind the ball with a V-Shape with the feet. - Special handling if the robot can not reach the kick pose. Based on the odometry and the last walking steps we change the kick pose slightly to prevent the robot to walk in place as a result of different joints not correctly executing small steps
- The ball position is changed. The perceived velocity can sometimes differ by large amount. To prevent the robot from e.g. turning and walking away from the ball, the ball position is clipped by the function
calcInterceptionPosition
WalkToBallGenerator¶
The WalkToBallGenerator
implements the behavior to walk around a ball and is implemented by the module WalkToBallEngine
. This module checks beforehand whether this special handling is needed. Therefore if the kick pose is not on the other side of the ball and a walking around the ball is not required, the WalkToPoseGenerator is automatically called to generate the next walk step.
When a walking around the ball is necessary the calculate both tangents to the ball, which is modeled as a circle. In case we are already inside the circle some special handling is applied to prevent walking further into the ball. Afterwards the tangent with the shorter distance is used as a walking path.
Afterwards the WalkUtilities are used to optimize between forward, diagonal and side walking to waste as little time as possible. The resulting step target is then clipped based on the translation polygon of the WalkingEngine
.
WalkToPoseGenerator¶
The WalkToPoseGenerator
is our general go-to representation to walk from point A to B. It is implemented by the module WalkToPoseEngine
. Here the obstacle avoidance from the behavior is used to determine the path to avoid a collision. Note that the orientation to walk past an obstacle is independent of such obstacle. Otherwise the robot would rotate to follow the path and afterwards rotate once again to align to the original walk target. This can cost precious time and slow down the robot significantly.
Afterwards the WalkUtilities are used to optimize between forward, diagonal and side walking to waste as little time as possible. The resulting step target is then clipped based on the translation polygon of the WalkingEngine
.
WalkAtSpeedGenerator¶
The WalkAtSpeedGenerator
either takes in percentages of speeds for the rotational and translational components or direct speed values. In both cases a corresponding walk step is calculated based on the limits of the WalkingEngine
. It is implemented by the module WalkAtSpeedEngine
.
DribbleGenerator¶
The DribbleGenerator
is implemented by the module DribbleEngine
and implements the dribbling into a given direction. The same could be achieved by requesting a forward kick with the MotionRequest
type WalkToBallAndKick
. The DribbleEngine
optimizes this request further by determining the best kick foot directly in the motion thread and allowing more freedom in the execution.
Note
Nonetheless the execution of the kicks itself are not as smooth as they could. The robots are often waiting two walk steps for a better alignment which is not necessary, did not reach the ball with a kick or did kick the ball and stop walking, which removes all momentum.
InterceptBallGenerator¶
The InterceptBallGenerator
is implemented by the module InterceptBallProvider
. If the behavior set the flag shouldInterceptBall
in the MotionRequest
, this module is called to calculate a walking step to intercept a rolling ball.
The walking step is optimized to execute large side steps in the direction of the interception point with the path the ball is rolling. As rotational walking steps are sometimes necessary too, the side translation and rotational size are both optimize to prefer large side steps over rotational steps. This is due the constraint, that the walking becomes very unstable if the robot executed both. Therefore the walking already reduces the translation sizes if high rotational steps are requested. For the intercepting we swaped this constraint, therefore the rotational step size is reduced for large translational steps.
As a result the robots will always do the largest possible side step in the direction of the interception point with close to no rotational component. Only afterwards, when the legs are moving together again, execute a rotational step if necessary.
Additionally, the walking itself will update this intercepting step and will even start intercepting after a new non-intercepting step already started. This is further explained here.
WalkUtilities¶
The WalkUtilities
are functions found in Tools/Motion/WalkUtilities.h
. They are currently used by the WalkToBallEngine
and the WalkToPoseEngine
to optimize the rotation and translation when walking from point A to point B. Both modules use the same functions to prevent behavior oscillation and to enforce that those different situations, walking to a ball and walking to a pose on the field, are treated the same.
The general idea is that when walking from point A to B the current orientation of the robot should not matter that much. It is important that when the target pose is reached the orientation is so too, but while walking to it, it is allowed to differ. Therefore it should not matter if the robot is walking perfectly straight or slightly diagonal or even sideways, as long as no additional time is wasted. Otherwise, which was the approach in previous years, the robot is forced to perfectly align itself with the walking path. This caused the robot to execute small rotational steps in every walking step, because the walk is not smooth and rotates the robot with every walking step.
For this reason it is faster to just accept that the robot will slowly turn its orientation over time when walking to a position than to force a correction in every step. This of course is at some point only possible if the walking is capable of doing so too. Hence the current WalkingEngine
is to some degree optimized in that regard that it can support large diagonal and large side steps.
On the other hand the functions are implemented in such a way that a target of interest, like the ball or the target pose, can be visible with both cameras and are not concealed by the shoulders or lost because of errors in the localization of the odometry.
calcSideWalk¶
Give a target of interest (ToI) the goal of this function is to find a walk orientation, which is later used as the rotation part for the walk step, which lets the robot walk sideways while also keeping the ToI in sight.
This is achieved by defining a static view range maxTargetFocusAngle
, which is applied to the current angle to the ToI. For example if the ToI is at coordinate (100,100) then the current angle to the ToI is 45 degrees. With maxTargetFocusAngle = { -50_deg, 50_deg}
the final view range would be { -5_deg, 95_deg }
.
Afterwards a second angle range is determined, which represents the view range based on the max side step range (e.g. max side step size plus min and max forward translation). It is based on the optimal side walk direction, e.g. the 90 degree direction relative to the walk target direction which is closer to the ToI angle, and the max step size to the side.
Those two ranges are then used to clip the walk direction (rotated to force exact side steps of 90 degrees) to get the largest side steps which also still allow the ToI be inside the view range.
The implementation itself is slightly more complicated to correctly handle angles outside the \(-\pi\) and \(+\pi\) range.
calcDiagonal¶
Similar to calcSideWalk the same approaches are applied. We use the same view range maxTargetFocusAngle
. But instead of optimized side walking, we use the translation polygon of the WalkingEngine
to get the maximum size of diagonal walking steps. Those allow for the maximum possible forward speed with some additional side speed. The walk direction angle is then clipped into this diagonal angle range and view range.
The implementation itself is once again slightly more complicated to correctly handle angles outside the \(-\pi\) and \(+\pi\) range.
Translation Optimization¶
Both calcSideWalk and calcDiagonal do some additional optimization at the end. calcDiagonal
will rotate the translation of the walk target to prevent the robot to overshoot the walking path. This problem occurs because with every second walking step the side movement is clipped to 0 as the left foot cannot move right and the right foot cannot move left. This would otherwise result in the robot walking in a curved path and walking for a longer distance than intended.
Also both functions optimize the rotation with a simple trick. In walking steps, in which the side movement is clipped to 0, we can allow for most of the rotation that is calculated to be executed by the walk step. But in every other step where the side movement is not clipped, we will reduce the rotation so much that all translation can be executed.
Here an example why this trick is quite impactful:
The robot is in an duel with another robot for the ball. The ball rolls to the right. The robot waits for the next foot support switch and now the right foot will be the swing foot. In theory the robot should be able to instantly walk sideways to the right to follow the ball. Without the mentioned trick the walk step planing might want to add some rotation, because the robot is rolling a small amount backwards (relative to us). This in turn would reduce the maximum allowed translation, down to 0. Therefore the robot would execute a rotation step. After about 250 ms the next foot support switch occurs and the left foot is now the swing foot. As the robot still wants to walk to the right, but cannot execute such step, it will just finish the rotational walk step and effectively not move. Only with the next walk step the robot will finally start walking sideways.
With this optimization trick the robot would instantly walk sideways with the first walk step and start the rotation with the second step. This saves up to 500 ms, which is very crucial in duels with other robots and can mean the difference between a goal for the own team and a goal for the opponent team.