from behaviors.behavior import Behavior import yaml class KeyframeSkill(Behavior): def __init__(self, agent, file: str): super().__init__(agent) self.keyframe_step: int = 0 self.keyframe_start_time: float = None with open(f"{file}", "r") as f: self.skill_description = yaml.safe_load(f) self.has_symmetry: bool = self.skill_description["symmetry"] self.keyframes: list = self.skill_description["keyframes"] self.kp: float = self.skill_description["kp"] self.kd: float = self.skill_description["kd"] def execute(self, reset, *args, **kwargs): if reset: self.keyframe_step = 0 self.keyframe_start_time = self.agent.world.server_time current_keyframe = self.keyframes[self.keyframe_step] raw_motor_positions = current_keyframe["motor_positions"] current_keyframe_kp = current_keyframe.get("kp", self.kp) current_keyframe_kd = current_keyframe.get("kd", self.kd) p_gains = current_keyframe.get("p_gains", None) d_gains = current_keyframe.get("d_gains", None) for readable_motor_name, position in raw_motor_positions.items(): p_gain = ( p_gains.get(readable_motor_name, current_keyframe_kp) if p_gains else current_keyframe_kp ) d_gain = ( d_gains.get(readable_motor_name, current_keyframe_kd) if d_gains else current_keyframe_kd ) if self.has_symmetry: motor_names, is_inverse_direction = self.agent.robot.MOTOR_SYMMETRY[ readable_motor_name ] for motor_name in motor_names: server_motor_name = self.agent.robot.MOTOR_FROM_READABLE_TO_SERVER[ motor_name ] self.agent.robot.set_motor_target_position( motor_name=server_motor_name, target_position=position if is_inverse_direction else -position, kp=p_gain, kd=d_gain, ) if is_inverse_direction: is_inverse_direction = False # Only inverts one joint else: server_motor_name = self.agent.robot.MOTOR_FROM_READABLE_TO_SERVER[ readable_motor_name ] self.agent.robot.set_motor_target_position( motor_name=server_motor_name, target_position=position, kp=self.kp, kd=self.kd, ) keyframe_time: float = current_keyframe["delta"] elapsed_keyframe_time = self.agent.world.server_time - self.keyframe_start_time if elapsed_keyframe_time >= keyframe_time: self.keyframe_start_time = self.agent.world.server_time self.keyframe_step += 1 if self.keyframe_step >= len(self.keyframes): return True return False def is_ready(self, *args): return True