What are the consequences of disabling ERROR_CONTROL_DEADLINE_MISSED?

I am messing around in the firmware, trying to implement some custom behaviour in place of the usual Torque Control mode. This began as an attempt to work around a problem and is now just for seeing how far I can go with it.

To do this I am inserting code in Controller::update() and Motor::update(), just altering the values of torque and current_setpoint. (I am using fw-v0.5.1 - I think those names might have changed in more recent revisions.)

I cannot do too much in here without hitting ERROR_CONTROL_DEADLINE_MISSED - which I assume means the code I’ve added is taking too long to run.

Is it safe to comment out the bit in motor.cpp that raises this error? I’m assuming no.

Better question: is there somewhere else I can put my code, other than in Controller::update()? I still need it to run as fast as possible, but it can go a bit slower than every 125us (which is the value I get when printing current_meas_period, and therefore I’m taking to be the time between successive Controller::update() calls.)

  • EDIT: and it should be somewhere that still has access to the pos and vel estimates for the Axis as well as some other, custom values I’m remembering between updates. Currently I’ve added those as properties to the Controller class.

probably it’d be better to make it a new task in FreeRTOS, if you know how to do that.

So I had a go, but it turns out, I don’t. Do you have any experience here?

I have tried to alter the start_thread() function in axis.cpp so it now looks like this:

// @brief Starts run_state_machine_loop in a new thread
void Axis::start_thread() {
    osThreadDef(thread_def, run_state_machine_loop_wrapper, hw_config_.thread_priority, 0, stack_size_ / sizeof(StackType_t));
    thread_id_ = osThreadCreate(osThread(thread_def), this);
    thread_id_valid_ = true;
    
    osThreadDef(experiment_controller_thread_def, run_experiment_controller_loop_wrapper, hw_config_.thread_priority, 0, stack_size_ / sizeof(StackType_t));
    experiment_controller_thread_id_ = osThreadCreate(osThread(experiment_controller_thread_def), this);
    experiment_controller_thread_id_valid_ = true;
}

where the loop wrapper is a copy-paste of the state machine loop wrapper like this:

static void run_state_machine_loop_wrapper(void* ctx) {
    reinterpret_cast<Axis*>(ctx)->run_state_machine_loop();
    reinterpret_cast<Axis*>(ctx)->thread_id_valid_ = false;
}

static void run_experiment_controller_loop_wrapper(void* ctx) {
    reinterpret_cast<Axis*>(ctx)->run_experiment_controller_loop();
    reinterpret_cast<Axis*>(ctx)->experiment_controller_thread_id_valid_ = false;
}

and run_experiment_controller_loop() looks like this:

void Axis::run_experiment_controller_loop() {
	for (;;) {
        // do stuff here when this actually works.
	}
}

The result compiles fine, but after loading it, Windows no longer recognises the ODrive. So I don’t even know what errors it might be generating.

I have no familiarity with FreeRTOS at all, and am playing everything by ear based on what I see in main.cpp.

Does anyone want to point me in the right direction?

Try putting a osDelay(1); in your for loop

What’s probably happening is, because the control system thread priority is likely higher than the USB comms thread priority, an infinite loop without any delay to pass control to other threads will starve the communications thread of execution time.

1 Like

You’re a star, I could have spent days before I worked that out.

2 Likes