diff --git a/Firmware/fibre/cpp/interfaces_template.j2 b/Firmware/fibre/cpp/interfaces_template.j2 index 91af9494..07cc35c5 100644 --- a/Firmware/fibre/cpp/interfaces_template.j2 +++ b/Firmware/fibre/cpp/interfaces_template.j2 @@ -38,7 +38,7 @@ public: [%- for enum in intf.enums %] enum [[enum.name | to_pascal_case]] { [%- for k, value in enum['values'].items() %] - [[((enum.name + k) | to_macro_case).ljust(32)]] = [% if enum.is_flags %]0x[['%08x' | format(value.value)]][% else %][[value.value]][% endif %], + [[((enum.name | to_macro_case) + "_" + (k | to_macro_case)).ljust(32)]] = [% if enum.is_flags %]0x[['%08x' | format(value.value)]][% else %][[value.value]][% endif %], [%- endfor %] }; [%- endfor %] diff --git a/Firmware/fibre/tools/interface_generator.py b/Firmware/fibre/tools/interface_generator.py index ebdd72ef..713ddce5 100644 --- a/Firmware/fibre/tools/interface_generator.py +++ b/Firmware/fibre/tools/interface_generator.py @@ -131,10 +131,13 @@ dictionary = [] def get_words(string): """ - Splits a string in PascalCase into a list of lower case words + Splits a string in PascalCase or MACRO_CASE into a list of lower case words """ - regex = ''.join((re.escape(w) + '|') for w in dictionary) + '[a-z0-9]+|[A-Z][a-z0-9]*' - return [(w if w in dictionary else w.lower()) for w in re.findall(regex, string)] + if string.isupper(): + return [w.lower() for w in string.split('_')] + else: + regex = ''.join((re.escape(w) + '|') for w in dictionary) + '[a-z0-9]+|[A-Z][a-z0-9]*' + return [(w if w in dictionary else w.lower()) for w in re.findall(regex, string)] def join_name(*names, delimiter: str = '.'): """ diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 1af868a4..bc8b14cd 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -20,16 +20,16 @@ interfaces: toplevel interface. attributes: error: - nullflag: 'None' + nullflag: NONE flags: - ControlIterationMissed: + CONTROL_ITERATION_MISSED: brief: At least one control iteration was missed. doc: | The main control loop is supposed to runs at a fixed frequency. If the device is computationally overloaded (e.g. too many active components) it's possible that one or more control iterations are skipped. - DcBusUnderVoltage: + DC_BUS_UNDER_VOLTAGE: brief: The DC voltage fell below the limit configured in `config.dc_bus_undervoltage_trip_level`. doc: | Confirm that your power leads are connected securely. For initial @@ -47,7 +47,7 @@ interfaces: limit. To limit your PSU power draw you can limit your motor current and/or velocity limit `controller.config.vel_limit` and `motor.config.current_lim`. - DcBusOverVoltage: + DC_BUS_OVER_VOLTAGE: brief: The DC voltage exceeded the limit configured in `config.dc_bus_overvoltage_trip_level`. doc: | Confirm that you have a brake resistor of the correct value @@ -65,12 +65,12 @@ interfaces: connections you can also try increasing your brake resistance by ~ 0.01 Ohm at a time to a maximum of 0.05 greater than your brake resistor value. - DcBusOverRegenCurrent: {doc: too much current pushed into the power supply} - DcBusOverCurrent: {doc: too much current pulled out of the power supply} - BrakeDeadtimeViolation: - BrakeDutyCycleNan: - InvalidBrakeResistance: {doc: '`config.brake_resistance` is non-positive or NaN.'} -# BrakeResistorDisarmed: + DC_BUS_OVER_REGEN_CURRENT: {doc: too much current pushed into the power supply} + DC_BUS_OVER_CURRENT: {doc: too much current pulled out of the power supply} + BRAKE_DEADTIME_VIOLATION: + BRAKE_DUTY_CYCLE_NAN: + INVALID_BRAKE_RESISTANCE: {doc: '`config.brake_resistance` is non-positive or NaN.'} +# BRAKE_RESISTOR_DISARMED: # doc: The brake resistor was unexpectedly disarmed. vbus_voltage: @@ -365,8 +365,8 @@ interfaces: c_is_class: True attributes: error: - nullflag: None - flags: {DuplicateCanIds: } + nullflag: NONE + flags: {DUPLICATE_CAN_IDS: } config: c_is_class: False attributes: @@ -386,23 +386,23 @@ interfaces: c_is_class: True attributes: error: - nullflag: 'None' + nullflag: NONE flags: - InvalidState: + INVALID_STATE: brief: An invalid state was requested. doc: | You tried to run a state before you are allowed to. Typically you tried to run encoder calibration or closed loop control before the motor was calibrated, or you tried to run closed loop control before the encoder was calibrated. - WatchdogTimerExpired: {bit: 11} - MinEndstopPressed: - MaxEndstopPressed: - EstopRequested: - HomingWithoutEndstop: + WATCHDOG_TIMER_EXPIRED: {bit: 11} + MIN_ENDSTOP_PRESSED: + MAX_ENDSTOP_PRESSED: + ESTOP_REQUESTED: + HOMING_WITHOUT_ENDSTOP: bit: 17 doc: the min endstop was not enabled during homing - OverTemp: + OVER_TEMP: # unused doc: Check `motor.error` for more details. step_dir_active: readonly bool @@ -566,9 +566,9 @@ interfaces: c_is_class: True attributes: error: - nullflag: None + nullflag: NONE flags: - PhaseResistanceOutOfRange: + PHASE_RESISTANCE_OUT_OF_RANGE: brief: The measured motor phase resistance is outside of the plausible range. doc: | During calibration the motor resistance and @@ -599,11 +599,11 @@ interfaces: resistance_calib_max_voltage > calibration_current * phase_resistance resistance_calib_max_voltage < 0.5 * vbus_voltage ``` - PhaseInductanceOutOfRange: + PHASE_INDUCTANCE_OUT_OF_RANGE: brief: The measured motor phase inductance is outside of the plausible range. doc: | - See `PhaseResistanceOutOfRange` for details. - DrvFault: + See `PHASE_RESISTANCE_OUT_OF_RANGE` for details. + DRV_FAULT: bit: 3 brief: The gate driver chip reported an error. doc: | @@ -620,8 +620,8 @@ interfaces: test motor and 50A on another test motor. Refer to [this post](https://discourse.odriverobotics.com/t/drv-fault-on-odrive-v3-4/558) for instructions for a hardware fix. - ControlDeadlineMissed: - ModulationMagnitude: + CONTROL_DEADLINE_MISSED: + MODULATION_MAGNITUDE: bit: 7 doc: | The bus voltage was insufficent to push the requested current @@ -633,34 +633,34 @@ interfaces: For gimbal motors, it is recommended to set the `config.calibration_current` and `config.current_lim` to half your bus voltage, or less. - CurrentSenseSaturation: {bit: 10} - CurrentLimitViolation: {bit: 12} - ModulationIsNan: {bit: 16} - MotorThermistorOverTemp: {doc: The motor thermistor measured a temperature above motor.motor_thermistor.config.temp_limit_upper} - FetThermistorOverTemp: {doc: The inverter thermistor measured a temperature above motor.fet_thermistor.config.temp_limit_upper} - TimerUpdateMissed: {doc: A timer update event was missed. Perhaps the previous timer update took too much time. This is not expected in official release firmware.} - CurrentMeasurementUnavailable: {doc: The phase current measurement is not available. The ADC failed to sample the current sensor in time. This is not expected in official release firmware.} - ControllerFailed: {doc: The motor was disarmed because the underlying controller failed. Usually this is the FOC controller.} - IBusOutOfRange: + CURRENT_SENSE_SATURATION: {bit: 10} + CURRENT_LIMIT_VIOLATION: {bit: 12} + MODULATION_IS_NAN: {bit: 16} + MOTOR_THERMISTOR_OVER_TEMP: {doc: The motor thermistor measured a temperature above motor.motor_thermistor.config.temp_limit_upper} + FET_THERMISTOR_OVER_TEMP: {doc: The inverter thermistor measured a temperature above motor.fet_thermistor.config.temp_limit_upper} + TIMER_UPDATE_MISSED: {doc: A timer update event was missed. Perhaps the previous timer update took too much time. This is not expected in official release firmware.} + CURRENT_MEASUREMENT_UNAVAILABLE: {doc: The phase current measurement is not available. The ADC failed to sample the current sensor in time. This is not expected in official release firmware.} + CONTROLLER_FAILED: {doc: The motor was disarmed because the underlying controller failed. Usually this is the FOC controller.} + I_BUS_OUT_OF_RANGE: doc: | The DC current sourced/sunk by this motor exceeded the configured hard limits. More specifically `i_bus` fell outside of the range `config.i_bus_hard_min` ... `config.i_bus_hard_max`. - BrakeResistorDisarmed: {doc: An attempt was made to run the motor PWM while the brake resistor was enabled but disarmed.} - SystemLevel: + BRAKE_RESISTOR_DISARMED: {doc: An attempt was made to run the motor PWM while the brake resistor was enabled but disarmed.} + SYSTEM_LEVEL: doc: | The motor had to be disarmed because of a system level error. See `ODrive.Error` for more details. - BadTiming: {doc: The main control loop got out of sync with the motor control loop. This could indicate that the main control loop got stuck.} - UnknownPhaseEstimate: {doc: The current controller did not get a valid angle input. Maybe you didn't calibrate the encoder.} - UnknownPhaseVel: {doc: The motor controller did not get a valid phase velocity input.} - UnknownTorque: {doc: The motor controller did not get a valid torque input.} - UnknownCurrentCommand: {doc: The current controller did not get a valid current setpoint. Maybe you didn't configure the controller correctly.} - UnknownCurrentMeasurement: {doc: The current controller did not get a valid current measurement.} - UnknownVbusVoltage: {doc: The current controller did not get a valid `vbus_voltage` measurement.} - UnknownVoltageCommand: {doc: The current controller did not get a valid feedforward voltage setpoint.} - UnknownGains: {doc: The current controller gains were not configured. Run motor calibration or set `config.phase_resistance` and `config.phase_inductance` manually.} - ControllerInitializing: {doc: Internal value used while the controller is not yet ready to generate PWM timings.} + BAD_TIMING: {doc: The main control loop got out of sync with the motor control loop. This could indicate that the main control loop got stuck.} + UNKNOWN_PHASE_ESTIMATE: {doc: The current controller did not get a valid angle input. Maybe you didn't calibrate the encoder.} + UNKNOWN_PHASE_VEL: {doc: The motor controller did not get a valid phase velocity input.} + UNKNOWN_TORQUE: {doc: The motor controller did not get a valid torque input.} + UNKNOWN_CURRENT_COMMAND: {doc: The current controller did not get a valid current setpoint. Maybe you didn't configure the controller correctly.} + UNKNOWN_CURRENT_MEASUREMENT: {doc: The current controller did not get a valid current measurement.} + UNKNOWN_VBUS_VOLTAGE: {doc: The current controller did not get a valid `vbus_voltage` measurement.} + UNKNOWN_VOLTAGE_COMMAND: {doc: The current controller did not get a valid feedforward voltage setpoint.} + UNKNOWN_GAINS: {doc: The current controller gains were not configured. Run motor calibration or set `config.phase_resistance` and `config.phase_inductance` manually.} + CONTROLLER_INITIALIZING: {doc: Internal value used while the controller is not yet ready to generate PWM timings.} is_armed: readonly bool is_calibrated: readonly bool current_meas_phA: {type: readonly float32, c_getter: 'current_meas_.value_or(Iph_ABC_t{0.0f, 0.0f, 0.0f}).phA'} @@ -798,9 +798,9 @@ interfaces: c_is_class: True attributes: error: - nullflag: None + nullflag: NONE flags: - Overspeed: + OVERSPEED: doc: | Try increasing `config.vel_limit`. The default of 2 turns per second gives a motor speed of only 120 RPM. Note: Even if @@ -812,11 +812,11 @@ interfaces: default value of 1.2 means it will only allow a 20% violation of the speed limit. You can set the `config.vel_limit_tolerance` to 0 to disable the check altogether. - InvalidInputMode: - UnstableGain: - InvalidMirrorAxis: - InvalidLoadEncoder: - InvalidEstimate: + INVALID_INPUT_MODE: + UNSTABLE_GAIN: + INVALID_MIRROR_AXIS: + INVALID_LOAD_ENCODER: + INVALID_ESTIMATE: input_pos: type: float32 unit: turn @@ -914,10 +914,10 @@ interfaces: c_is_class: True attributes: error: - nullflag: None + nullflag: NONE flags: - UnstableGain: - CprPolepairsMismatch: + UNSTABLE_GAIN: + CPR_POLEPAIRS_MISMATCH: doc: | Confirm you have entered the correct count per rotation (CPR) for [your encoder](https://docs.odriverobotics.com/encoders). The @@ -928,21 +928,21 @@ interfaces: switches on the encoder PCB and so you may need to check that these are in the right positions. If your encoder lists its pulse per rotation (PPR) multiply that number by four to get CPR. - NoResponse: + NO_RESPONSE: doc: | Confirm that your encoder is plugged into the right pins on the ODrive board. - UnsupportedEncoderMode: - IllegalHallState: - IndexNotFoundYet: + UNSUPPORTED_ENCODER_MODE: + ILLEGAL_HALL_STATE: + INDEX_NOT_FOUND_YET: doc: | Check that your encoder is a model that has an index pulse. If your encoder does not have a wire connected to pin Z on your ODrive then it does not output an index pulse. - AbsSpiTimeout: - AbsSpiComFail: - AbsSpiNotReady: - HallNotCalibratedYet: + ABS_SPI_TIMEOUT: + ABS_SPI_COM_FAIL: + ABS_SPI_NOT_READY: + HALL_NOT_CALIBRATED_YET: is_ready: readonly bool index_found: readonly bool shadow_count: readonly int32 @@ -996,10 +996,10 @@ interfaces: c_is_class: True attributes: error: - nullflag: None + nullflag: NONE flags: - UnstableGain: - UnknownCurrentMeasurement: + UNSTABLE_GAIN: + UNKNOWN_CURRENT_MEASUREMENT: phase: {type: readonly float32, unit: rad, c_getter: phase_.any().value_or(0.0f)} pll_pos: {type: readonly float32, unit: rad} phase_vel: {type: readonly float32, unit: rad/s, c_getter: phase_vel_.any().value_or(0.0f)} @@ -1135,49 +1135,49 @@ interfaces: valuetypes: ODrive.GpioMode: values: - Digital: + DIGITAL: doc: | The pin can be used for one or more of these functions: Step, dir, enable, encoder index, hall effect encoder, SPI encoder nCS (this one is exclusive). - DigitalPullUp: - doc: Same as `Digital` but with the internal pull-up resistor enabled. - DigitalPullDown: - doc: Same as `Digital` but with the internal pull-down resistor enabled. - AnalogIn: + DIGITAL_PULL_UP: + doc: Same as `DIGITAL` but with the internal pull-up resistor enabled. + DIGITAL_PULL_DOWN: + doc: Same as `DIGITAL` but with the internal pull-down resistor enabled. + ANALOG_IN: doc: | The pin can be used for one or more of these functions: Sin/cos encoders, analog input, `get_adc_voltage`. - UartA: {doc: See `config.enable_uart_a`.} - UartB: {doc: This mode is not supported on ODrive v3.x.} - UartC: {doc: This mode is not supported on ODrive v3.x.} - CanA: {doc: See `config.enable_can_a`.} - I2cA: {doc: See `config.enable_i2c_a`.} - SpiA: {doc: Note that the SPI pins on ODrive v3.x are hardwired so they + UART_A: {doc: See `config.enable_uart_a`.} + UART_B: {doc: This mode is not supported on ODrive v3.x.} + UART_C: {doc: This mode is not supported on ODrive v3.x.} + CAN_A: {doc: See `config.enable_can_a`.} + I2C_A: {doc: See `config.enable_i2c_a`.} + SPI_A: {doc: Note that the SPI pins on ODrive v3.x are hardwired so they cannot be configured through software. Consequently, even though SPI_A is exposed, this mode is of no use on ODrive v3.x.} - Pwm: {doc: See `config.gpio0_pwm_mapping`.} - Enc0: {doc: The pin is used by quadrature encoder 0.} - Enc1: {doc: The pin is used by quadrature encoder 1.} - Enc2: {doc: This mode is not supported on ODrive v3.x.} - MechBrake: {doc: This is to support external mechanical brakes.} - Status: {doc: The pin is used for status output (see `config.error_gpio_pin`)} + PWM: {doc: See `config.gpio0_pwm_mapping`.} + ENC0: {doc: The pin is used by quadrature encoder 0.} + ENC1: {doc: The pin is used by quadrature encoder 1.} + ENC2: {doc: This mode is not supported on ODrive v3.x.} + MECH_BRAKE: {doc: This is to support external mechanical brakes.} + STATUS: {doc: The pin is used for status output (see `config.error_gpio_pin`)} ODrive.Can.Protocol: - values: {Simple: } + values: {SIMPLE: } ODrive.Axis.AxisState: # TODO: remove redundant "Axis" in name values: - Undefined: + UNDEFINED: doc: will fall through to idle - Idle: + IDLE: brief: Disable motor PWM and do nothing. - StartupSequence: + STARTUP_SEQUENCE: brief: Run the startup procedure. doc: the actual sequence is defined by the `config`.startup... flags - FullCalibrationSequence: + FULL_CALIBRATION_SEQUENCE: doc: Run motor calibration and then encoder offset calibration (or encoder index search if `.encoder.config.use_index` is `True`). - MotorCalibration: + MOTOR_CALIBRATION: brief: Measure phase resistance and phase inductance of the motor. doc: | * To store the results set `motor.config.pre_calibrated` to `True` @@ -1185,63 +1185,63 @@ valuetypes: don't have to run the motor calibration on the next start up. * This modifies the variables `motor.config.phase_resistance` and `motor.config.phase_inductance`. - EncoderIndexSearch: + ENCODER_INDEX_SEARCH: brief: Turn the motor in one direction until the encoder index is traversed. doc: This state can only be entered if `encoder.config.use_index` is `True`. value: 6 - EncoderOffsetCalibration: + ENCODER_OFFSET_CALIBRATION: brief: Turn the motor in one direction for a few seconds and then back to measure the offset between the encoder position and the electrical phase. doc: | * Can only be entered if the motor is calibrated (`motor.is_calibrated`). * A successful encoder calibration will make the `encoder.is_ready` go to true. - ClosedLoopControl: + CLOSED_LOOP_CONTROL: brief: Run closed loop control. doc: | * The action depends on the `controller.config.control_mode`. * Can only be entered if the motor is calibrated (`motor.is_calibrated`) and the encoder is ready (`encoder.is_ready`). - LockinSpin: + LOCKIN_SPIN: brief: Run lockin spin. doc: | Can only be entered if the motor is calibrated (`motor.is_calibrated`) or the motor direction is unspecified (`motor.config.direction` == 1) - EncoderDirFind: + ENCODER_DIR_FIND: brief: Run encoder direction search. doc: | Can only be entered if the motor is calibrated (`motor.is_calibrated`). - Homing: + HOMING: brief: Run axis homing function. doc: Endstops must be enabled to use this feature. - EncoderHallPolarityCalibration: + ENCODER_HALL_POLARITY_CALIBRATION: brief: Rotate the motor in lockin and calibrate hall polarity doc: ODrive assumes 120 degree electrical hall spacing. This routine determines if that is the case and sets the polarity if the halls are on 60 degree electrical spacing - EncoderHallPhaseCalibration: + ENCODER_HALL_PHASE_CALIBRATION: brief: Rotate the motor for 30s to calibrate hall sensor edge offsets doc: The phase offset is not calibrated at this time, so the map is only relative ODrive.Encoder.Mode: values: - Incremental: - Hall: - Sincos: - SpiAbsCui: + INCREMENTAL: + HALL: + SINCOS: + SPI_ABS_CUI: value: 0x100 doc: compatible with CUI AMT23xx - SpiAbsAms: + SPI_ABS_AMS: value: 0x101 doc: compatible with AMS AS5047P, AS5048A/AS5048B (no daisy chain support) - SpiAbsAeat: + SPI_ABS_AEAT: value: 0x102 doc: not yet implemented - SpiAbsRls: + SPI_ABS_RLS: value: 0x103 doc: RLS Encoders - SpiAbsMa732: + SPI_ABS_MA732: value: 0x104 doc: MagAlpha MA732 magnetic encoder @@ -1249,17 +1249,17 @@ valuetypes: values: # Note: these should be sorted from lowest level of control to # highest level of control, to allow "<" style comparisons. - VoltageControl: + VOLTAGE_CONTROL: doc: this one is not normally used - TorqueControl: - VelocityControl: - PositionControl: + TORQUE_CONTROL: + VELOCITY_CONTROL: + POSITION_CONTROL: ODrive.Controller.InputMode: values: - Inactive: + INACTIVE: brief: Disable inputs. Setpoints retain their last value. - Passthrough: + PASSTHROUGH: brief: Pass `input_xxx` through to `xxx_setpoint` directly. doc: | ### Valid Inputs: @@ -1272,7 +1272,7 @@ valuetypes: * `CONTROL_MODE_TORQUE_CONTROL` * `CONTROL_MODE_VELOCITY_CONTROL` * `CONTROL_MODE_POSITION_CONTROL` - VelRamp: + VEL_RAMP: brief: Ramps a velocity command from the current value to the target value. doc: | ### Configuration Values: @@ -1284,7 +1284,7 @@ valuetypes: ### Valid Control Modes: * `CONTROL_MODE_VELOCITY_CONTROL` - PosFilter: + POS_FILTER: brief: Implements a 2nd order position tracking filter. doc: | Intended for use with step/dir interface, but can also be used with @@ -1302,9 +1302,9 @@ valuetypes: ### Valid Control modes: * `CONTROL_MODE_POSITION_CONTROL` - MixChannels: + MIX_CHANNELS: brief: Not Implemented. - TrapTraj: + TRAP_TRAJ: brief: Implementes an online trapezoidal trajectory planner. doc: | ![Trapezoidal Planner Response](../TrapTrajPosVel.PNG) @@ -1320,7 +1320,7 @@ valuetypes: ### Valid Control Modes: * `CONTROL_MODE_POSITION_CONTROL` - TorqueRamp: + TORQUE_RAMP: brief: Ramp a torque command from the current value to the target value. doc: | ### Configuration Values: @@ -1331,7 +1331,7 @@ valuetypes: ### Valid Control Modes: * `CONTROL_MODE_TORQUE_CONTROL` - Mirror: + MIRROR: brief: Implements "electronic mirroring". doc: | This is like electronic camming, but you can only mirror exactly the @@ -1351,7 +1351,7 @@ valuetypes: ODrive.Motor.MotorType: values: - HighCurrent: + HIGH_CURRENT: #LowCurrent: # not implemented - Gimbal: {value: 2} - Acim: + GIMBAL: {value: 2} + ACIM: diff --git a/tools/enums_template.j2 b/tools/enums_template.j2 index bb20ca37..58d5bfc3 100644 --- a/tools/enums_template.j2 +++ b/tools/enums_template.j2 @@ -8,7 +8,7 @@ # [[enum.fullname]] [%- for k, value in enum['values'].items() %] -[[(((enum.parent.name if enum.name in ['Error', 'Mode'] else '') + enum.name + k) | to_macro_case).ljust(40)]] = [% if enum.is_flags %]0x[['%08x' | format(value.value)]][% else %][[value.value]][% endif %] +[[((((enum.parent.name if enum.name in ['Error', 'Mode'] else '') + enum.name) | to_macro_case) + "_" + (k | to_macro_case)).ljust(40)]] = [% if enum.is_flags %]0x[['%08x' | format(value.value)]][% else %][[value.value]][% endif %] [%- endfor %] [%- endif %] [%- endfor %]