Skip to content

Fsm integration#14

Open
guytonde wants to merge 24 commits into
mainfrom
fsm_integration
Open

Fsm integration#14
guytonde wants to merge 24 commits into
mainfrom
fsm_integration

Conversation

@guytonde
Copy link
Copy Markdown

integration of fsm

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a major refactoring of the VCU firmware, introducing a new Finite State Machine for motor control, a centralized fault management system, and CAN message watchdogs. It also adds tasks for input processing and status broadcasting, supported by auto-generated lookup tables. Feedback identifies several critical bugs and logic errors, including the use of incorrect CAN IDs for status updates, potential out-of-bounds memory access in the FSM and watchdog modules, and inverted logic in pedal deviation checks. Furthermore, improvements are needed for throttle setpoint normalization, type-safe CAN data decoding, and the implementation of actual precharge sensing logic instead of hardcoded bits.

Comment thread Firmware/Drivers/Src/CANbus.c Outdated
uint8_t moco_status_rx_data[CAN_DLC_MC_VELOCITYMEASUREMENT] = {0};

can_status_t result =
can_fd_recv(motorfdcan, CAN_ID_MC_VELOCITYMEASUREMENT, &header, moco_status_rx_data, delay);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The MotorCAN_Recv_Status function is incorrectly calling can_fd_recv with CAN_ID_MC_VELOCITYMEASUREMENT (0x402) instead of CAN_ID_MC_STATUS (0x401). This will cause the status decoding logic to operate on velocity data.

        can_fd_recv(motorfdcan, CAN_ID_MC_STATUS, &header, moco_status_rx_data, delay);

Comment thread Firmware/Drivers/Src/Watchdogs.c Outdated
&wd_buffers[wd_count]
);
configASSERT(t != NULL);
wd_timers[wd_count] = t;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The watchdog timer handle is being stored in the wd_timers array using wd_count as the index, but watchdog_received_can_message (and other functions) access it using the idx parameter. If idx does not match the creation order, this will lead to accessing the wrong timer or a NULL pointer, causing a crash. Use idx as the array index for consistency.

    wd_timers[idx] = t;

Comment on lines +70 to +71
fsm_inputs = xEventGroupGetBits(fsmInputGroup);
current_state = FSM[current_state.NextStates[fsm_inputs]];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The fsm_inputs value retrieved from the event group is used directly as an index into the NextStates array. Since the event group can contain more bits than the array size (512), any unexpected bits being set will cause an out-of-bounds memory access. The inputs should be masked with FSM_INPUTS_MASK_ALL before indexing.

    fsm_inputs = xEventGroupGetBits(fsmInputGroup) & FSM_INPUTS_MASK_ALL;
    current_state = FSM[current_state.NextStates[fsm_inputs]];

