"""Defines a class that dictates how to communicate with the motors.Modified to work with Robstride motors.TODO: create a generic motor class that can work with any motor type."""importtimefromdataclassesimportdataclassfromtypingimportAnyimportfirmware.robstride_motors.clientasrobstridefromfirmware.motor_utils.motor_utilsimportMotorInterface,MotorParams
[docs]classRobstrideMotor(MotorInterface):"""A class to interface with a motor over a CAN bus."""CALIBRATION_SPEED=0.5# rad/sdef__init__(self,motor_id:int,control_params:RobstrideParams,client:robstride.Client)->None:"""Initializes the motor. Args: motor_id: The ID of the motor. control_params: The control parameters for the motor. client: The CAN bus interface. """super().__init__(motor_id,control_params,client)self.disable()self.set_operation_mode(robstride.RunMode.Position)self.enable()self.get_position()self.set_control_params()print(f"Motor {motor_id} initialized")
[docs]defset_operation_mode(self,mode:robstride.RunMode)->None:"""Sets the operation mode of the motor to position, speed, or current control! Args: mode: The mode to set the motor to. """self.communication_interface.write_param(self.motor_id,"run_mode",mode)self.communication_interface.enable(self.motor_id)
[docs]defset_position(self,position:float,**kwargs:Any)->None:"""Sets the position of the motor using force position hybrid control. Args: position: The position to set the motor to. kwargs: Additional arguments to pass to the motor. """resp=self.communication_interface.write_param(self.motor_id,"loc_ref",position)self.position=resp.angle
[docs]defset_zero_position(self)->None:"""Sets the zero position of the motor."""_=self.communication_interface.zero_pos(self.motor_id)self.set_position(0)
[docs]defget_position(self)->float:"""Updates the value of the motor's position attribute. Args: wait_time: how long to wait for a response from the motor read_only: whether to read the position value or not Returns: "Valid" if the message is valid, "Invalid" otherwise """resp=self.communication_interface.read_param(self.motor_id,"mechpos")iftype(resp)isfloat:self.position=respreturnself.position
[docs]defget_speed(self)->float:"""Updates the value of the motor's speed attribute. Args: wait_time: how long to wait for a response from the motor read_only: whether to read the speed value or not Returns: "Valid" if the message is valid, "Invalid" otherwise """resp=self.communication_interface.read_param(self.motor_id,"mechvel")iftype(resp)isfloat:self.speed=respreturnself.speed
[docs]defget_current(self)->float:"""Updates the value of the motor's current attribute. Args: wait_time: how long to wait for a response from the motor read_only: whether to read the current value or not Returns: "Valid" if the message is valid, "Invalid" otherwise """resp=self.communication_interface.read_param(self.motor_id,"iqf")iftype(resp)isfloat:self.current=respreturnself.current
[docs]defset_current(self,current:float)->None:"""Sets the current of the motor. Args: current: The current to set the motor to. """self.communication_interface.write_param(self.motor_id,"iq_ref",current)
[docs]defset_speed(self,speed:float)->None:"""Sets the speed of the motor. Args: speed: The speed to set the motor to in rad/s. """self.communication_interface.write_param(self.motor_id,"spd_ref",speed)
[docs]defcalibrate(self,current_limit:float=10)->None:"""Calibrates the motor assuming the existence of hard stops. Args: current_limit: The current limit to use during calibration. """print(f"Calibrating {self}...")# Set run mode to speedself.set_operation_mode(robstride.RunMode.Speed)# Set speed and check for stallself.set_speed(self.CALIBRATION_SPEED)whileabs(self.get_current())<current_limit:print(f"Current: {self.get_current()}")time.sleep(0.1)# Set speed to 0self.set_speed(0)# Read position and set as highhigh=self.get_position()print(f"High: {high}")# Set speed and check for stallself.set_speed(-self.CALIBRATION_SPEED)time.sleep(0.1)whileabs(self.get_current())<current_limit:print(f"Current: {self.get_current()}")time.sleep(0.1)# Set speed to 0self.set_speed(0)# Read position and set as lowlow=self.get_position()print(f"Low: {low}")# Set run mode to positionself.set_operation_mode(robstride.RunMode.Position)setpoint=(high+low)/2# Set zero positionself.set_position(setpoint)print(f"Zeroing at {setpoint}")whileabs(self.get_position()-setpoint)>0.01:time.sleep(0.1)self.set_zero_position()print(f"{self} calibrated")