Skip to content

CLF-CBF Config

CLF-CBF Configuration class

Defining the problem:

As with the CBF, we require implementation of the dynamics functions f and g, as well as the barrier function(s) h. Now, with the CLF-CBF, we require the definition of the Control Lyapunov Function (CLF) V. This CLF must be a positive definite function of the state.

Depending on the relative degree of your barrier function(s), you should implement the h_1 method (for a relative-degree-1 barrier), and/or the h_2 method (for a relative-degree-2 barrier).

Likewise, for the CLF, you should implement the V_1 method (for a relative-degree-1 CLF), and/or the V_2 method (for a relative-degree-2 CLF).

Tuning the CLF-CBF:

As with the CBF, the CLF-CBF config allows for adjustment of the class-Kappa CBF "gain" functions alpha and alpha_2. Additionally, the CLF-CBF config allows for adjustment of the class-Kappa CLF "gain" functions gamma and gamma_2 (for relative-degree-2 CLFs).

The CLF-CBF config also allows for adjustment of the quadratic control term H and the linear control term F in the CLF objective. These can be used to adjust the weightings between inputs, for instance.

Relaxation:

If the CBF constraints are not necessarily globally feasible, you can enable further relaxation in the CLFCBFConfig. However, since the CLF constraint was already relaxed with respect to the CBF constraint, this means that tuning the relaxation parameters is critical. In general, the penalty on the CBF relaxation should be much higher than the penalty on the CLF relaxation.

If strict enforcement of the CLF-CBF is desired, your higest-level controller should handle the case where the QP is infeasible.

CLFCBFConfig

Bases: CBFConfig

Control Lyapunov Function / Control Barrier Function (CLF-CBF) configuration class.

This is an abstract class which requires implementation of the following methods:

  • f(z): The uncontrolled dynamics function
  • g(z): The control affine dynamics function
  • h_1(z) and/or h_2(z): The barrier function(s), of relative degree 1 and/or 2
  • V_1(z) and/or V_2(z): The Lyapunov function(s), of relative degree 1 and/or 2

For finer-grained control over the CLF-CBF, the following methods may be updated from their defaults:

  • alpha(h): "Gain" of the CBF
  • alpha_2(h_2): "Gain" of the relative-degree-2 CBFs, if applicable
  • gamma(v): "Gain" of the CLF
  • gamma_2(v): "Gain" of the relative-degree-2 CLFs, if applicable
  • H(z): Quadratic control term in the CLF objective
  • F(z): Linear control term in the CLF objective

Parameters:

Name Type Description Default
n int

State dimension

required
m int

Control dimension

required
u_min ArrayLike

Minimum control input, shape (m,). Defaults to None (Unconstrained).

None
u_max ArrayLike

Maximum control input, shape (m,). Defaults to None (Unconstrained).

None
relax_cbf bool

Whether to allow for relaxation in the CBF QP. Defaults to True.

True
cbf_relaxation_penalty float

Penalty on the slack variable in the relaxed CBF QP. Defaults to 1e4. Note: only applies if relax_cbf is True.

10000.0
clf_relaxation_penalty float

Penalty on the CLF slack variable when enforcing the CBF. Defaults to 1e2

100.0
solver_tol float

Tolerance for the QP solver. Defaults to 1e-3.

0.001
init_args tuple

If your barrier function relies on additional arguments other than just the state, include an initial seed for these arguments here. This is to help test the output of the barrier function. Defaults to ().

