Source code for psj_lib.devices.base.capabilities.pid_controller

"""PID controller parameter configuration."""

from .piezo_capability import PiezoCapability


[docs] class PIDController(PiezoCapability): """Configure PID controller parameters for closed-loop operation. Provides access to Proportional, Integral, Derivative, and differential filter parameters that control closed-loop positioning behavior. PID Control Theory: - P (Proportional): Response proportional to error. Higher = faster but may overshoot - I (Integral): Eliminates steady-state error. Too high causes oscillation - D (Derivative): Dampens oscillation. Higher = more damping but noise sensitive - TF (Diff Filter): Filters derivative term to reduce noise amplification Example: >>> pid = channel.pid_controller >>> # Set aggressive PID for fast response >>> await pid.set(p=10.0, i=5.0, d=0.5, diff_filter=100.0) >>> # Read current parameters >>> p = await pid.get_p() >>> i = await pid.get_i() >>> print(f"PID: P={p}, I={i}") Note: - Improper tuning causes poor performance and possible damage to actuator! - Start with conservative values and tune incrementally - Only active when closed-loop control is enabled - Parameter ranges are device-specific """ CMD_P = "PID_CONTROLLER_P" CMD_I = "PID_CONTROLLER_I" CMD_D = "PID_CONTROLLER_D" CMD_TF = "PID_CONTROLLER_TF"
[docs] async def set( self, p: float | None = None, i: float | None = None, d: float | None = None, diff_filter: float | None = None ) -> None: """Set PID controller parameters. Parameters are set independently - only provided values are updated. Omitted parameters remain unchanged. Args: p: Proportional gain (higher = faster response, more overshoot) i: Integral gain (eliminates steady-state error) d: Derivative gain (dampens oscillation) diff_filter: Differential filter time constant (noise reduction) Example: >>> # Set only P and I, leave D and filter unchanged >>> await channel.pid_controller.set(p=8.0, i=4.0) >>> >>> # Fine-tune all parameters >>> await channel.pid_controller.set( ... p=12.0, i=6.0, d=0.01, diff_filter=150.0 ... ) Note: - Units and ranges are device-specific - Test parameter changes with small movements first - Higher D gains amplify sensor noise (use diff_filter) """ if p is not None: await self._write(self.CMD_P, [p]) if i is not None: await self._write(self.CMD_I, [i]) if d is not None: await self._write(self.CMD_D, [d]) if diff_filter is not None: await self._write(self.CMD_TF, [diff_filter])
[docs] async def get_p(self) -> float: """Get proportional gain parameter. Returns: Current P (proportional) gain value Example: >>> p_gain = await channel.pid_controller.get_p() """ result = await self._write(self.CMD_P) return float(result[0])
[docs] async def get_i(self) -> float: """Get integral gain parameter. Returns: Current I (integral) gain value Example: >>> i_gain = await channel.pid_controller.get_i() """ result = await self._write(self.CMD_I) return float(result[0])
[docs] async def get_d(self) -> float: """Get derivative gain parameter. Returns: Current D (derivative) gain value Example: >>> d_gain = await channel.pid_controller.get_d() """ result = await self._write(self.CMD_D) return float(result[0])
[docs] async def get_diff_filter(self) -> float: """Get differential filter time constant. Returns: Current differential filter value Example: >>> tf = await channel.pid_controller.get_diff_filter() """ result = await self._write(self.CMD_TF) return float(result[0])