Based on notes created by Sam Coogan and Murat Arcak. Licensed under a “Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License”
Recall that we also have the following theorem for barrier functions:
Theorem: Barrier Function
If \(h\) is a barrier function, then \(\mathcal{C}=\{x:h(x)\geq 0\}\) is positively invariant.
Definition: Control Barrier Function
A function \(h\) with \(\mathcal{C}=\{x\mid h(x)\geq 0\}\) is a control barrier function (CBF) for a control-affine system \(\dot{x} = f(x) + g(x)u\) if there exists a locally Lipschitz function \(\alpha:\mathbb{R}\to\mathbb{R}\) satisfying \(\alpha(0)=0\) such that
\[\sup_{u\in\mathbb{R}^m} \nabla h(x)^T(f(x)+g(x)u)\geq -\alpha (h(x))\quad \text{for all } x\in\mathbb{R}^n. \tag{2}\]
The supremum is the smallest number that is greater than or equal to every element in the set. The supremum must be a real number (cannot be infinity).
We can also write Equation 2 using Lie derivative notation:
If \(h\) is a control barrier function for Equation 1, then the following hold:
\(U(x)\neq \emptyset\) for all \(x\);
Any Lipschitz feedback control \(u:\mathbb{R}^n\to \mathbb{R}^m\) satisfying \(u(x)\in U(x)\) renders \(\mathcal{C}\) invariant;
A feedback control is given by \[u^*(x)=
\begin{cases}
0 & \text{if }\nabla h(x)^T f(x)+\alpha(h(x))\geq 0\\
\dfrac{-\nabla h(x)^Tf(x)-\alpha(h(x))}{\|\nabla h(x)^T g(x)\|_2^2}(g(x)^T\nabla h(x)) & \text{otherwise,}
\end{cases} \tag{5}\] which is the same as: \[u^*(x)=
\begin{cases}
0 & \text{if } L_fh(x) +\alpha(h(x)) \geq 0\\
\dfrac{-(L_fh(x) + \alpha(h(x)))L_g h(x)^T}{L_gh(x) L_g h(x)^T} & \text{otherwise.}
\end{cases}\] A sufficient condition for \(u^*(x)\) to be Lipschitz on some domain is that \(\nabla h(x)^Tg(x)\neq 0\) everywhere on the domain.
Proof:
If \(\sup_{u\in\mathbb{R}^m} \nabla h(x)^T(f(x)+g(x)u)<\infty\), then the sup is attained for some \(u\).
\(h\) becomes a (regular) barrier function for \(\tilde{f}(x)=f(x)+g(x)u(x)\) and the theorem from the previous lecture applies.
(Sketch) First, note that \(u^*(x)\) is well-defined since \(\nabla h(x)^T g(x)\neq 0\) whenever \(\nabla h(x)^T f(x)+\alpha(h(x))< 0\) by the CBF condition. \(u^*(x)\) can be considered as a composition of 3 Lipschitz functions and is therefore Lipschitz. Finally, we can verify that \[\nabla h(x)^T(f(x)+g(x)u^*(x))+\alpha(h(x))
=
\begin{cases}
\nabla h(x)^Tf(x) +\alpha(h(x))&\text{if } \nabla h(x)^Tf(x) +\alpha(h(x))\geq 0\\
0&\text{otherwise}
\end{cases}
\geq 0.\]
where \(C(\mu,x)\) is some cost function that is convex in \(\mu\) for each fixed state \(x\).
Example 1: Suppose \(k(x):\mathbb{R}^n\to\mathbb{R}^m\) is some nominal feedback controller designed for some other purpose (e.g., performance objectives). Choose \(C(\mu,x)=\|\mu-k(x)\|_2^2\). The result is a quadratic program (with affine constraints) to compute \(u(x)\) at each \(x\).
Raises questions about solving a QP in real-time online; care must be taken with discretization values, etc.
Convex solvers are fast enough that they can be included “in-the-loop” and have been for applications like stable bipedal locomotion and quadrotor control.
The CBF can be enforced alongside a nominal controller using a CBF-QP. For example, consider the pendulum with a sinusoid-tracking controller \(u_{des}\) obtained through input-output linearization. A minimally-invasive CBF-QP would be:
\[\begin{aligned}
u^* = \underset{u}{\text{minimize}} \;&\|u - u_{des}\|_2^2 \\
\text{subject to} \;&L_fh +L_gh u + \gamma h \geq 0
\end{aligned}\]
Show code
import cvxpy as cpdef io_controller(x,t): # sinusoid tracking controller theta, thetadot = x[0], x[1] epsilon =10 period =1.0 xdes = np.deg2rad(45) * np.sin(2* np.pi * t / period) # Desired position in radians dxdes = np.deg2rad(45)*np.cos(2* np.pi * t / period) * (2* np.pi / period) # Desired velocity in radians/sec v =- (epsilon**2* (theta-xdes)) - (2*epsilon * (thetadot-dxdes))return (g_gravity/L_vel)*np.sin(theta) + vdef cbf_tracking_controller(x, gamma, t): theta, thetadot = x[0], x[1]# Get desired input from io_controller u_des = io_controller(x, t)# Define CBF components Lf = Lf_h(x) Lg = Lg_h(x) hx = h(x)if Lg ==0and Lf + gamma * hx <0:raiseValueError("Lg_h(x) * u cannot be zero. Adjust the control barrier function or system dynamics.")# Quadratic Program u = cp.Variable(1) cost = cp.quad_form(u - u_des, np.eye(1)) cbf_constraint = Lf + Lg * u + gamma * hx >=0 prob = cp.Problem(cp.Minimize(cost), [cbf_constraint]) prob.solve()# Use this control input u_safe =float(u.value[0])if prob.status != cp.OPTIMAL:print("Problem is not optimal Using default controller.") u_safe = u_deselse: u_diff = u.value - u_des# print("Control input difference:", u_diff)return u_safedef make_tracking_ode(gamma):def pendulum(t, x): theta, thetadot = x[0], x[1] u = io_controller(x,t) if gamma isNoneelse cbf_tracking_controller(x, gamma, t) thetaddot =-g_gravity * np.sin(theta) + ureturn [thetadot, thetaddot]return pendulum# Animationsol_cbf = solve_ivp(make_tracking_ode(100.0), (0, 10), x0, t_eval=t_eval, **opts)sol_nominal = solve_ivp(make_tracking_ode(None), (0, 10), x0, t_eval=t_eval, **opts)HTML(make_pendulum_anim(sol_cbf, title='Pendulum Reference Tracking ($\\gamma=100$)', sol_ghost=sol_nominal).to_jshtml())
Need for Higher-Order CBFs
For CBFs to be implemented as previously discussed, we need to ensure that \(\nabla h(x)^Tg(x) = L_g h(x) \neq 0\) for all \(x\) in the domain of interest. However, this would preclude us from selecting a CBF to limit the pendulum position, i.e., \(h(x) := \theta_{\max}^2 - x_1^2\). In this case, we need higher-order CBFs. We will cover these in the next lecture.