()
Source code in cbfpy/config/clf_cbf_config.py
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
class CLFCBFConfig(CBFConfig):
    """Control Lyapunov Function / Control Barrier Function (CLF-CBF) configuration class.

    This is an abstract class which requires implementation of the following methods:

    - `f(z)`: The uncontrolled dynamics function
    - `g(z)`: The control affine dynamics function
    - `h_1(z)` and/or `h_2(z)`: The barrier function(s), of relative degree 1 and/or 2
    - `V_1(z)` and/or `V_2(z)`: The Lyapunov function(s), of relative degree 1 and/or 2

    For finer-grained control over the CLF-CBF, the following methods may be updated from their defaults:

    - `alpha(h)`: "Gain" of the CBF
    - `alpha_2(h_2)`: "Gain" of the relative-degree-2 CBFs, if applicable
    - `gamma(v)`: "Gain" of the CLF
    - `gamma_2(v)`: "Gain" of the relative-degree-2 CLFs, if applicable
    - `H(z)`: Quadratic control term in the CLF objective
    - `F(z)`: Linear control term in the CLF objective

    Args:
        n (int): State dimension
        m (int): Control dimension
        u_min (ArrayLike, optional): Minimum control input, shape (m,). Defaults to None (Unconstrained).
        u_max (ArrayLike, optional): Maximum control input, shape (m,). Defaults to None (Unconstrained).
        relax_cbf (bool, optional): Whether to allow for relaxation in the CBF QP. Defaults to True.
        cbf_relaxation_penalty (float, optional): Penalty on the slack variable in the relaxed CBF QP. Defaults to 1e4.
            Note: only applies if relax_cbf is True.
        clf_relaxation_penalty (float): Penalty on the CLF slack variable when enforcing the CBF. Defaults to 1e2
        solver_tol (float, optional): Tolerance for the QP solver. Defaults to 1e-3.
        init_args (tuple, optional): If your barrier function relies on additional arguments other than just the state,
            include an initial seed for these arguments here. This is to help test the output of the barrier function.
            Defaults to ().
    """

    def __init__(
        self,
        n: int,
        m: int,
        u_min: Optional[ArrayLike] = None,
        u_max: Optional[ArrayLike] = None,
        relax_cbf: bool = True,
        cbf_relaxation_penalty: float = 1e4,
        clf_relaxation_penalty: float = 1e2,
        solver_tol: float = 1e-3,
        init_args: tuple = (),
    ):
        super().__init__(
            n,
            m,
            u_min,
            u_max,
            relax_cbf,
            cbf_relaxation_penalty,
            solver_tol,
            init_args,
        )

        if not (
            isinstance(clf_relaxation_penalty, (int, float))
            and clf_relaxation_penalty > 0
        ):
            raise ValueError(
                f"Invalid clf_relaxation_penalty: {clf_relaxation_penalty}. Must be a positive value."
            )
        self.clf_relaxation_penalty = float(clf_relaxation_penalty)

        # Check on CLF dimension
        z_test = jnp.ones(self.n)
        v1_test = self.V_1(jnp.ones(self.n))
        v2_test = self.V_2(jnp.ones(self.n))
        if v1_test.ndim != 1 or v2_test.ndim != 1:
            raise ValueError("CLF(s) must output 1D arrays")
        self.num_rd1_clf = v1_test.shape[0]
        self.num_rd2_clf = v2_test.shape[0]
        self.num_clf = self.num_rd1_clf + self.num_rd2_clf
        if self.num_clf == 0:
            raise ValueError(
                "No Lyanpunov functions provided."
                + "\nYou can implement this via the V_1 and/or V_2 methods in your config class"
            )
        v_test = jnp.concatenate([v1_test, v2_test])
        gamma_test = self.gamma(v_test)
        gamma_2_test = self.gamma_2(v2_test)
        if gamma_test.shape != (self.num_clf,):
            raise ValueError(
                f"Invalid shape for gamma(V(z)): {gamma_test.shape}. Expected ({self.num_clf},)"
                + "\nCheck that the output of the gamma() function matches the number of CLFs"
            )
        if gamma_2_test.shape != (self.num_rd2_clf,):
            raise ValueError(
                f"Invalid shape for gamma_2(V_2(z)): {gamma_2_test.shape}. Expected ({self.num_rd2_clf},)"
                + "\nCheck that the output of the gamma_2() function matches the number of RD2 CLFs"
            )
        self._check_class_kappa(self.gamma, self.num_clf)
        self._check_class_kappa(self.gamma_2, self.num_rd2_clf)
        H_test = self.H(z_test)
        if H_test.shape != (self.m, self.m):
            raise ValueError(
                f"Invalid shape for H(z): {H_test.shape}. Expected ({self.m}, {self.m})"
            )
        if not self._is_symmetric_psd(H_test):
            raise ValueError("H(z) must be symmetric positive semi-definite")
        # TODO: add a warning if the CLF relaxation penalty > the QP relaxation penalty?

    def V_1(self, z: ArrayLike) -> Array:
        """Relative-Degree-1 Control Lyapunov Function (CLF)

        A CLF is a positive-definite function which evaluates to zero at the equilibrium point, and is
        such that there exists a control input u which makes the time-derivative of the CLF negative.

        Relative degree can generally be thought of as the number of integrations required between the
        input and output of the system. For instance, a (relative-degree-1) CLF based on velocities,
        with acceleration inputs, will be directly modified on the next timestep.

        At least one of `V_1` or `V_2` must be implemented. Multiple CLFs is possible, but generally, these cannot all
        be strictly enforced.

        Args:
            z (ArrayLike): State, shape (n,)

        Returns:
            Array: V(z): The RD1 CLF evaluation, shape (num_rd1_clf,)
        """
        return jnp.array([])

    # TODO: Check if the math behind this is actually valid
    def V_2(self, z: ArrayLike) -> Array:
        """Relative-Degree-2 (high-order) Control Lyapunov Function (CLF)

        A CLF is a positive-definite function which evaluates to zero at the equilibrium point, and is
        such that there exists a control input u which makes the time-derivative of the CLF negative.

        Relative degree can generally be thought of as the number of integrations required between the
        input and output of the system. For instance, a (relative-degree-2) CLF based on position,
        with acceleration inputs, will be modified in two timesteps: the acceleration changes the velocity,
        which then changes the position.

        At least one of `V_1` or `V_2` must be implemented. Multiple CLFs is possible, but generally, these cannot all
        be strictly enforced.

        Args:
            z (ArrayLike): State, shape (n,)

        Returns:
            Array: V(z): The RD2 CLF evaluation, shape (num_rd2_clf,)
        """
        return jnp.array([])

    def gamma(self, v: ArrayLike) -> Array:
        """A class Kappa function, dictating the "gain" of the CLF

        For reference, a class Kappa function is a monotonically increasing function which passes through the origin.

        The default implementation can be overridden for more fine-grained control over the CLF

        Args:
            v (ArrayLike): Evaluation of the CLF(s) at the current state, shape (num_clf,).

        Returns:
            Array: gamma(V(z)), shape (num_clf,).
        """
        return v

    def gamma_2(self, v_2: ArrayLike) -> Array:
        """A second class Kappa function, dictating the "gain" associated with the derivative of the CLF

        For reference, a class Kappa function is a monotonically increasing function which passes through the origin.

        The default implementation can be overridden for more fine-grained control over the CLF

        Args:
            v_2 (ArrayLike): Evaluation of the RD2 CLF(s) at the current state, shape (num_rd2_clf,)

        Returns:
            Array: gamma_2(V_2(z)), shape (num_rd2_clf,)
        """
        return v_2

    def H(self, z: ArrayLike) -> Array:
        """Matrix defining the quadratic control term in the CLF objective (minimize 0.5 * u^T H u + F^T u)

        **Must be PSD!**

        The default implementation is just the (m x m) identity matrix, but this can be overridden
        for more fine-grained control over the objective

        Args:
            z (ArrayLike): State, shape (n,)

        Returns:
            Array: H, shape (m, m)
        """
        return jnp.eye(self.m)

    def F(self, z: ArrayLike) -> Array:
        """Vector defining the linear term in the CLF objective (minimize 0.5 * u^T H u + F^T u)

        The default implementation is a zero vector, but this can be overridden
        for more fine-grained control over the objective

        Args:
            z (ArrayLike): State, shape (n,)

        Returns:
            Array: F, shape (m,)
        """
        return jnp.zeros(self.m)

