cRIO upgrade v20 relay problems

The relay code behavior appears to have changed when we updated the cRio firmware from v19 to v20.

The relay is set into forward only mode. When a joystick button is pushed, the relay is turned “on” (sets it to kOn). Our code then sleeps for 500 ms, then turns the relay off (sets it to kOff).
Before the update to v20, this worked as expected. The relay light would turn green for half a second, then turn back to amber. Now, it only stays green for maybe a tenth of a second. We increased the sleep time to several seconds, but it is having no effect. It seems like the relay code is turning itself off. Any ideas about what could have happened?

99.99999999% of the time, programmers will correlate mysterious bugs with things like Windows updates, daylight savings time, tacos at lunch, and updating the cRio to v20. In actuality, the program was changed at around the same time and now it doesn’t work. Post your code and we can fix it regardless of what version your cRio is running. :]

Without seeing your code, though, I might suggest that you use a timer to control time sensitive actions. It’s not a good idea to pause your robot code. Imagine if you just passed out for .5 seconds then woke up. You would be confused. It is better practice to let your code cycle so that all the sensor and user input can be processed and acted upon. So for your relay, you would start the timer when the button is pushed, set the relay to kOn until the timer reaches your setpoint, then kOff.

To elaborate on the previous post, the last update to WPILibJ enables the watchdog by default and sets the timeout to 0.1 seconds. Since your user program is sleeping the watchdog is not being fed and the output is disabled after the tenth of a second as described. I would recommend to use a timer or a separate thread for this rather than pause all of your code.

So it seems that I was not blaming the problem on the change of phase of the moon after all. This did result from the update to v20. Thank you, MattD, for your cordial and knowledgeable response.

Our code looks like this -

relay7.set(Relay.Value.kOn);
// delay half second
try { Thread.sleep(500);
} catch( InterruptedException e ){}
relay7.set(Relay.Value.kOff);

I think this should yield to the rest of the system and allow whatever needs to happen with the watchdog to happen, no?

Is there some code concerning the watchdog that we may not have changed like we should have?

OK, I think the light bulb over my head is beginning to make buzzing noises and glow dimly.

We have not tried this yet (and please correct me if I am wrong), but it appears that the *user *watchdog is set to timeout after .1 seconds, and since our user code is sleeping for .5 seconds, nobody is kicking the dog, and it is therefore zapping us.

First, this evening we are going to try just disabling the user watchdog during init to see if that corrects the issue(?) Based on the results of that test, we will investigate changing the structure of our code to put some kind of dog-kicking mechanism into a separate thread, or setting the timeout on the watchdog to 1 second, or leave it disabled. (If leaving it disabled is verboten, PLEASE let me know!)

Assuming we are now merrily on our way, thanks for the input!

Sounds like you have it figured out. The best way to deal with this is to do your delaying asynchronously via a timer, thus letting your Watchdog get fed (not kicked! :)) by your main thread of execution. But turning off the Watchdog or setting the timeout to something longer than your delay would also be technically correct (if a bit more unsafe). Making a separate thread to feed your Watchdog is not something that I would not recommend (having a safety mechanism in place that does nothing to ensure safety is arguably worse than having none at all).

I know that in LV, there is a “Delay and Feed” VI that does what you are looking for. I’ll assume there is an equivalent in Java.

Basically, it waits for the given amount of time while feeding the watchdog. No need for extra loops or yields or whatnot!

I agree with Jared that you should apply a timer to your timed functions (as mentioned previously). Your idea of starting another thread for the watchdog is interesting, but I’m not sure if it will work as the watchdog is attached to your RobotBase which is extended by IterativeRobot and SimpleRobot. It is, in general, ok to disable the watchdog to test problems, but the robot should be up on blocks. You cannot disable a runaway robot that is no longer listening to controls, which is the reason why the watchdog is there. Here is how we handle our kick timer (in stripped down code)

public class IRobot extends IterativeRobot
{
 
    Timer robotTime = new Timer();
    
    Joystick js_right = new Joystick(1);
    Joystick js_left = new Joystick(2);
    Solenoid latch = new Solenoid(1);
    Solenoid unlatch = new Solenoid(2);
    Solenoid kick1 = new Solenoid(3);
    Solenoid unkick1 = new Solenoid(4);

    public void robotInit()
    {

        this.getWatchdog().setEnabled(true);
        this.getWatchdog().setExpiration(.2);
        this.getWatchdog().feed();
        robotTime.reset();
        robotTime.stop();
    }

    
    public void disabledPeriodic()
    {
        this.getWatchdog().feed();
      
    
    /**
     * This function is called periodically during operator control
     */
    public void teleopPeriodic()
    {

       

        //***************Kicker Controls*****************
        if (!kicking && js_left.getTrigger())
        {
            kicking = true;
        }
        if (kicking)
        {
            kickTimer();
        }

    
    }

    public boolean kickTimer()
    {
        
        if (robotTime.get() == 0)
        {
            // KICK
            latch.set(false);
            unlatch.set(true);
            robotTime.start();
        } else if (robotTime.get() >= 0.5)
        {
            // RETRACT
            latch.set(true);
            unlatch.set(false);
            kick1.set(false);
            unkick1.set(true);
        }
        if (robotTime.get() >= 4)
        {
            // GET READY TO KICK AGAIN
            kick1.set(true);
            unkick1.set(false);
            kicking = false;
            robotTime.stop();
            robotTime.reset();
        }
        return kicking;
    }

It should be noted that the Timer object here is the one defined by the WPI library and NOT the one defined by java.util.

It’s also possible that an exception is being thrown by the wait.

It’s a good idea to always output something in the catch statement just in case an exception is thrown.

Something like

try {
  // your code that may throw exception
} catch (Exception e) {
   System.err.println(e);  // this will print the stack trace of the exception
}

This way you’ll be able to tell in the output if something wacky is happening.

Our test (disabling the user watchdog) did “correct” the issue. We are now looking at what our real fix will be. Thanks for all the input!

And FYI, if you look at my avatar, you will see that it is OK for me to refer to it as “kicking the dog”, since I am a virtual dog in CD space. :smiley: