def set_offset(self, offset=0):  # Command 17 + 18
        """
        配置偏差,掉电保护 Set servo offset and save to non-volatile memory to survive reboot
        :param self.id: 舵机 id Servo id
        :param offset: 偏差 Offset value
        :return: True = Successful or Error code
        """

        # 设置偏差 Set offset
        result = Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                             Serial_Servo.ANGLE_OFFSET_ADJUST,
                                             offset)
        if type(result) == str: return result
        # 设置为掉电保护 Save to non-volatile memory
        return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                           Serial_Servo.ANGLE_OFFSET_WRITE)
    def set_load(self, mode=1):  # Command 31
        '''
        Set torque bearing mode
        :param mode: desired load mode. 0 = unlaoded, 1 = loaded
        :return: True = success or error code
        '''

        return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                           Serial_Servo.LOAD_MODE_WRITE, mode)
    def unload(self):  # Command 31
        '''
        Set torque free mode
        :param self.id: servo id
        :return: True = success or error code
        '''

        return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                           Serial_Servo.LOAD_MODE_WRITE, 0)
    def stop(self):  # Command 12
        '''
        停止舵机运行 Stop servo immediately
        :param self.id: Servo id
        :return: True = successful or error code
        '''

        return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                           Serial_Servo.MOVE_STOP)
    def servo_mode(self):  # Command 29
        '''
        Set limited angle servo mode
        :param self.id: Servo id
        :return: Success = True or error code
        '''

        return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                           Serial_Servo.MOTOR_MODE_WRITE, 0)
    def set_LED_mode(self, mode=1):  # Command 33
        '''
        Set LED state
        :param self.id: Servo id
        :param mode: LED mode. 0 LED always on. 1 LED off.
        :return:
        '''

        return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                           Serial_Servo.LED_CTRL_WRITE, mode)
    def trigger(self):  # Command 11
        '''
        Triggers movement to new position as defined by previously transmitted
        new_standby_pos. Command 7.
        param self.id: Servo id
        :return: True = successful or error code
        '''

        return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                           Serial_Servo.MOVE_START)
    def get_pos(self):  # Command 28
        '''
        读取舵机当前位置 Read real time servo position
        :param self.id: Servo id
        :return: Current servo position or error code
        '''

        msg = Ctrl.serial_servo_read_cmd(
            self.pi, self.id, Serial_Servo.POS_READ)  # Send data request
        if type(msg) == str: print("Current position read error", msg)
        return msg  # Return value once received
    def get_LED_mode(self):  # Command 34
        '''
        Read LED state
        :param self.id: Servo id
        :return: Return LED mode or error code
        '''

        msg = Ctrl.serial_servo_read_cmd(
            self.pi, self.id, Serial_Servo.LED_CTRL_READ)  # Send data request
        if type(msg) == str: print("LED mode read error", msg)
        return msg  # Return value once received
    def temp(self):  # Command 26
        '''
        读取舵机温度 Read real time servo temperature
        :param self.id: Servo id
        :return: Temperature value or error code
        '''

        msg = Ctrl.serial_servo_read_cmd(
            self.pi, self.id, Serial_Servo.TEMP_READ)  # Send data request
        if type(msg) == str: print("Current temperature read error", msg)
        return msg  # Return value once received
    def set_vin_limits(self, limits=Vin_limits):  # Command 22
        '''
        设置舵机转动范围 Set servo voltage-in alarm limits
        :param self.id: Servo id
        :param limits: (Lower, Upper)
        :return: True = success or error code
        '''

        return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                           Serial_Servo.VIN_LIMIT_WRITE,
                                           limits[0], limits[1])
    def get_LED_err(self):  # Command 36
        '''
        Read LED error code
        :param self.id: Servo id
        :return: Return LED error code (above) or error code
        '''

        msg = Ctrl.serial_servo_read_cmd(
            self.pi, self.id, Serial_Servo.LED_ERROR_READ)  # Send data request
        if type(msg) == str: print("LED error mode read error", msg)
        return msg  # Return value once received
    def set_rotation_limits(self, limits=rotate_limits):  # Command 20
        '''
        设置舵机转动范围 Set the servo rotation limits
        :param self.id: Servo id
        :param limits: (Lower, Upper)
        :return: True = successful or error code
        '''

        return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                           Serial_Servo.ANGLE_LIMIT_WRITE,
                                           limits[0], limits[1])
 def set_pos(self, posn):  # Command 1
     '''
     Move servo to new position
     param self.id: Servo id
     param pos: position for servo to move to
     param tim: time to reach destination in mS
     :return: True or error code
     '''
     return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                        Serial_Servo.MOVE_TIME_WRITE,
                                        posn[0], posn[1])
    def set_temp_limit(self, m_temp=temp_limits[1]):  # Command 24
        '''
        设置舵机最高温度报警 Set servo temperature alarm value
        :param self.id: Servo id
        :param m_temp: Temperature value
        :return: Error value or True = successful
        '''

        return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                           Serial_Servo.TEMP_LIMIT_WRITE,
                                           m_temp)
    def vin(self):  # Command 27
        '''
        读取舵机温度 Read real time servo voltage-in
        :param self.id: Servo id
        :return: Servo voltage-in or error code
        '''

        msg = Ctrl.serial_servo_read_cmd(
            self.pi, self.id, Serial_Servo.VIN_READ)  # Send data request
        if type(msg) == str: print("Input voltage read read error", msg)
        return msg  # Return value once received
    def get_load_mode(self):  # Command 32
        '''
        Read torque/no torque mode
        :param self.id: Servo id
        :return: Return motor load mode or error code.
        0 for unloaded, no torque output. 1 loaded, high torque output
        '''

        msg = Ctrl.serial_servo_read_cmd(
            self.pi, self.id, Serial_Servo.LOAD_MODE_READ)  # Send data request
        if type(msg) == str: print("Motor mode read error", msg)
        return msg  # Return value once received
    def get_temp_limit(self):  # Command 25
        '''
        读取舵机温度报警范围 Read servo temperature alarm value
        :param id: Servo id
        :return: Servo temperature alarm value or error code
        '''

        msg = Ctrl.serial_servo_read_cmd(
            self.pi, self.id,
            Serial_Servo.TEMP_LIMIT_READ)  # Send data request
        if type(msg) == str: print("Temperature limit read error", msg)
        return msg  # Return value once received
    def get_vin_limits(self):  # Command 23
        '''
        读取舵机转动范围 Read servo voltage-in alarm limits
        :param id: Servo id
        :return: 返回元祖 0: 低位  1: 高位 0: (Lower limit, Upper limit) or error code
        '''

        # 发送读取偏差指令 Send read offset command
        msg = Ctrl.serial_servo_read_cmd(
            self.pi, self.id, Serial_Servo.VIN_LIMIT_READ)  # Send data request
        if type(msg) == str: print("Voltage-in limits read error", msg)
        return msg  # Return value once received
    def motor_mode(self):  # Command 30
        '''
        读取舵机当前位置 Read servo motor mode
        :param self.id: Servo id
        :return: Return motor mode or error code (mode, speed)
        '''

        msg = Ctrl.serial_servo_read_cmd(
            self.pi, self.id,
            Serial_Servo.MOTOR_MODE_READ)  # Send data request
        if type(msg) == str: print("Motor mode read error", msg)
        return msg  # Return value once received
    def get_set_pos(self):  # Command 2
        '''
        Read the last servo set position sent.
        THIS IS NOT NECESSARILY THE CURRENT POSITION, it's the last REQUESTED position
        :param self.id: Servo id
        :return: (Position, Speed) or error code
        '''

        msg = Ctrl.serial_servo_read_cmd(
            self.pi, self.id, Serial_Servo.MOVE_TIME_READ)  # Send data request
        if type(msg) == str: print("Get set position error", msg)
        return msg  # Return value once received
    def get_offset(self):  # Command 19
        '''
        读取偏差值 Read offset value
        :param self.id: 舵机号 Servo id
        :return: Offset value or error code
        '''

        # 发送读取偏差指令 Send read offset command
        msg = Ctrl.serial_servo_read_cmd(
            self.pi, self.id,
            Serial_Servo.ANGLE_OFFSET_READ)  # Send data request
        if type(msg) == str: print("Get offset read error", msg)
        return msg  # Return value once received
    def get_rotation_limits(self):  # Command 21
        '''
        读取舵机转动范围 Read the servo rotation limits
        :param self.id: Servo id
        :return: 返回元祖 0: 低位  1: 高位 (Lower limit, Upper limit) or error code
        '''

        # 发送读取偏差指令 Send read rotation limits command
        msg = Ctrl.serial_servo_read_cmd(
            self.pi, self.id,
            Serial_Servo.ANGLE_LIMIT_READ)  # Send data request
        if type(msg) == str: print("Get rotation limits error", msg)
        return msg  # Return value once received
    def set_standby_pos(self, posn):  # Command 7
        '''
        Prepare to move servo to new position.
        Nothing happens until the user transmits trigger. Command 11.
        param self.id: Servo id
        param posn: position for servo to move to
        param tim: time to reach destination in mS
        :return: True = successful or error code
        '''

        return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                           Serial_Servo.MOVE_TIME_WAIT_WRITE,
                                           posn[0], posn[1])
    def set_LED_err(self, mode=7):  # Command 35
        '''
        Set LED error mode
        :param self.id: Servo id
        :param mode: LED error mode. Range 0 to 7
          0      No alarm
          1      Over temperature
          2      Over voltage
          3      Over temperature and over voltage
          4      locked_rotor
          5      Over temperature and locked_rotor
          6      Over voltage and locked_rotor
          7      Over temperature , over voltage and locked_rotor
        :return: True = success or error code
        '''

        return Ctrl.serial_servo_write_cmd(self.pi, self.id,
                                           Serial_Servo.LED_ERROR_WRITE, mode)
        results["vin_limits"] = self.vin_limits  # Command 23
        results["vin"] = self.vin  # Command 27
        results["offset"] = self.offset  # Command 19
        results["load"] = self.load  # Command 32
        results["LED_mode"] = self.LED_mode  # Command 34
        results["LED_err"] = self.LED_err  # Command 36

        print(" ")
        print(" ")
        return results  # Return data


if __name__ == '__main__':
    import pigpio  # Standard Raspberry Pi GPIO library
    pi = pigpio.pi()  # Create a Raspberry Pi object
    Ctrl.portinit(pi)  # Initialise the read/write switch

    servos = ()
    for id in range(Serial_Servo.num_servos):  # Create all servos
        servos += (Serial_Servo(pi, id + 1),
                   )  # tuples are 0 indexed, servos 1 indexed

    print(Serial_Servo.num_servos, Serial_Servo.servo_type,
          " servos under test.")

    results = ()
    for id in range(Serial_Servo.num_servos):  # for all servos
        result = servos[id].servo_state  # Collect status information
        print(result)
        results += (result, )