f(z) abstractmethod

The uncontrolled dynamics function. Possibly nonlinear, and locally Lipschitz

i.e. the function f, such that z_dot = f(z) + g(z) u

Parameters:

Name Type Description Default
z ArrayLike

The state, shape (n,)

required

Returns:

Name Type Description
Array Array

Uncontrolled state derivative component, shape (n,)

Source code in cbfpy/config/cbf_config.py
202
203
204
205
206
207
208
209
210
211
212
213
214
@abstractmethod
def f(self, z: ArrayLike) -> Array:
    """The uncontrolled dynamics function. Possibly nonlinear, and locally Lipschitz

    i.e. the function f, such that z_dot = f(z) + g(z) u

    Args:
        z (ArrayLike): The state, shape (n,)

    Returns:
        Array: Uncontrolled state derivative component, shape (n,)
    """
    pass

g(z) abstractmethod

The control affine dynamics function. Locally Lipschitz.

i.e. the function g, such that z_dot = f(z) + g(z) u

Parameters:

Name Type Description Default
z ArrayLike

The state, shape (n,)

required

Returns:

Name Type Description
Array Array

Control matrix, shape (n, m)

Source code in cbfpy/config/cbf_config.py
216
217
218
219
220
221
222
223
224
225
226
227
228
@abstractmethod
def g(self, z: ArrayLike) -> Array:
    """The control affine dynamics function. Locally Lipschitz.

    i.e. the function g, such that z_dot = f(z) + g(z) u

    Args:
        z (ArrayLike): The state, shape (n,)

    Returns:
        Array: Control matrix, shape (n, m)
    """
    pass

h_1(z, *h_args)

Relative-degree-1 barrier function(s).

A (zeroing) CBF is a continuously-differentiable function h, such that for any state z in the interior of the safe set, h(z) should be > 0, and h(z) = 0 on the boundary. When in the unsafe set, h(z) < 0.

Relative degree can generally be thought of as the number of integrations required between the input and output of the system. For instance, a (relative-degree-1) CBF based on velocities, with acceleration inputs, will be directly modified on the next timestep.

If your barrier function is relative-degree-2, or if you would like to enforce additional barriers which are relative-degree-2, use the h_2 method.

Parameters:

Name Type Description Default
z ArrayLike

State, shape (n,)

required
*h_args

Optional additional arguments for the barrier function. Note: If using additional args with your barrier, these must be a static shape/type, or else this will trigger a recompilation in Jax.

()

Returns:

Name Type Description
Array Array

Barrier function(s), shape (num_rd1_barr,)

Source code in cbfpy/config/cbf_config.py
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
def h_1(self, z: ArrayLike, *h_args) -> Array:
    """Relative-degree-1 barrier function(s).

    A (zeroing) CBF is a continuously-differentiable function h, such that for any state z in the interior of
    the safe set, h(z) should be > 0, and h(z) = 0 on the boundary. When in the unsafe set, h(z) < 0.

    Relative degree can generally be thought of as the number of integrations required between the
    input and output of the system. For instance, a (relative-degree-1) CBF based on velocities,
    with acceleration inputs, will be directly modified on the next timestep.

    If your barrier function is relative-degree-2, or if you would like to enforce additional barriers
    which are relative-degree-2, use the `h_2` method.

    Args:
        z (ArrayLike): State, shape (n,)
        *h_args: Optional additional arguments for the barrier function. Note: If using additional args with your
            barrier, these must be a static shape/type, or else this will trigger a recompilation in Jax.

    Returns:
        Array: Barrier function(s), shape (num_rd1_barr,)
    """
    return jnp.array([])

h_2(z, *h_args)

Relative-degree-2 (high-order) barrier function(s).

A (zeroing) CBF is a continuously-differentiable function h, such that for any state z in the interior of the safe set, h(z) should be > 0, and h(z) = 0 on the boundary. When in the unsafe set, h(z) < 0.

Relative degree can generally be thought of as the number of integrations required between the input and output of the system. For instance, a (relative-degree-2) CBF based on position, with acceleration inputs, will be modified in two timesteps: the acceleration changes the velocity, which then changes the position.

If your barrier function is relative-degree-1, or if you would like to enforce additional barriers which are relative-degree-1, use the h_1 method.

Parameters:

Name Type Description Default
z ArrayLike

State, shape (n,)

required
*h_args

Optional additional arguments for the barrier function. Note: If using additional args with your barrier, these must be a static shape/type, or else this will trigger a recompilation in Jax.

()

Returns:

Name Type Description
Array Array

Barrier function(s), shape (num_rd2_barr,)

