Skip to content

Commit

Permalink
Merge pull request #688 from ami-iit/variable_swingfoot_orientation
Browse files Browse the repository at this point in the history
Add the possibility to change the orientation of the foot in the swing foot planner when the contact is not active
  • Loading branch information
GiulioRomualdi authored Jun 23, 2023
2 parents 91ad0cf + 606cc06 commit 522bf23
Show file tree
Hide file tree
Showing 10 changed files with 547 additions and 85 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ All notable changes to this project are documented in this file.
- 🤖 [ergoCubSN000] Clean the mas remapper files of the `YarpRobotLoggerDevice` (https://github.com/ami-iit/bipedal-locomotion-framework/pull/673)
- 🤖 [ergoCubSN000] Enable the logging of the realsense camera `YarpRobotLoggerDevice` (https://github.com/ami-iit/bipedal-locomotion-framework/pull/672)
- Add the possibility to force the internal state of the `SchmittTrigger` (https://github.com/ami-iit/bipedal-locomotion-framework/pull/684)
- Add the possibility to update the contact list in the swing foot planner when the contact is not active and the new orientation is different from the previous one (https://github.com/ami-iit/bipedal-locomotion-framework/pull/688)
- Add the possibility to set the boundary condition for the velocity and acceleration of the `SO3Planner` (https://github.com/ami-iit/bipedal-locomotion-framework/pull/688)

### Fixed
- Fix RobotDynamicsEstimator compilation dependencies (https://github.com/ami-iit/bipedal-locomotion-framework/pull/665)
Expand Down
2 changes: 1 addition & 1 deletion docs/config.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[master]
main_page = "docs/pages/main-page.dox"
additional_pages = ["docs/pages/python-additional-info.md"]
additional_pages = ["docs/pages/python-additional-info.md", "docs/pages/so3-minjerk.md"]
src_folder = "src"

['v0.13.0']
Expand Down
3 changes: 3 additions & 0 deletions docs/pages/main-page.dox
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
\brief The **bipedal-locomotion-framework** project is a _suite_ of libraries for achieving
bipedal locomotion on humanoid robots.

\section interesting-math-notes 📚 Interesting Math Notes
What follows is a list of interesting math notes that can be usefull to fully understand the usage of the library
- \ref so3-minjerk

\section mandatory-dependencies 📄 Mandatory dependencies
The **bipedal-locomotion-framework** project is versatile and can be used to compile only some components.
Expand Down
134 changes: 134 additions & 0 deletions docs/pages/so3-minjerk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# 🧮 SO3 Minimum jerk trajectory {#so3-minjerk}

## Introduction
Planning a minimum jerk trajectory in SO(3) can be a complex task. In this document, we aim to demonstrate the capabilities of the **bipedal-locomotion-framework** for generating minimum jerk trajectories in SO(3). The document is structured as follows: we first provide an overview of the mathematical foundations behind the planner, followed by a simple example illustrating its usage. Finally, we recommend some interesting readings for readers seeking more in-depth explanations and rigorous proofs.

## 📐 Math
Given a fixed initial rotation \f$(t_0, R_0)\f$ and a final rotation \f$(t_f, R_f)\f$ and the associated left trivialized angular velocities, \f$(t_0, \omega_0)\f$ and \f$(t_f, \omega_f)\f$, we want to compute a trajectory \f$R : \mathbb{R}_+ \rightarrow SO(3)\f$ such that \f$R(t_0) = R_0\f$, \f$R(t_f) = R_f\f$, \f$\omega(t_0) = \omega_0\f$, \f$\omega(t_f) = \omega_f\f$, \f$\dot{\omega}(t_0) = \dot{\omega}_0\f$, \f$\dot{\omega}(t_f) = \dot{\omega}_f\f$ such that left trivialized angular jerk is minimized

\f[
\mathfrak{G} = \int_{t_0}^{t_f} \left({}^\mathcal{F} \ddot{\omega} _ {\mathcal{I}, F}^\top {}^\mathcal{F} \ddot{\omega} _ {\mathcal{I}, F} \right)\text{d} t.
\f]

Following the work of [Zefran et al. "On the Generation of Smooth Three-Dimensional Rigid Body Motions"](https://doi.org/10.1109/70.704225) it is possible to prove that a trajectory \f$R(t)\f$ that satisfies the following equation is a minimum jerk trajectory in SO(3).

\f[
\begin{array}{ll}
\omega ^{(5)} & + 2 \omega \times \omega ^{(4)} \\
& + \frac{4}{5} \omega \times (\omega \times \omega ^{(3)}) + \frac{5}{2} \dot{\omega} \times \omega^{(3)} \\
& + \frac{1}{4} \omega \times (\omega \times (\omega \times \ddot{\omega})) \\
& + \frac{3}{2} \omega \times (\dot{\omega} \times \ddot{\omega}) \\
& - (\omega \times \ddot{\omega}) \times \dot{\omega} \\
& - \frac{1}{4} (\omega \times \dot{\omega}) \times \ddot{\omega} \\
& - \frac{3}{8} \omega \times ((\omega \times \dot{\omega}) \times \dot{\omega}) \\
& - \frac{1}{8} (\omega \times (\omega \times \dot{\omega})) \times \dot{\omega} = 0.
\end{array}
\f]

From now on we call this condition: **Minimum jerk trajectory condition**.

It is worth noting that the above does not admit an analytic solution for arbitrary boundary conditions.
However, in the case of zero boundary velocity and acceleration or specific structure of the boundary condition, it is possible to show that
\f[
R(t) = R_{0} \exp{\left(s(t-t_0) \log\left(R_0^\top R_f \right) \right)} \quad \quad s(\tau) = a_5 \tau^5 + a_4 \tau^4 + a_3 \tau^3 + a_2 \tau^2 + a_1 \tau + a_0
\f]
satisfies condition the minimum jerk necessary condition. To prove the latest statement, we assume that \f$t_0 = 0\f$ and \f$t_1 = 1\f$, and then we compute the left trivialized angular velocity. The assumption can be easily removed with a simple change of variables.

The angular velocity is given by

\f[
\begin{array}{ll}
\omega^\wedge &= R^\top \dot{R} \\
&= \dot{s} \exp{\left(-s\log\left( R _ 0^\top R _ f \right) \right)}R_{0} ^\top R _ {0} \log\left( R _ 0^\top R _ f \right) \exp{\left(s\log\left( R _ 0^\top R _ f \right) \right)} \\
&= \dot{s}\exp{\left(-s\log\left(R _ 0^\top R _ f \right) \right)} \log\left( R _ 0^\top R _ f \right) \exp{\left(s\log\left( R _ 0^\top R _ f \right) \right)} \\
&= \dot{s}\exp{\left(-s\log\left(R _ 0^\top R _ f \right) \right)} \exp{\left(s\log\left( R _ 0^\top R _ f \right) \right)} \log\left( R _ 0^\top R _ f \right) \\
&= \dot{s} \log\left( R _ 0^\top R _ f \right).
\end{array}
\f]

In other words, the angular velocity will be always proportional to \f$\log\left( R_0^\top R_f \right)\f$.

This means that we can ask for an initial and final angular velocity that is linearly dependent on \f$\log\left(R_0^\top R_f \right)\f$.
Let us introduce \f$\omega^\wedge(0)\f$ and \f$\omega^\wedge(1)\f$ as

\f[
\omega^\wedge(0) = \lambda ^\omega _ 0 \log\left( R_0^\top R_f \right) \quad \omega^\wedge(1) = \lambda ^\omega _ 1 \log\left( R_0^\top R_f \right)
\f]

similarly for the angular acceleration

\f[
\dot{\omega}^\wedge(0) = \lambda ^\alpha _ 0 \log\left( R_0^\top R_f \right) \quad \dot{\omega}^\wedge(1) = \lambda ^\alpha _ 1 \log\left( R_0^\top R_f \right)
\f]

So combining the initial and the final boundary conditions we can write the following linear system.
\f[
\begin{array}{ll}
s(0) &= 0 \\
s(1) &= 1 \\
\dot{s}(0) &= \lambda ^\omega _ 0 \\
\dot{s}(1) &= \lambda ^\omega _ 1 \\
\ddot{s}(0) &= \lambda ^\alpha _ 0 \\
\ddot{s}(1) &= \lambda ^\alpha _ 1
\end{array}
\f]

Solving the above system we obtain

\f[
\begin{array}{ll}
a_0 &= 0 \\
a_1 &= \lambda ^\omega _ 0 \\
a_2 &= \lambda ^\alpha _ 0/2 \\
a_3 &= \lambda ^\alpha _ 1/2 - (3 \lambda ^\alpha _ 0)/2 - 6 \lambda ^\omega _ 0 - 4 \lambda ^\omega _ 1 + 10 \\
a_4 &= (3 \lambda ^\alpha _ 0)/2 - \lambda ^\alpha _ 1 + 8 \lambda ^\omega _ 0 + 7 \lambda ^\omega _ 1 - 15 \\
a_5 &= \lambda ^\alpha _ 1/2 - \lambda ^\alpha _ 0/2 - 3 \lambda ^\omega _ 0 - 3 \lambda ^\omega _ 1 + 6
\end{array}
\f]

It is now easy to show that \f$\omega\f$ satisfies the minimum jerk condition indeed

\f[
\omega ^{(5)} = 0
\f]

and all the cross products vanish since the angular velocity and its derivatives are linearly dependent.

## 💻 How to use the planner

The SO3 minimum jerk planner is provided in **bipedal-locomotion-framework** through a template class that allows the user to use the left or the right trivialized angular velocity

```cpp
using namespace std::chrono_literals;

manif::SO3d initialTransform = manif::SO3d::Random();
manif::SO3d finalTransform = manif::SO3d::Random();

constexpr std::chrono::nanoseconds T = 1s;

BipedalLocomotion::Planner::SO3PlannerInertial planner;
manif::SO3d::Tangent initialVelocity = (finalTransform * initialTransform.inverse()).log();

initialVelocity.coeffs() = initialVelocity.coeffs() * 2;
planner.setInitialConditions(initialVelocity, manif::SO3d::Tangent::Zero());
planner.setFinalConditions(manif::SO3d::Tangent::Zero(), manif::SO3d::Tangent::Zero());
planner.setRotations(initialTransform, finalTransform, T);

manif::SO3d rotation, predictedRotation;
manif::SO3d::Tangent velocity, predictedVelocity;
manif::SO3d::Tangent acceleration;
planner.evaluatePoint(0.42s, rotation, velocity, acceleration);
```
## 📖 Interesting readings
The interested reader
can refer to the extensive literature, among which it is worth mentioning:
- Žefran, M., Kumar, V., and Croke, C. (1998). _On the generation of smooth threedimensional rigid body motions_. IEEE Transactions on Robotics and Automation,
14(4):576–589.
- Dubrovin, B. A., Fomenko, A. T., and Novikov, S. P. (1984). _Modern Geometry —
Methods and Applications, volume 93_. Springer New York, New York, NY.
- Needham, T. (2021). _Visual Differential Geometry and Forms_. Princeton University
Press.
- Pressley, A. (2010). _Elementary Differential Geometry_. Springer London, London.
- Giulio Romualdi (2022) _Online Control of Humanoid Robot Locomotion_ Ph.D. Thesis.
80 changes: 75 additions & 5 deletions src/Planners/include/BipedalLocomotion/Planners/SO3Planner.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,45 @@ class SO3Planner : public System::Source<SO3PlannerState>
SO3PlannerState m_state; /**< Current state of the planner. It is used by the advance
capabilities. */

/**
* Description of a 5-th polynomial. It contains the coefficients of the sub-trajectory.
*/
struct Polynomial
{
double a0;
double a1;
double a2;
double a3;
double a4;
double a5;
};

/**
* Struct containing the boundary condition
*/
struct BoundaryConditions
{
manif::SO3d::Tangent velocity;
manif::SO3d::Tangent acceleration;
bool isSet{false};
};

BoundaryConditions initialCondition; /**< Initial condition */
BoundaryConditions finalCondition; /**< Final condition */
bool areCoefficientsComputed{false}; /**< If true the coefficients are computed and updated */
Polynomial polynomial;

/**
* This function is the entry point to compute the coefficients of the spline
*/
bool computeCoefficients();

/**
* Compute the distance given two rotations. It depends on the trivialization.
*/
static manif::SO3d::Tangent
computeDistance(const manif::SO3d& initialRotation, const manif::SO3d& finalRotation);

public:
/**
* Set the rotation
Expand All @@ -91,8 +130,7 @@ class SO3Planner : public System::Source<SO3PlannerState>
* @param state state of the planner.
* @return True in case of success/false otherwise.
*/
bool evaluatePoint(const std::chrono::nanoseconds& time,
SO3PlannerState& state) const;
bool evaluatePoint(const std::chrono::nanoseconds& time, SO3PlannerState& state);

/**
* Get the trajectory at a given time
Expand All @@ -104,12 +142,11 @@ class SO3Planner : public System::Source<SO3PlannerState>
* (accordingly to the trivialization used).
* @return True in case of success/false otherwise.
*/
template<class Derived>
template <class Derived>
bool evaluatePoint(const std::chrono::nanoseconds& time,
manif::SO3d& rotation,
manif::SO3TangentBase<Derived>& velocity,
manif::SO3TangentBase<Derived>& acceleration) const;

manif::SO3TangentBase<Derived>& acceleration);

/**
* Set the time step of the advance interface.
Expand All @@ -119,6 +156,24 @@ class SO3Planner : public System::Source<SO3PlannerState>
*/
bool setAdvanceTimeStep(const std::chrono::nanoseconds& dt);

/**
* Set the initial condition of the spline
* @param velocity initial angular velocity.
* @param acceleration initial angular acceleration.
* @return True in case of success, false otherwise.
*/
bool setInitialConditions(const manif::SO3d::Tangent& velocity,
const manif::SO3d::Tangent& acceleration);

/**
* Set the final condition of the trajectory generator
* @param velocity final angular velocity.
* @param acceleration final angular acceleration.
* @return True in case of success, false otherwise.
*/
bool setFinalConditions(const manif::SO3d::Tangent& velocity,
const manif::SO3d::Tangent& acceleration);

/**
* Get the state of the system.
* @warning if the the time step of the advance is not set the user cannot use the advance
Expand All @@ -142,6 +197,21 @@ class SO3Planner : public System::Source<SO3PlannerState>
* @return True if the advance is successfull.
*/
bool advance() final;

/**
* Project the tangent vector on the vector that represents the distance between the two
* rotations.
* @param initialRotation initial rotation \f${}^{\mathcal{I}}R_{\mathcal{B}_0}\f$.
* @param finalRotation final rotation \f${}^{\mathcal{I}}R_{\mathcal{B}_T}\f$.
* @param vector Tangent vector that needs to be projected.
* @return The projected tangent vector.
* @warning If the initial and final rotations coincides the projected tangent vector will be
* set equal to zero.
* @note this method can be used along with setInitialConditions and setFinalConditions.
*/
static manif::SO3d::Tangent projectTangentVector(const manif::SO3d& initialRotation,
const manif::SO3d& finalRotation,
const manif::SO3d::Tangent& vector);
};

/**
Expand Down
Loading

0 comments on commit 522bf23

Please sign in to comment.