Skip to content

Upload MCU Information Query

The upload mcu information query can be used by the client to upload the mcu PWM information. This information is required in order to operate a "DumbMCU". The query uses the format:

!s-uINF-[SERVO_COUNT]-[PWM_MIN(0):PWM_MAX(0)]-<...>-[PWM_MIN(SERVO_COUNT-1):PWM_MAX(SERVO_COUNT-1)]-e!
  • [SERVO_COUNT] → A single uint8_t indicating how many servos the mcu has. Since this number cannot be zero, it does not need any offset applied.
  • [PWM_MIN:PWM_MAX] → The information pair PWM_MIN, the minimum PWM signal position; and PWM_MAX, the maximum PWM signal for the given servo; which represent the calibration information for a given servo. These two PWM values are separated by the ASCII character : (uint8_t c=58), and for multiple movements, each information pair PWM_MIN(i):PWM_MAX(i) is separated by a dash - (uint8_t c=45) from the information pair of the following servo calibration. Both of the PWM_SIGNAL (uint16_t values) must have the positive +1 offset applied, as they can take value zero.

The possible responses for this query by the server are either a generic ACK control query, or a negative control query with one of the following control codes:

  • _NACK_InvalidQuery (uint8_t c=255) → If the query format is invalid: contains null-bytes, invalid header or tail sequences, or the query function code is not recognized.
  • _NACK_NoActiveMCU (uint8_t c=254) → If client has not selected a mcu before issuing the command.
  • _NACK_InvalidParameter (uint8_t c=252) → If the query parameters are out of range: a servo id exceeds the selected mcu servo count, or a PWM signal value out of the range [0→32766].
  • _NACK_ServoCountMissmatch (uint8_t c=251) → If the user tries to update information for a different number of servos than the selected mcu has.
  • _NACK_ErrorLoadingMINMAX (uint8_t c=247) → If the PWM information could not be loaded into the server database.

PWM Signal codification

Since the PWM signal can take various bit resolution levels, usually ranging from 8-bit to 16-bit, with >16bit being niche or application-specific territory, the procotol allocates 2 bytes (up to 15-bit pwm resolution) for PWM signals on SRVP queries.

This means that in order to follow the protocol no-zero convention, each individual byte needs to incorporate this offset. This is required because, for values of PWM_SIGNAL<255, the upper-byte will always be zero, and for the specific value PWM_SIGNAL=256, the lower-byte will be zero.

How is offset applied

The offset is introduced by fixing the most significant bit of the uint16_t PWM_SIGNAL to 1, and then adding 1 to the normal PWM signal value. This results in a 15-bit signal with one fewer representable PWM value, a range of [0 → 32766]. On PWM servos that use the full 15-bit resolution over a 180º linear range, this results in a precision loss of approximately 5.493 millidegrees reduction in total range, and 0.1676 microdegrees decrease in angular resolution per step, which is effectively negligible for most use-cases.

To introduce this offset, the formula PWM_SIGNAL = pwm + (1+(0b1<<15)) is used; and the formula pwm = PWM_SIGNAL - (1+(0b1<<15)) is used on the receiving end to undo the offset applied.

Endianness

To avoid the endianness problem, the protocol introduces a normalized implementation through which uint16_t values are split into two uint8_t values in a set order (the first byte will be the upper-byte, followed by the lower-byte). The visual representation of this transformation would be:

uint16 uint16

And the functions used for this are:

divideIntoBytes()
1
2
3
4
5
6
std::string QueryGenerator::divideIntoBytes(uint16_t u){
    std::string hl = "";
    hl+=(uint8_t)(u>>8);
    hl+=(uint8_t)(u&0x00ff);
    return hl;
}
restore16int()
inline uint16_t QueryGenerator::restore16int(uint8_t c0,uint8_t c1){return (c0<<8)+c1;}

uINF Communication Overview

uint16 uint16