Best Practices¶
Softstart¶
In robotic prostheses (as well as in general robotics), startup and initialization can often produce abrupt changes in motor torque that are undesirable. These sudden step changes in torque can be unsettling to the user and unececssarily hard on the hardware. To address this, we recommend implementing a softstart mechanism. This approach ensures a smooth ramp-up of torque at startup by scaling the control parameters, such as torque, impedance gains, or position gains, over a specified period.
Although the opensourceleg
library does not include a built-in softstart feature, it is straightforward to implement using the SaturatingRamp
class from the math submodule. Below, we outline the general procedure and provide an example script for a position control implementation. Similar effects for impedance, torque, and velocity control can be achieved following the same steps.
Implementation Steps¶
-
Define a
SaturatingRamp
Instance Create an instance of theSaturatingRamp
class from theopensourceleg.math.math
module, specifying the desired softstart duration (e.g.,SOFT_START_TIME = 1.5
seconds). -
Scale Control Parameters During each iteration of your control loop, use the output of the
SaturatingRamp
instance to scale your control parameters (e.g., torque commands, impedance gains, or position gains). After the ramp duration, theSaturatingRamp
object outputs a value of1
, leaving your parameters unchanged for the remainder of the execution.
Example: Position Control with Softstart¶
Here, we walk through an example script demonstrating softstart in a position control paradigm.
Key Code Snippets¶
- Initialize the
SaturatingRamp
Instance The following snippet shows how to create aSaturatingRamp
instance with the desired softstart time: - Scale Control Gains During each loop iteration, call the ramp's update method and scale the control gains with the result:
ss_scale = soft_start_ramp.update(t)
actpack.set_position_gains(
DEFAULT_POSITION_GAINS.kp * ss_scale,
DEFAULT_POSITION_GAINS.kd * ss_scale,
DEFAULT_POSITION_GAINS.ki * ss_scale,
)
command_position = start_position + (1 / 2) * np.pi
actpack.set_output_position(value=command_position)
Here is the full script:
import numpy as np
from opensourceleg.actuators.base import CONTROL_MODES
from opensourceleg.actuators.dephy import DEFAULT_POSITION_GAINS, DephyActuator
from opensourceleg.logging.logger import Logger
from opensourceleg.math.math import SaturatingRamp
from opensourceleg.utilities.softrealtimeloop import SoftRealtimeLoop
FREQUENCY = 1000
DT = 1 / FREQUENCY
GEAR_RATIO = 1.0
SOFT_START_TIME = 1.0
def softstart_position_control():
position_logger = Logger(
log_path="./logs",
file_name="position_control",
)
actpack = DephyActuator(
port="/dev/ttyACM0", gear_ratio=GEAR_RATIO, frequency=FREQUENCY, debug_level=0, dephy_log=False
)
clock = SoftRealtimeLoop(dt=DT)
soft_start_ramp = SaturatingRamp(SOFT_START_TIME)
with actpack:
actpack.set_control_mode(mode=CONTROL_MODES.POSITION)
actpack.update()
start_position = actpack.output_position
for t in clock:
ss_scale = soft_start_ramp.update(t)
actpack.set_position_gains(
DEFAULT_POSITION_GAINS.kp * ss_scale,
DEFAULT_POSITION_GAINS.kd * ss_scale,
DEFAULT_POSITION_GAINS.ki * ss_scale,
)
command_position = start_position + (1 / 2) * np.pi
actpack.set_output_position(value=command_position)
actpack.update()
position_logger.info(f"Time: {t}; \
Command Position: {command_position}; \
Output Position: {actpack.output_position}")
if __name__ == "__main__":
softstart_position_control()