Skip to content

types

PID Calibration Models

Data types, enums, and dataclasses for the PID calibration tool.

CommandKind #

Bases: Enum

Determines which command protocol a PID type uses.

Source code in cogip/tools/firmware_pid_calibration/types.py
28
29
30
31
32
33
34
35
36
37
class CommandKind(Enum):
    """Determines which command protocol a PID type uses."""

    POSE = "pose"
    SPEED = "speed"

    @property
    def layout_path(self) -> Path:
        """Path to the graph layout YAML file for this command kind."""
        return Path(__file__).parent / f"pid_graph_{self.value}_layout.yaml"

layout_path property #

Path to the graph layout YAML file for this command kind.

MotionKind #

Bases: Enum

Determines which motion strategy a PID type uses.

Source code in cogip/tools/firmware_pid_calibration/types.py
21
22
23
24
25
class MotionKind(Enum):
    """Determines which motion strategy a PID type uses."""

    LINEAR = "linear"
    ANGULAR = "angular"

PidGains dataclass #

PID gains (Kp, Ki, Kd) for a single controller.

Source code in cogip/tools/firmware_pid_calibration/types.py
127
128
129
130
131
132
133
134
135
136
137
@dataclass
class PidGains:
    """PID gains (Kp, Ki, Kd) for a single controller."""

    kp: float = 0.0
    ki: float = 0.0
    kd: float = 0.0

    def copy(self) -> "PidGains":
        """Create a copy of the gains."""
        return PidGains(kp=self.kp, ki=self.ki, kd=self.kd)

copy() #

Create a copy of the gains.

Source code in cogip/tools/firmware_pid_calibration/types.py
135
136
137
def copy(self) -> "PidGains":
    """Create a copy of the gains."""
    return PidGains(kp=self.kp, ki=self.ki, kd=self.kd)

PidType #

Bases: Enum

Types of PID controllers.

Each member is the single source of truth for: - label: human-readable name (also used as telemetry graph plot title) - description: longer explanation - param_names: (kp_name, ki_name, kd_name) for firmware parameters - controller: PB_ControllerEnum to activate - command_kind: whether to use pose or speed commands - motion_kind: which MotionKind to use for calibration - default_distance: default test distance in mm or deg (pose types only) - default_speed: default test speed in mm/s or deg/s (speed types only) - default_duration_ms: default speed command duration in ms (speed types only)

The index is auto-computed from declaration order (1-based).

Source code in cogip/tools/firmware_pid_calibration/types.py
 40
 41
 42
 43
 44
 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
class PidType(Enum):
    """Types of PID controllers.

    Each member is the single source of truth for:
    - label: human-readable name (also used as telemetry graph plot title)
    - description: longer explanation
    - param_names: (kp_name, ki_name, kd_name) for firmware parameters
    - controller: PB_ControllerEnum to activate
    - command_kind: whether to use pose or speed commands
    - motion_kind: which MotionKind to use for calibration
    - default_distance: default test distance in mm or deg (pose types only)
    - default_speed: default test speed in mm/s or deg/s (speed types only)
    - default_duration_ms: default speed command duration in ms (speed types only)

    The index is auto-computed from declaration order (1-based).
    """

    LINEAR_POSE = dict(
        label="Linear Pose",
        description="Position control (distance)",
        param_names=("linear_pose_pid_kp", "linear_pose_pid_ki", "linear_pose_pid_kd"),
        controller=PB_ControllerEnum.QUADPID_TRACKER,
        command_kind=CommandKind.POSE,
        motion_kind=MotionKind.LINEAR,
        default_distance=DEFAULT_LINEAR_DISTANCE_MM,
    )
    ANGULAR_POSE = dict(
        label="Angular Pose",
        description="Position control (rotation)",
        param_names=("angular_pose_pid_kp", "angular_pose_pid_ki", "angular_pose_pid_kd"),
        controller=PB_ControllerEnum.QUADPID_TRACKER,
        command_kind=CommandKind.POSE,
        motion_kind=MotionKind.ANGULAR,
        default_distance=DEFAULT_ANGULAR_DISTANCE_DEG,
    )
    LINEAR_SPEED = dict(
        label="Linear Speed",
        description="Velocity control (linear)",
        param_names=("linear_speed_pid_kp", "linear_speed_pid_ki", "linear_speed_pid_kd"),
        controller=PB_ControllerEnum.TRACKER_SPEED_TUNING,
        command_kind=CommandKind.SPEED,
        motion_kind=MotionKind.LINEAR,
        default_speed=DEFAULT_LINEAR_SPEED_MM_S,
        default_duration_ms=DEFAULT_SPEED_DURATION_MS,
    )
    ANGULAR_SPEED = dict(
        label="Angular Speed",
        description="Velocity control (angular)",
        param_names=("angular_speed_pid_kp", "angular_speed_pid_ki", "angular_speed_pid_kd"),
        controller=PB_ControllerEnum.TRACKER_SPEED_TUNING,
        command_kind=CommandKind.SPEED,
        motion_kind=MotionKind.ANGULAR,
        default_speed=DEFAULT_ANGULAR_SPEED_DEG_S,
        default_duration_ms=DEFAULT_SPEED_DURATION_MS,
    )

    def __init__(self, config: dict):
        self.index = len(self.__class__.__members__) + 1
        self.label = config["label"]
        self.description = config["description"]
        self.param_names = config["param_names"]
        self.controller = config["controller"]
        self.command_kind = config["command_kind"]
        self.motion_kind = config["motion_kind"]
        self.default_distance = config.get("default_distance", 0)
        self.default_speed = config.get("default_speed", 0)
        self.default_duration_ms = config.get("default_duration_ms", 0)

    @classmethod
    def from_index(cls, index: int) -> "PidType":
        """Get PidType by its index number."""
        for pid_type in cls:
            if pid_type.index == index:
                return pid_type
        raise ValueError(f"Invalid PID type index: {index}")

    @classmethod
    def choices(cls) -> list[str]:
        """Return list of valid index choices as strings."""
        return [str(pid_type.index) for pid_type in cls]

    @classmethod
    def table_rows(cls) -> list[tuple[str, str, str]]:
        """Return table rows: (index, label, description)."""
        return [(str(pt.index), pt.label, pt.description) for pt in cls]

choices() classmethod #

Return list of valid index choices as strings.

Source code in cogip/tools/firmware_pid_calibration/types.py
116
117
118
119
@classmethod
def choices(cls) -> list[str]:
    """Return list of valid index choices as strings."""
    return [str(pid_type.index) for pid_type in cls]

from_index(index) classmethod #

Get PidType by its index number.

Source code in cogip/tools/firmware_pid_calibration/types.py
108
109
110
111
112
113
114
@classmethod
def from_index(cls, index: int) -> "PidType":
    """Get PidType by its index number."""
    for pid_type in cls:
        if pid_type.index == index:
            return pid_type
    raise ValueError(f"Invalid PID type index: {index}")

table_rows() classmethod #

Return table rows: (index, label, description).

Source code in cogip/tools/firmware_pid_calibration/types.py
121
122
123
124
@classmethod
def table_rows(cls) -> list[tuple[str, str, str]]:
    """Return table rows: (index, label, description)."""
    return [(str(pt.index), pt.label, pt.description) for pt in cls]