Running a Relay for a Set Time

I need to run a relay for a set amount of time while still being able to run the rest of the robot’s functions. When I use the tried and true Wait() function from the Watchdog, it (as expected) halts the rest of robot operations. I have looked into separating out this function in a Task/Semaphore formation, but I’m not sure if it will solve this or exactly where to start with this (I have looked through this tutorial, but I’m still not sure where to start). What is the best way to run a function for a set amount of time while still running drive/other schmazz? :slight_smile:

One of our programmers got it with a separate task, but what I’d suggest is starting a Timer, polling it in your loop, and as soon as the timer exceeds some length of time, turn the relay off.

This is a C++ example. Its a state machine that starts with a trigger on a joystick. It even includes the 2 second lockout before the kicker can be fired again.


enum Kicker_State {
Kicker_off, 
Kicker_going_out, 
Kicker_out, 
Kicker_coming_back, 
Kicker_reload};

Timer kicker_timer;
Kicker_State kicker_state = Kicker_off;

while (IsOperatorControl())
{
    GetWatchdog().Feed();
    myRobot.TankDrive(left_stick, right_stick);		// drive with two sticks
    Wait(0.005);				// wait for a motor update time
    
    // kicker out-in actuator
    switch (kicker_state)
    {
    case Kicker_off:
        // see if go button is pressed
        if (right_stick.GetRawButton(KICKER_BUTTON))
        {
            kicker->Set(Relay::kForward);	// turn on
            kicker_timer.Reset();
            kicker_timer.Start();
            kicker_state = Kicker_going_out;
        }
        break;
    case Kicker_going_out:
        // see if enough time elasped
        if (kicker_timer.Get() >= .25)
        {
            kicker->Set(Relay::kOff);
            kicker_timer.Reset();
            kicker_state = Kicker_out;
        }
        break;
    case Kicker_out:
        // see if enough time elasped
        if (kicker_timer.Get() >= .5)
        {
            kicker->Set(Relay::kReverse);
            kicker_timer.Reset();
            kicker_state = Kicker_coming_back;
        }
        break;
    case Kicker_coming_back:
        // see if enough time elasped
        if (kicker_timer.Get() >= .25)
        {
            kicker->Set(Relay::kOff);
            kicker_timer.Reset();
            kicker_state = Kicker_reload;
        }
        break;
    case Kicker_reload:
        // see if enough time elasped
        if (kicker_timer.Get() >= 2.0)
        {
            kicker_state = Kicker_off;
            kicker_timer.Stop();
        }
        break;
    }
    
}	// end operator control loop



I’d recommend using the Notifier class. It automatically calls a callback function after a given amount of time, and works on an interrupt level so it doens’t block other code until it runs.