# Humanoid and wheeled-legged controllers in C++ and Python: balancing at different frequencies

Talk given at the Humanoids 2022 Tutorial on Challenge-driven Learning of Humanoid Robot Control in Virtual Environments, 28 November 2022.

## Abstract¶

The physics of a task dictate how fast a controller should run to perform it. Balancing, in particular, is a rather low-frequency task: it was demonstrated (in theory and on real hardware) that a DCM-based controller can balance an adult-size humanoid while running at only 10 Hz. In this talk, we will discuss how this property allows us to write more control-critical code in a high-level language like Python. We will illustrate our points with practical sub-modules from two controllers: the LIPM walking controller for HRP humanoids, implemented with mc_rtc, and the Pink controller for the Upkie wheeled-biped, implemented with Vulp (🦊).

## Content¶

 Slides Python code from the slides Motion control software for the Upkie wheeled biped

## Discussion ¶

Thanks to all those who have contributed to the conversation so far. Feel free to leave a reply using the form below, or subscribe to the  Discussion's atom feed to stay tuned.

• Posted on

Does Vulp run on Windows? This would be helpful when setting up a teaching environment for students.

• Posted on

Currently Vulp only supports Linux for x86 and ARM architectures, which is Upkie's use case. We can add Windows support to the roadmap: #3.

Note however that Vulp targets mostly researchers, research engineers, or PhD students. It may have some rough edges for students earlier in the learning curve.

• Posted on

• Posted on

We indeed need to specify what is discretized exactly. In this analysis, the continuous-time DCM dynamics are discretized with sampling time $\def\LdG{\dot{L}_G} \def\Ld{\dot{L}} \def\bfA{\boldsymbol{A}} \def\bfB{\boldsymbol{B}} \def\bfC{\boldsymbol{C}} \def\bfD{\boldsymbol{D}} \def\bfE{\boldsymbol{E}} \def\bfF{\boldsymbol{F}} \def\bfG{\boldsymbol{G}} \def\bfH{\boldsymbol{H}} \def\bfI{\boldsymbol{I}} \def\bfJ{\boldsymbol{J}} \def\bfK{\boldsymbol{K}} \def\bfL{\boldsymbol{L}} \def\bfM{\boldsymbol{M}} \def\bfN{\boldsymbol{N}} \def\bfO{\boldsymbol{O}} \def\bfP{\boldsymbol{P}} \def\bfQ{\boldsymbol{Q}} \def\bfR{\boldsymbol{R}} \def\bfS{\boldsymbol{S}} \def\bfT{\boldsymbol{T}} \def\bfU{\boldsymbol{U}} \def\bfV{\boldsymbol{V}} \def\bfW{\boldsymbol{W}} \def\bfX{\boldsymbol{X}} \def\bfY{\boldsymbol{Y}} \def\bfZ{\boldsymbol{Z}} \def\bfalpha{\boldsymbol{\alpha}} \def\bfa{\boldsymbol{a}} \def\bfbeta{\boldsymbol{\beta}} \def\bfb{\boldsymbol{b}} \def\bfcd{\dot{\bfc}} \def\bfchi{\boldsymbol{\chi}} \def\bfc{\boldsymbol{c}} \def\bfd{\boldsymbol{d}} \def\bfe{\boldsymbol{e}} \def\bff{\boldsymbol{f}} \def\bfgamma{\boldsymbol{\gamma}} \def\bfg{\boldsymbol{g}} \def\bfh{\boldsymbol{h}} \def\bfi{\boldsymbol{i}} \def\bfj{\boldsymbol{j}} \def\bfk{\boldsymbol{k}} \def\bflambda{\boldsymbol{\lambda}} \def\bfl{\boldsymbol{l}} \def\bfm{\boldsymbol{m}} \def\bfn{\boldsymbol{n}} \def\bfomega{\boldsymbol{\omega}} \def\bfone{\boldsymbol{1}} \def\bfo{\boldsymbol{o}} \def\bfpdd{\ddot{\bfp}} \def\bfpd{\dot{\bfp}} \def\bfphi{\boldsymbol{\phi}} \def\bfp{\boldsymbol{p}} \def\bfq{\boldsymbol{q}} \def\bfr{\boldsymbol{r}} \def\bfsigma{\boldsymbol{\sigma}} \def\bfs{\boldsymbol{s}} \def\bftau{\boldsymbol{\tau}} \def\bft{\boldsymbol{t}} \def\bfu{\boldsymbol{u}} \def\bfv{\boldsymbol{v}} \def\bfw{\boldsymbol{w}} \def\bfxi{\boldsymbol{\xi}} \def\bfx{\boldsymbol{x}} \def\bfy{\boldsymbol{y}} \def\bfzero{\boldsymbol{0}} \def\bfz{\boldsymbol{z}} \def\calA{\mathcal{A}} \def\calB{\mathcal{B}} \def\calC{\mathcal{C}} \def\calD{\mathcal{D}} \def\calE{\mathcal{E}} \def\calF{\mathcal{F}} \def\calG{\mathcal{G}} \def\calH{\mathcal{H}} \def\calI{\mathcal{I}} \def\calJ{\mathcal{J}} \def\calK{\mathcal{K}} \def\calL{\mathcal{L}} \def\calM{\mathcal{M}} \def\calN{\mathcal{N}} \def\calO{\mathcal{O}} \def\calP{\mathcal{P}} \def\calQ{\mathcal{Q}} \def\calR{\mathcal{R}} \def\calS{\mathcal{S}} \def\calT{\mathcal{T}} \def\calU{\mathcal{U}} \def\calV{\mathcal{V}} \def\calW{\mathcal{W}} \def\calX{\mathcal{X}} \def\calY{\mathcal{Y}} \def\calZ{\mathcal{Z}} \def\d#1{{\rm d}{#1}} \def\defeq{\stackrel{\mathrm{def}}{=}} \def\dim{\rm dim} \def\p{\boldsymbol{p}} \def\qdd{\ddot{\bfq}} \def\qd{\dot{\bfq}} \def\q{\boldsymbol{q}} \def\xdd{\ddot{x}} \def\xd{\dot{x}} \def\ydd{\ddot{y}} \def\yd{\dot{y}} \def\zdd{\ddot{z}} \def\zd{\dot{z}} \delta t$. Meanwhile, force control is assumed to run in an underlying continuous process, but its outcome (e.g. delay) is lumped in a ZMP tracking error at the next sampling time.

• Posted on

I have a follow-up question: does this work consider the distance from the ZMP to the edge of its support area?

It seems the maximum sampling period would become smaller as this distance shrinks.

• Posted on

Indeed, this analysis does not consider the distance to the edge of the support area.

I agree with you that the maximum sampling period should be affected by the position of the ZMP within its support area.

• Posted on

You mentioned Rust and Julia. Do you have plans to extend Vulp to these languages?

• Posted on

Vulp being a protocol, it is open to implementation in either Rust or Julia. Rust has proper safety guarantees compared to C++, and Julia performs faster than Python with roughly the same level of abstraction—although, regarding this last point, we saw in this presentation that the current performance of Python is already sufficient for many balancing use cases. Personally I'm interested in Rust's guarantees and type system.

• Posted on

That's good to hear! I contribute to OpenRR, the Open Rust Robotics platform. You should check it out.

• Posted on

👍

You can use Markdown with $\LaTeX$ formulas in your comment.