-1

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);
    }
}
Niklas Rosencrantz
  • 25,640
  • 75
  • 229
  • 424
  • 1
    how often is this task executed? with all those calls to printf(), the time for a single execution will be rather slow. The jump of +/- 15 in the throttle setting might make the current velocity seem to respond quickly, but if the task is executed often, then it is probably to much. – user3629249 Mar 11 '15 at 02:40
  • 1
    there seems to be several global variables, like cruise_control_decrease-velocity and cruise_control_increase_velocity and cruise_velocity. All these would be better kept in a struct and a pointer to that struct passed to the task . – user3629249 Mar 11 '15 at 02:42
  • 1
    the while loop has no limiting execution rate implemented, so it will execute dozens/hundreds of times per second. when btn_reg indicates a desired change, the throttle setting will change very very very fast, probably not what you want. suggest adding some kind of limiting logic so the while loop is only executed at some periodic rate, say 10 times per second. the current code does not release the CPU, so will hog the cpu cycles, resulting in other tasks being CPU starved. Infact, without pre-emptive scheduling, nothing else may get executed. – user3629249 Mar 11 '15 at 02:49
  • 1
    what is the max accelleration/decelleration rate allowed? how does that match with 'throttle' value changes? BTW: there is no limiting on the max throttle value, this could result in a overflow of the throttle value – user3629249 Mar 11 '15 at 02:52
  • 1
    the 'target' cruise velocity needs to be updated when the user is pressing either the accelerate button or the decelerate button. usually a cruise control includes a 'set' button, that is often the decel button if held. such momentary .vs. hold of buttons needs to be checked for and handled. Therefore, the code needs to 1) handle button debounce, 2) handle momentary button press events 3) needs to handle hold button press events. 4) may need to handle multiple button press events. 5) needs to handle startup/on button events. 6) needs to handle off/stop button events. – user3629249 Mar 11 '15 at 02:58

1 Answers1

1
  • 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.

Clifford
  • 88,407
  • 13
  • 85
  • 165