Search code examples
cembeddedniosquartusucos

How can I improve my ad hoc cruise control system for Nios 2?


I have written in Nios 2 an ad hoc cruise control system for a school assignment. I versioned it with github. We want the cruise control to differ at most 2 m/s for speeds >= 25 m/s. The latest improvement I could do was checking the velocities in the condition which did improve the control. I couldn't prove before I tried that the change would have effect so it's an ad hoc trial and error approach which is not so good. Now the cruise control actually keeps the spped within 2 m/s if activated. What more can be done now that I managed to improve it once? Can I use something from control theory to miprove the behavior?

/*
 * The task 'ControlTask' is the main task of the application. It reacts
 * on sensors and generates responses.
 */

void ControlTask(void* pdata)
{
    INT8U err;
    INT8U throttle = 40; /* Value between 0 and 80, which is interpreted as between 0.0V and 8.0V */
    void* msg;
    INT16S* current_velocity;
    int btn_reg;
    INT16S* current_output;
    printf("Control Task created!\n");

    while (1)
    {

        OSSemPend(aSemaphore, 1, &err); // Trying to access the key
        msg = OSMboxPend(Mbox_Velocity, 0, &err);
        current_velocity = (INT16S*) msg;
        printf("Control Task!\n");
        ButtonIO(current_velocity, throttle);
        btn_reg = IORD_ALTERA_AVALON_PIO_DATA(DE2_PIO_KEYS4_BASE);
        printf("btn_reg %d\n", btn_reg);
        if (btn_reg == 7) {
            ++throttle;
        } else if (cruise_control_increase_velocity == 1) {
            printf("increase velocity \n");
            if (*current_velocity <= cruise_velocity) {
                throttle = throttle + 15;
            }


            cruise_control_increase_velocity = 0;
        }
        else if (btn_reg == 11) {
            if (throttle > 0) {
                --throttle;
            }

        } else if (cruise_control_decrease_velocity == 1) {
            printf("decrease_velocity \n");
            if (throttle >= 15 && current_velocity >= cruise_velocity) {
                throttle = throttle -15;

            }
            cruise_control_decrease_velocity = 0;
        }
        if (btn_reg== 13) {
            printf("do cruise control\n" );
            cruise_velocity = *current_velocity;
        }
        Button1IO(current_velocity);
        SwitchIO(current_velocity, getGlobalPosition());
        err = OSMboxPost(Mbox_Throttle, (void *) &throttle);
    }
}

Solution

    • Clearly separate the control task from the I/O. They have different real-time requirements and performing both in the same task loop can be detrimental to control stability; although with a slow responding system such as a motor-vehicle, it may not be critical, but it still makes good design sense to separate these activities.

    • Use a classic PID control loop where the error input is actual speed - target speed, and the output is throttle position. The I (integral) gain ensures sufficient throttle to maintain speed in steady-state conditions, the P (proportional) gain controls the aggressiveness of acceleration. while the D (derivative) gain damps response to minimise overshoot/undershoot, and improves response to sudden changes such as hills. With an asymetric, non-linear system with a good deal of hysteresis, tuning the control loop may not be straightforward and you need to avoid being too aggressive with the coefficients. An over-damped response is however is probably conducive to passenger comfort and fuel consumption. The I term should probably be limited to prevent "wind-up", which may result for example in sudden acceleration on summiting a steep hill if the target speed could not be closely tracked.

    • Avoid global variables. The code posted externally to this site as in the order of 24 global variables.