Source code in cbfpy/config/cbf_config.py
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def h_2(self, z: ArrayLike, *h_args) -> Array:
    """Relative-degree-2 (high-order) barrier function(s).

    A (zeroing) CBF is a continuously-differentiable function h, such that for any state z in the interior of
    the safe set, h(z) should be > 0, and h(z) = 0 on the boundary. When in the unsafe set, h(z) < 0.

    Relative degree can generally be thought of as the number of integrations required between the
    input and output of the system. For instance, a (relative-degree-2) CBF based on position,
    with acceleration inputs, will be modified in two timesteps: the acceleration changes the velocity,
    which then changes the position.

    If your barrier function is relative-degree-1, or if you would like to enforce additional barriers
    which are relative-degree-1, use the `h_1` method.

    Args:
        z (ArrayLike): State, shape (n,)
        *h_args: Optional additional arguments for the barrier function. Note: If using additional args with your
            barrier, these must be a static shape/type, or else this will trigger a recompilation in Jax.

    Returns:
        Array: Barrier function(s), shape (num_rd2_barr,)
    """
    return jnp.array([])

alpha(h)

A class Kappa function, dictating the "gain" of the barrier function(s)

For reference, a class Kappa function is a monotonically increasing function which passes through the origin. A simple example is alpha(h) = h

The default implementation can be overridden for more fine-grained control over the CBF

Parameters:

Name Type Description Default
h ArrayLike

Evaluation of the barrier function(s) at the current state, shape (num_cbf,)

required

Returns:

Name Type Description
Array Array

alpha(h(z)), shape (num_cbf,)

Source code in cbfpy/config/cbf_config.py
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
def alpha(self, h: ArrayLike) -> Array:
    """A class Kappa function, dictating the "gain" of the barrier function(s)

    For reference, a class Kappa function is a monotonically increasing function which passes through the origin.
    A simple example is alpha(h) = h

    The default implementation can be overridden for more fine-grained control over the CBF

    Args:
        h (ArrayLike): Evaluation of the barrier function(s) at the current state, shape (num_cbf,)

    Returns:
        Array: alpha(h(z)), shape (num_cbf,)
    """
    return h

alpha_2(h_2)

A second class Kappa function which dictactes the "gain" associated with the relative-degree-2 barrier functions

For reference, a class Kappa function is a monotonically increasing function which passes through the origin. A simple example is alpha_2(h_2) = h_2

The default implementation can be overridden for more fine-grained control over the CBF

Parameters:

Name Type Description Default
h_2 ArrayLike

Evaluation of the RD2 barrier function(s) at the current state, shape (num_rd2_cbf,)

required

Returns:

Name Type Description
Array Array

alpha_2(h_2(z)), shape (num_rd2_cbf,).

Source code in cbfpy/config/cbf_config.py
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
def alpha_2(self, h_2: ArrayLike) -> Array:
    """A second class Kappa function which dictactes the "gain" associated with the relative-degree-2
    barrier functions

    For reference, a class Kappa function is a monotonically increasing function which passes through the origin.
    A simple example is alpha_2(h_2) = h_2

    The default implementation can be overridden for more fine-grained control over the CBF

    Args:
        h_2 (ArrayLike): Evaluation of the RD2 barrier function(s) at the current state, shape (num_rd2_cbf,)

    Returns:
        Array: alpha_2(h_2(z)), shape (num_rd2_cbf,).
    """
    return h_2

P(z, u_des, *h_args)

Quadratic term in the CBF QP objective (minimize 0.5 * x^T P x + q^T x)

This defaults to 2 * I, which is the value of P when minimizing the standard CBF objective, ||u - u_des||_{2}^{2}

To change the objective, override this method. Note that P must be PSD

Parameters:

Name Type Description Default
z Array

State, shape (n,)

required
u_des Array

Desired control input, shape (m,)

required
*h_args

Optional additional arguments for the barrier function.

()

Returns:

Name Type Description
Array Array

P matrix, shape (m, m)

Source code in cbfpy/config/cbf_config.py
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
def P(self, z: Array, u_des: Array, *h_args) -> Array:
    """Quadratic term in the CBF QP objective (minimize 0.5 * x^T P x + q^T x)

    This defaults to 2 * I, which is the value of P when minimizing the standard CBF objective,
    ||u - u_des||_{2}^{2}

    To change the objective, override this method. **Note that P must be PSD**

    Args:
        z (Array): State, shape (n,)
        u_des (Array): Desired control input, shape (m,)
        *h_args: Optional additional arguments for the barrier function.

    Returns:
        Array: P matrix, shape (m, m)
    """
    return 2 * jnp.eye(self.m)

q(z, u_des, *h_args)

Linear term in the CBF QP objective (minimize 0.5 * x^T P x + q^T x)

This defaults to -2 * u_des, which is the value of q when minimizing the standard CBF objective, ||u - u_des||_{2}^{2}

To change the objective, override this method.

Parameters:

Name Type Description Default
z Array

State, shape (n,)

required
u_des Array

Desired control input, shape (m,)

required
*h_args

Optional additional arguments for the barrier function.

()

Returns:

Name Type Description
Array Array

q vector, shape (m,)

Source code in cbfpy/config/cbf_config.py
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
def q(self, z: Array, u_des: Array, *h_args) -> Array:
    """Linear term in the CBF QP objective (minimize 0.5 * x^T P x + q^T x)

    This defaults to -2 * u_des, which is the value of q when minimizing the standard CBF objective,
    ||u - u_des||_{2}^{2}

    To change the objective, override this method.

    Args:
        z (Array): State, shape (n,)
        u_des (Array): Desired control input, shape (m,)
        *h_args: Optional additional arguments for the barrier function.

    Returns:
        Array: q vector, shape (m,)
    """
    return -2 * u_des

V_1(z)

Relative-Degree-1 Control Lyapunov Function (CLF)

A CLF is a positive-definite function which evaluates to zero at the equilibrium point, and is such that there exists a control input u which makes the time-derivative of the CLF negative.

Relative degree can generally be thought of as the number of integrations required between the input and output of the system. For instance, a (relative-degree-1) CLF based on velocities, with acceleration inputs, will be directly modified on the next timestep.

At least one of V_1 or V_2 must be implemented. Multiple CLFs is possible, but generally, these cannot all be strictly enforced.

Parameters:

Name Type Description Default
z ArrayLike

State, shape (n,)

required

Returns:

Name Type Description
Array Array

V(z): The RD1 CLF evaluation, shape (num_rd1_clf,)

Source code in cbfpy/config/clf_cbf_config.py
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
def V_1(self, z: ArrayLike) -> Array:
    """Relative-Degree-1 Control Lyapunov Function (CLF)

    A CLF is a positive-definite function which evaluates to zero at the equilibrium point, and is
    such that there exists a control input u which makes the time-derivative of the CLF negative.

    Relative degree can generally be thought of as the number of integrations required between the
    input and output of the system. For instance, a (relative-degree-1) CLF based on velocities,
    with acceleration inputs, will be directly modified on the next timestep.

    At least one of `V_1` or `V_2` must be implemented. Multiple CLFs is possible, but generally, these cannot all
    be strictly enforced.

    Args:
        z (ArrayLike): State, shape (n,)

    Returns:
        Array: V(z): The RD1 CLF evaluation, shape (num_rd1_clf,)
    """
    return jnp.array([])

V_2(z)

Relative-Degree-2 (high-order) Control Lyapunov Function (CLF)

A CLF is a positive-definite function which evaluates to zero at the equilibrium point, and is such that there exists a control input u which makes the time-derivative of the CLF negative.

Relative degree can generally be thought of as the number of integrations required between the input and output of the system. For instance, a (relative-degree-2) CLF based on position, with acceleration inputs, will be modified in two timesteps: the acceleration changes the velocity, which then changes the position.

At least one of V_1 or V_2 must be implemented. Multiple CLFs is possible, but generally, these cannot all be strictly enforced.

Parameters:

Name Type Description Default
z ArrayLike

State, shape (n,)

required

Returns:

Name Type Description
Array Array

V(z): The RD2 CLF evaluation, shape (num_rd2_clf,)

Source code in cbfpy/config/clf_cbf_config.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
def V_2(self, z: ArrayLike) -> Array:
    """Relative-Degree-2 (high-order) Control Lyapunov Function (CLF)

    A CLF is a positive-definite function which evaluates to zero at the equilibrium point, and is
    such that there exists a control input u which makes the time-derivative of the CLF negative.

    Relative degree can generally be thought of as the number of integrations required between the
    input and output of the system. For instance, a (relative-degree-2) CLF based on position,
    with acceleration inputs, will be modified in two timesteps: the acceleration changes the velocity,
    which then changes the position.

    At least one of `V_1` or `V_2` must be implemented. Multiple CLFs is possible, but generally, these cannot all
    be strictly enforced.

    Args:
        z (ArrayLike): State, shape (n,)

    Returns:
        Array: V(z): The RD2 CLF evaluation, shape (num_rd2_clf,)
    """
    return jnp.array([])

gamma(v)

A class Kappa function, dictating the "gain" of the CLF

For reference, a class Kappa function is a monotonically increasing function which passes through the origin.

The default implementation can be overridden for more fine-grained control over the CLF

Parameters:

Name Type Description Default
v ArrayLike

Evaluation of the CLF(s) at the current state, shape (num_clf,).

required

Returns:

Name Type Description
Array Array

gamma(V(z)), shape (num_clf,).

Source code in cbfpy/config/clf_cbf_config.py
193
194
195
196
197
198
199
200
201
202
203
204
205
206
def gamma(self, v: ArrayLike) -> Array:
    """A class Kappa function, dictating the "gain" of the CLF

    For reference, a class Kappa function is a monotonically increasing function which passes through the origin.

    The default implementation can be overridden for more fine-grained control over the CLF

    Args:
        v (ArrayLike): Evaluation of the CLF(s) at the current state, shape (num_clf,).

    Returns:
        Array: gamma(V(z)), shape (num_clf,).
    """
    return v

gamma_2(v_2)

A second class Kappa function, dictating the "gain" associated with the derivative of the CLF

For reference, a class Kappa function is a monotonically increasing function which passes through the origin.

The default implementation can be overridden for more fine-grained control over the CLF

Parameters:

Name Type Description Default
v_2 ArrayLike

Evaluation of the RD2 CLF(s) at the current state, shape (num_rd2_clf,)

required

Returns:

Name Type Description
Array Array

gamma_2(V_2(z)), shape (num_rd2_clf,)

Source code in cbfpy/config/clf_cbf_config.py
208
209
210
211
212
213
214
215
216
217
218
219
220
221
def gamma_2(self, v_2: ArrayLike) -> Array:
    """A second class Kappa function, dictating the "gain" associated with the derivative of the CLF

    For reference, a class Kappa function is a monotonically increasing function which passes through the origin.

    The default implementation can be overridden for more fine-grained control over the CLF

    Args:
        v_2 (ArrayLike): Evaluation of the RD2 CLF(s) at the current state, shape (num_rd2_clf,)

    Returns:
        Array: gamma_2(V_2(z)), shape (num_rd2_clf,)
    """
    return v_2

H(z)

Matrix defining the quadratic control term in the CLF objective (minimize 0.5 * u^T H u + F^T u)

Must be PSD!

The default implementation is just the (m x m) identity matrix, but this can be overridden for more fine-grained control over the objective

Parameters:

Name Type Description Default
z ArrayLike

State, shape (n,)

required

Returns:

Name Type Description
Array Array

H, shape (m, m)

Source code in cbfpy/config/clf_cbf_config.py
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
def H(self, z: ArrayLike) -> Array:
    """Matrix defining the quadratic control term in the CLF objective (minimize 0.5 * u^T H u + F^T u)

    **Must be PSD!**

    The default implementation is just the (m x m) identity matrix, but this can be overridden
    for more fine-grained control over the objective

    Args:
        z (ArrayLike): State, shape (n,)

    Returns:
        Array: H, shape (m, m)
    """
    return jnp.eye(self.m)

F(z)

Vector defining the linear term in the CLF objective (minimize 0.5 * u^T H u + F^T u)

The default implementation is a zero vector, but this can be overridden for more fine-grained control over the objective

Parameters:

Name Type Description Default
z ArrayLike

State, shape (n,)

required

Returns:

Name Type Description
Array Array

F, shape (m,)

Source code in cbfpy/config/clf_cbf_config.py
239
240
241
242
243
244
245
246
247
248
249
250
251
def F(self, z: ArrayLike) -> Array:
    """Vector defining the linear term in the CLF objective (minimize 0.5 * u^T H u + F^T u)

    The default implementation is a zero vector, but this can be overridden
    for more fine-grained control over the objective

    Args:
        z (ArrayLike): State, shape (n,)

    Returns:
        Array: F, shape (m,)
    """
    return jnp.zeros(self.m)