Comment thread Firmware/Tasks/Src/FSMTask.c Outdated
// if we're actually going backwards, let off the pedal until we slow down
MotorCAN_Send_Drive_Cmd(0.0f, 0.0f, 0);
} else {
MotorCAN_Send_Drive_Cmd(MAX_VELOCITY, apply_rollover_limit(g_data_read->accel_brake.AccelPedal_Main_Pos), 0);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The pedal position AccelPedal_Main_Pos (likely 0-100 or 0-255) is being passed directly to the motor controller drive command. The Wavesculptor 22 expects a normalized current setpoint between 0.0f and 1.0f. Sending raw values will result in incorrect torque requests. Use map_to_percent to normalize the value.

        float throttle = map_to_percent(g_data_read->accel_brake.AccelPedal_Main_Pos, 0, 100, 0, 100);
        MotorCAN_Send_Drive_Cmd(MAX_VELOCITY, apply_rollover_limit(throttle), 0);

g_data_read->accel_brake.BrakePedal_Redundant_Fault ||
fabs(g_data_read->accel_brake.AccelPedal_Main_Pos -
g_data_read->accel_brake.AccelPedal_Redundant_Pos) < ACCEPTABLE_PEDAL_DEVIATION) {
mask |= FAULT_BIT(FAULT_ID_PEDAL_BOARD_FAULT);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The pedal deviation fault logic is inverted. It currently triggers a fault if the difference between the main and redundant sensors is less than the acceptable deviation. It should trigger if the difference is greater than the threshold.

        fabs((float)g_data_read->accel_brake.AccelPedal_Main_Pos -
            (float)g_data_read->accel_brake.AccelPedal_Redundant_Pos) > ACCEPTABLE_PEDAL_DEVIATION) {

Comment thread Firmware/Tasks/Src/VCUStatusTask.c Outdated
Comment on lines +18 to +21
else if(faults_is_active(VCU_STATUS_VCU_FAULT_MOTOR_PCHG_CONTACTOR_SENSE))
vcu_fault = VCU_STATUS_VCU_FAULT_MOTOR_PCHG_CONTACTOR_SENSE;
else if(faults_is_active(VCU_STATUS_VCU_FAULT_MOTOR_CONTACTOR_SENSE))
vcu_fault = VCU_STATUS_VCU_FAULT_MOTOR_CONTACTOR_SENSE;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The faults_is_active function is being called with values from the vcu_status_vcu_fault_e enum instead of the FaultID_e enum. This results in checking the wrong bits in the fault event group. For example, passing VCU_STATUS_VCU_FAULT_MOTOR_PCHG_CONTACTOR_SENSE (value 2) will check if FAULT_ID_MOTOR_DC_BUS_OVERVOLTAGE is active.

Suggested change
else if(faults_is_active(VCU_STATUS_VCU_FAULT_MOTOR_PCHG_CONTACTOR_SENSE))
vcu_fault = VCU_STATUS_VCU_FAULT_MOTOR_PCHG_CONTACTOR_SENSE;
else if(faults_is_active(VCU_STATUS_VCU_FAULT_MOTOR_CONTACTOR_SENSE))
vcu_fault = VCU_STATUS_VCU_FAULT_MOTOR_CONTACTOR_SENSE;
else if(faults_is_active(FAULT_ID_PRECHARGE_SENSE_MISMATCH))
vcu_fault = VCU_STATUS_VCU_FAULT_MOTOR_PCHG_CONTACTOR_SENSE;
else if(faults_is_active(FAULT_ID_MOTOR_SENSE_MISMATCH))
vcu_fault = VCU_STATUS_VCU_FAULT_MOTOR_CONTACTOR_SENSE;

Comment on lines +77 to +78
out->MC_MotorVelocity = *((float *)&motor_vel_rx_data[0]);
out->MC_VehicleVelocity = *((float *)&motor_vel_rx_data[4]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Directly dereferencing a casted pointer to float from a uint8_t array can lead to strict aliasing violations and potential alignment faults on some architectures. It is safer to use memcpy for decoding floating-point values from the CAN buffer.

        memcpy(&out->MC_MotorVelocity, &motor_vel_rx_data[0], sizeof(float));
        memcpy(&out->MC_VehicleVelocity, &motor_vel_rx_data[4], sizeof(float));

if (g_data_read->driver_input.Cruise_Enable) s |= CRUISE_CONTROL_BUTTON_BIT;
if (g_data_read->bps_status.BPS_Regen_OK) s |= READY_TO_REGEN_BIT;
// if (contactor_get_sense(MOTOR_CONTACTOR) && contactor_get_sense(MOTOR_PRE_CONTACTOR))
s |= PRECHARGE_COMPLETE_BIT;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The PRECHARGE_COMPLETE_BIT is hardcoded to be always set, bypassing the actual contactor sense logic. This is dangerous as it allows the FSM to transition to drive states before precharge is actually finished. The commented-out logic should be implemented.

@guytonde
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a comprehensive refactor of the Vehicle Control Unit (VCU) firmware, introducing a new Finite State Machine (FSM) for motor control, a centralized fault handling system, and a watchdog monitoring system for CAN messages. The CAN driver was also updated to provide dedicated APIs for motor and car communication buses. Feedback highlights several critical bugs, including incorrect indexing in the watchdog module, inverted logic for pedal deviation faults, and the use of an incorrect CAN ID for motor status. Furthermore, improvements are needed regarding the scaling of pedal inputs, adherence to strict aliasing rules during CAN data parsing, and ensuring that the FSM is properly disabled when a fault occurs.

Comment thread Firmware/Drivers/Src/Watchdogs.c Outdated
&wd_buffers[wd_count]
);
configASSERT(t != NULL);
wd_timers[wd_count] = t;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The timer handle is being stored using wd_count as the index, but other functions in this module (such as watchdog_received_can_message and watchdog_received_can_message_ISR) use the idx parameter to access the wd_timers array. If watchdogs are created out of order or if idx does not match the creation sequence, this will lead to incorrect timer access or null pointer dereferences.

    wd_timers[idx] = t;

Comment on lines +75 to +76
fabs(g_data_read->accel_brake.AccelPedal_Main_Pos -
g_data_read->accel_brake.AccelPedal_Redundant_Pos) < ACCEPTABLE_PEDAL_DEVIATION) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The logic for detecting pedal deviation faults is inverted. Currently, a fault is triggered if the difference between the main and redundant pedal positions is less than the acceptable deviation. It should be triggered if the difference exceeds the threshold.

        fabs(g_data_read->accel_brake.AccelPedal_Main_Pos -
            g_data_read->accel_brake.AccelPedal_Redundant_Pos) > ACCEPTABLE_PEDAL_DEVIATION) {

Comment thread Firmware/Drivers/Src/CANbus.c Outdated
uint8_t moco_status_rx_data[CAN_DLC_MC_VELOCITYMEASUREMENT] = {0};

can_status_t result =
can_fd_recv(motorfdcan, CAN_ID_MC_VELOCITYMEASUREMENT, &header, moco_status_rx_data, delay);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The MotorCAN_Recv_Status function is incorrectly attempting to receive data using CAN_ID_MC_VELOCITYMEASUREMENT (0x403) instead of CAN_ID_MC_STATUS (0x401). This will result in the status struct being populated with velocity data, leading to incorrect fault and limit flag readings.

        can_fd_recv(motorfdcan, CAN_ID_MC_STATUS, &header, moco_status_rx_data, delay);

Comment thread Firmware/Tasks/Src/FSMTask.c Outdated
// if we're actually going backwards, let off the pedal until we slow down
MotorCAN_Send_Drive_Cmd(0.0f, 0.0f, 0);
} else {
MotorCAN_Send_Drive_Cmd(MAX_VELOCITY, apply_rollover_limit(g_data_read->accel_brake.AccelPedal_Main_Pos), 0);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The pedal position (AccelPedal_Main_Pos) is being passed directly as the current setpoint to the motor controller. The motor controller expects a normalized float value (typically 0.0 to 1.0), but the pedal position is a uint8_t (likely 0-100). This will cause the motor to receive a setpoint that is orders of magnitude higher than intended. Use the map_to_percent function to scale the input correctly.

        MotorCAN_Send_Drive_Cmd(MAX_VELOCITY, apply_rollover_limit(map_to_percent(g_data_read->accel_brake.AccelPedal_Main_Pos, 0, 100, 0, 100)), 0);

Comment on lines +73 to +74
out->MC_MotorVelocity = *((float *)&motor_vel_rx_data[0]);
out->MC_VehicleVelocity = *((float *)&motor_vel_rx_data[4]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Directly casting a uint8_t pointer to a float pointer and dereferencing it violates strict aliasing rules and can lead to undefined behavior or alignment issues. Use memcpy to safely extract the floating-point values from the byte array.

        memcpy(&out->MC_MotorVelocity, &motor_vel_rx_data[0], sizeof(float));
        memcpy(&out->MC_VehicleVelocity, &motor_vel_rx_data[4], sizeof(float));

Comment thread Firmware/Tasks/Src/FaultHandlerTask.c Outdated

Set_Fault_LED();
Fault_Loop();
// fsm_disable();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The call to fsm_disable() is commented out. In a fault condition, it is critical to transition the FSM to a safe state (DISABLED) to ensure that no further drive commands are sent to the motor controller.

            fsm_disable();

@guytonde
Copy link
Copy Markdown
Author

/gemini is there anything wrong with precharge

@gemini-code-assist
Copy link
Copy Markdown

The precharge sequence is handled within Firmware/Tasks/Src/PrechargeTask.c. The sequence transitions through WAITING, INITIAL, PRECHARGING, and COMPLETE states.

Key aspects of the precharge logic include:

  • Fault Monitoring: The Fault_Checker function (called in PRECHARGING and COMPLETE states) monitors for overvoltage, undervoltage, and contactor sense mismatches. If any fault is detected, it triggers the fault handler, which opens all contactors.
  • Timing: The PRECHARGE_TIMEOUT_MS (400ms) ensures the precharge sequence does not hang indefinitely. If the motor voltage does not reach 90% of the battery voltage within this time, a FAULT_ID_PRECHARGE_TIMEOUT is set.
  • Hysteresis: Once in the COMPLETE state, the system continuously monitors the voltage ratio. If the motor voltage drops below 80% of the battery voltage (PRECHARGE_THRESHOLD_80), it triggers a FAULT_ID_MOTOR_LT_BATTERY to ensure the system remains in a safe state.

If you are experiencing issues with the precharge sequence, I recommend checking the FaultHandlerTask logs to see if any of these specific fault IDs are being triggered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants