Running compressor blocks solenoid use

In our pneumatics setup, all our cylinders, solenoids and commands are working as expected except that when the compressor management code buried in wpilib turns the compressor on, the pneumatics commands are blocked and we have to wait for the compressor to finish.

Is this normal or have we missed something in the software somehow?

Thanks

That is not normal

Can you post a copy of the code please

It sounds like you have a separate command to handle the compressor running. It would be safer to initialize the compressor in the subsystem’s constructor.

Though, your code would really help solve the issue!

Thank you all for the replies. I’m slow in responding as I was expecting to get email notice. Guess my settings are wrong.

In any case, we have no code referencing the compressor at all. We use the pneumatics control module and per the wpilib docs, the compressor runs as soon as we instantiate the first solenoid and after that just runs in the min/max pressure loop on its own.

What parts of the software would you want to see. I’d hate to post the entire set of classes. Perhaps Robot.java, RobotMap.java, Pneumatics.java (the subsystem) and one of the pneumatics commands used with the solenoids?

For these kinds of bugs, a very effective technique is to create a new program with absolutely the minimum code for the solenoid. In the CS world these are called “Test cases”and if they work you can go on from there, and easy to post here.

If test cases still fail, it’ll really help the group who has to fix the bug to have the Test case, and hopefully it’ll get the bug fixed faster. And you’ll get more respect for having done as much as you could do, before reporting the bug.

I’m not allowed to post a zip file now or at least not yet, so here is what seems likely to be the relevant code for this robot.

I reiterate that we have used no compressor code in our robot classes. All the compressor work is being done under the covers by the wpilib code.

Here is the robot map class:

// RobotBuilder Version: 2.0
//
// This file was generated by RobotBuilder. It contains sections of
// code that are automatically generated and assigned by robotbuilder.
// These sections will be updated in the future when you export to
// Java from RobotBuilder. Do not put any code or make any change in
// the blocks indicating autogenerated code or it will be lost on an
// update. Deleting the comments indicating the section will prevent
// it from being updated in the future.

package org.usfirst.frc5585.PowerUp2018;

// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=IMPORTS
import edu.wpi.first.wpilibj.DoubleSolenoid;
import edu.wpi.first.wpilibj.PWMTalonSRX;
import edu.wpi.first.wpilibj.RobotDrive;
import edu.wpi.first.wpilibj.Spark;
import edu.wpi.first.wpilibj.SpeedController;

// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=IMPORTS

import edu.wpi.first.wpilibj.livewindow.LiveWindow;

/**

  • The RobotMap is a mapping from the ports sensors and actuators are wired into

  • to a variable name. This provides flexibility changing wiring, makes checking

  • the wiring easier and significantly reduces the number of magic numbers

  • floating around.
    */
    public class RobotMap {
    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS
    public static SpeedController driveTrainLeftRear;
    public static SpeedController driveTrainLeftFront;
    public static SpeedController driveTrainRightRear;
    public static SpeedController driveTrainRightFront;
    public static RobotDrive driveTrainRobortDrive;
    public static DoubleSolenoid pnuematicsGripper;
    public static DoubleSolenoid pnuematicsLift;

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS

    public static void init() {
    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
    driveTrainLeftRear = new PWMTalonSRX(3);
    LiveWindow.addActuator(“DriveTrain”, “Left Rear”, (PWMTalonSRX) driveTrainLeftRear);
    driveTrainLeftRear.setInverted(false);
    driveTrainLeftFront = new Spark(0);
    LiveWindow.addActuator(“DriveTrain”, “Left Front”, (Spark) driveTrainLeftFront);
    driveTrainLeftFront.setInverted(false);
    driveTrainRightRear = new PWMTalonSRX(2);
    LiveWindow.addActuator(“DriveTrain”, "Right Rear ", (PWMTalonSRX) driveTrainRightRear);
    driveTrainRightRear.setInverted(false);
    driveTrainRightFront = new Spark(1);
    LiveWindow.addActuator(“DriveTrain”, “Right Front”, (Spark) driveTrainRightFront);
    driveTrainRightFront.setInverted(false);
    driveTrainRobortDrive = new RobotDrive(driveTrainLeftFront, driveTrainLeftRear,
    driveTrainRightFront, driveTrainRightRear);

     driveTrainRobortDrive.setSafetyEnabled(true);
     driveTrainRobortDrive.setExpiration(0.1);
     driveTrainRobortDrive.setSensitivity(0.5);
     driveTrainRobortDrive.setMaxOutput(1.0);
    
     pnuematicsGripper = new DoubleSolenoid(0, 3, 2);
     LiveWindow.addActuator("Pnuematics", "Gripper", pnuematicsGripper);
     
     pnuematicsLift = new DoubleSolenoid(0, 0, 1);
     LiveWindow.addActuator("Pnuematics", "Lift", pnuematicsLift);
    

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
    }
    }

Here is the Robot class:

// RobotBuilder Version: 2.0
//
// This file was generated by RobotBuilder. It contains sections of
// code that are automatically generated and assigned by robotbuilder.
// These sections will be updated in the future when you export to
// Java from RobotBuilder. Do not put any code or make any change in
// the blocks indicating autogenerated code or it will be lost on an
// update. Deleting the comments indicating the section will prevent
// it from being updated in the future.

package org.usfirst.frc5585.PowerUp2018;

import edu.wpi.first.wpilibj.TimedRobot;
import edu.wpi.first.wpilibj.command.Command;
import edu.wpi.first.wpilibj.command.Scheduler;
import edu.wpi.first.wpilibj.drive.DifferentialDrive;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import org.usfirst.frc5585.PowerUp2018.commands.;
import org.usfirst.frc5585.PowerUp2018.subsystems.
;

/**

  • The VM is configured to automatically run this class, and to call the

  • functions corresponding to each mode, as described in the TimedRobot

  • documentation. If you change the name of this class or the package after

  • creating this project, you must also update the build.properties file in

  • the project.
    */
    public class Robot extends TimedRobot {

    Command autonomousCommand;
    SendableChooser<Command> chooser = new SendableChooser<>();

    public static OI oi;
    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS
    public static DriveTrain driveTrain;
    public static Pnuematics pnuematics;

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS

    SendableChooser auto;
    public static AutonomousVars autoVars;

    /**

    • This function is run when the robot is first started up and should be

    • used for any initialization code.
      */
      @Override
      public void robotInit() {
      RobotMap.init();
      autoVars = new AutonomousVars(); // subsystems

      // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
      driveTrain = new DriveTrain();
      pnuematics = new Pnuematics();

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
    // OI must be constructed after subsystems. If the OI creates Commands
    //(which it very likely will), subsystems are not guaranteed to be
    // constructed yet. Thus, their requires() statements may grab null
    // pointers. Bad news. Don’t move it.
    oi = new OI();
    auto = new SendableChooser(); // auto chooser code
    //auto.addDefault(“center”, new CenterAuto());
    //auto.addObject(“baseline”, new BaselineAuto());
    SmartDashboard.putData(“Autonomous program”, auto);
    SmartDashboard.putData(Scheduler.getInstance()); // init smartdashboard
    SmartDashboard.putData(Robot.driveTrain);
    //SmartDashboard.putData(Robot.lift);
    SmartDashboard.putString(“Camera Direction:”, “Forward”);
    //dashboard();

     // Add commands to Autonomous Sendable Chooser
     // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=AUTONOMOUS
    
     chooser.addDefault("Auto Drive", new AutoDrive());
    

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=AUTONOMOUS
    SmartDashboard.putData(“Auto mode”, chooser);
    }

    /**

    • This function is called when the disabled button is hit.
    • You can use it to reset subsystems before shutting down.
      */
      @Override
      public void disabledInit(){

    }

    @Override
    public void disabledPeriodic() {
    Scheduler.getInstance().run();
    }

    @Override
    public void autonomousInit() {
    autonomousCommand = chooser.getSelected();
    // schedule the autonomous command (example)
    if (autonomousCommand != null) autonomousCommand.start();
    }

    /**

    • This function is called periodically during autonomous
      */
      @Override
      public void autonomousPeriodic() {
      Scheduler.getInstance().run();
      }

    @Override
    public void teleopInit() {
    // This makes sure that the autonomous stops running when
    // teleop starts running. If you want the autonomous to
    // continue until interrupted by another command, remove
    // this line or comment it out.
    if (autonomousCommand != null) autonomousCommand.cancel();
    }

    /**

    • This function is called periodically during operator control
      */
      @Override
      public void teleopPeriodic() {
      Scheduler.getInstance().run();
      // dashboard();

    }
    }

Here is the OI class:

// RobotBuilder Version: 2.0
//
// This file was generated by RobotBuilder. It contains sections of
// code that are automatically generated and assigned by robotbuilder.
// These sections will be updated in the future when you export to
// Java from RobotBuilder. Do not put any code or make any change in
// the blocks indicating autogenerated code or it will be lost on an
// update. Deleting the comments indicating the section will prevent
// it from being updated in the future.

package org.usfirst.frc5585.PowerUp2018;

import org.usfirst.frc5585.PowerUp2018.commands.*;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.wpilibj.Joystick;
import edu.wpi.first.wpilibj.buttons.JoystickButton;

import org.usfirst.frc5585.PowerUp2018.subsystems.*;

/**

  • This class is the glue that binds the controls on the physical operator

  • interface to the commands and command groups that allow control of the robot.
    */
    public class OI {
    //// CREATING BUTTONS
    // One type of button is a joystick button which is any button on a joystick.
    // You create one by telling it which joystick it’s on and which button
    // number it is.
    // Joystick stick = new Joystick(port);
    // Button button = new JoystickButton(stick, buttonNumber);

    // There are a few additional built in buttons you can use. Additionally,
    // by subclassing Button you can create custom triggers and bind those to
    // commands the same as any other Button.

    //// TRIGGERING COMMANDS WITH BUTTONS
    // Once you have a button, it’s trivial to bind it to a button in one of
    // three ways:

    // Start the command when the button is pressed and let it run the command
    // until it is finished as determined by it’s isFinished method.
    // button.whenPressed(new ExampleCommand());

    // Run the command while the button is being held down and interrupt it once
    // the button is released.
    // button.whileHeld(new ExampleCommand());

    // Start the command when the button is released and let it run the command
    // until it is finished as determined by it’s isFinished method.
    // button.whenReleased(new ExampleCommand());

    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS
    public JoystickButton gripperButton;
    public JoystickButton dropperButton;
    public JoystickButton liftButton;
    public JoystickButton lowerButton;
    public JoystickButton grabLiftButton;
    public JoystickButton grabLiftReleaseButton;
    public Joystick joystick;

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS

    public OI() {
    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS

     joystick = new Joystick(0);
     
     grabLiftReleaseButton = new JoystickButton(joystick, 7);
     grabLiftReleaseButton.whenPressed(new GrabLiftReleaseGroup());
     grabLiftButton = new JoystickButton(joystick, 8);
     grabLiftButton.whenPressed(new GrabLiftGroup());
     lowerButton = new JoystickButton(joystick, 6);
     lowerButton.whileHeld(new LowerCube());
     liftButton = new JoystickButton(joystick, 5);
     liftButton.whileHeld(new LiftCube());
     dropperButton = new JoystickButton(joystick, 4);
     dropperButton.whileHeld(new ReleaseCube());
     gripperButton = new JoystickButton(joystick, 3);
     gripperButton.whileHeld(new GrabCube());
    
    
     // SmartDashboard Buttons
     SmartDashboard.putData("Auto Drive", new AutoDrive());
     SmartDashboard.putData("Arcade Drive", new ArcadeDrive());
     SmartDashboard.putData("Lift Cube", new LiftCube());
     SmartDashboard.putData("Lower Cube", new LowerCube());
     SmartDashboard.putData("Grab Cube", new GrabCube());
     SmartDashboard.putData("Release Cube", new ReleaseCube());
     SmartDashboard.putData("Grab Lift Group", new GrabLiftGroup());
     SmartDashboard.putData("Grab Lift Release Group", new GrabLiftReleaseGroup());
     SmartDashboard.putData("Drive Forward", new DriveForward());
     SmartDashboard.putData("Turn Left", new TurnLeft());
     SmartDashboard.putData("Turn Right", new TurnRight());
     SmartDashboard.putData("Auto Drive Left Group", new AutoDriveLeftGroup());
    

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTORS
    }

    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=FUNCTIONS
    public Joystick getJoystick() {
    return joystick;
    }

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=FUNCTIONS
    }

Here is the pneumatics subsystem class:

// RobotBuilder Version: 2.0
//
// This file was generated by RobotBuilder. It contains sections of
// code that are automatically generated and assigned by robotbuilder.
// These sections will be updated in the future when you export to
// Java from RobotBuilder. Do not put any code or make any change in
// the blocks indicating autogenerated code or it will be lost on an
// update. Deleting the comments indicating the section will prevent
// it from being updated in the future.

package org.usfirst.frc5585.PowerUp2018.subsystems;

import org.usfirst.frc5585.PowerUp2018.RobotMap;
import org.usfirst.frc5585.PowerUp2018.commands.*;
import edu.wpi.first.wpilibj.command.Subsystem;
// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=IMPORTS
import edu.wpi.first.wpilibj.DoubleSolenoid;

// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=IMPORTS

/**
*
*/
public class Pnuematics extends Subsystem {

// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTANTS

// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTANTS

// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS
private final DoubleSolenoid gripper = RobotMap.pnuematicsGripper;
private final DoubleSolenoid lift = RobotMap.pnuematicsLift;

// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DECLARATIONS

@Override
public void initDefaultCommand() {
	// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DEFAULT_COMMAND


// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=DEFAULT_COMMAND

	//
	// DoubleSolenoid Grabber = new DoubleSolenoid(1, 2);
	//
	// Grabber.set(DoubleSolenoid.Value.kOff);
	// Grabber.set(DoubleSolenoid.Value.kForward);
	// Grabber.set(DoubleSolenoid.Value.kReverse);
	// }

	// Set the default command for a subsystem here.
	// setDefaultCommand(new MySpecialCommand());

}

@Override
public void periodic() {
	// Put code here to be run every loop

}

// Put methods for controlling this subsystem
// here. Call these from Commands.
public void gripCube() {
	gripper.set(DoubleSolenoid.Value.kForward);
}

public void dropCube() {
	gripper.set(DoubleSolenoid.Value.kReverse);
}

public void liftCube() {
	lift.set(DoubleSolenoid.Value.kForward);
}

public void lowerCube() {
	lift.set(DoubleSolenoid.Value.kReverse);

}

}

And finally one of the pneumatics command classes:

// RobotBuilder Version: 2.0
//
// This file was generated by RobotBuilder. It contains sections of
// code that are automatically generated and assigned by robotbuilder.
// These sections will be updated in the future when you export to
// Java from RobotBuilder. Do not put any code or make any change in
// the blocks indicating autogenerated code or it will be lost on an
// update. Deleting the comments indicating the section will prevent
// it from being updated in the future.

package org.usfirst.frc5585.PowerUp2018.commands;
import edu.wpi.first.wpilibj.command.Command;
import org.usfirst.frc5585.PowerUp2018.Robot;

/**
*
*/
public class GrabCube extends Command {

// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=VARIABLE_DECLARATIONS

// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=VARIABLE_DECLARATIONS

// BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTOR
public GrabCube() {

// END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=CONSTRUCTOR
    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=VARIABLE_SETTING

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=VARIABLE_SETTING
    // BEGIN AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=REQUIRES
    requires(Robot.pnuematics);

    // END AUTOGENERATED CODE, SOURCE=ROBOTBUILDER ID=REQUIRES
}

// Called just before this Command runs the first time
@Override
protected void initialize() {
}

// Called repeatedly when this Command is scheduled to run
@Override
protected void execute() {
	Robot.pnuematics.gripCube();
}

// Make this return true when this Command no longer needs to run execute()
@Override
protected boolean isFinished() {
    return true;
}

// Called once after isFinished returns true
@Override
protected void end() {
}

// Called when another command which requires one or more of the same
// subsystems is scheduled to run
@Override
protected void interrupted() {
}

}

Let us know if any of this looks fundamentally wrong. A lot of the code is generated by the Robot Builder and then we add what’s needed to make things work.

Thanks,

Merritt

As I’m unable to attach files to my posts, I made a lengthy post with my code included. It looked like it was handled but now it seems not to be present.

I give up . . .

Merritt

It is OK to give up, just don’t quit.

Is your PCM indicating any errors? Check the behavior of the LEDs. Also, ensure that the 12/24v jumper is in the correct position for the solenoids you are using.

Oblarg

Haven’t seen the robot for a week due to kids being out on winter break and things being locked up.

If memory serves, there are no PCM errors or for that matter any errors showing in the console or on the PCM itself.

12/24 jumper is correct. Everything works perfectly when the compressor is not running, but as soon as it starts, none of the pneumatics controls function until it stops.

This is all pretty annoying since we have no code that addresses the compressor directly. We rely on the wpilib code to manage the compressor when we instantiate the solenoids in code.

I’ll be back at this on Tuesday next week. We aren’t competing this year but still have goals as far as the robot is concerned so it would be great to get things going.

As garyk suggests, we’ll try a stripped down program to just run the solenoids and nothing else to see if that helps.

Thanks for posting,

Merritt

Looking here today I see that the code I posted did indeed show up despite my post on 2018-02-24. If anyone has observations please comment. Some of the command group code is incomplete but shouldn’t affect this problem.

After double checking today, the status LED on the PCM is blinking green when the robot is up and enabled.

Per garyk’s suggestion above, we created a simple program that does nothing but run one double solenoid forward and reverse. The issue with the running compressor blocking solenoid operation is still present. As before, there is no code in this simple program that directly addresses the compressor.

Thanks in advance for any help.

Merritt

I think your problem may be related to RobotBuilder and how it generates commands and subsystems. We saw similar behavior when mapping motors to joystick buttons. You have options for whenpressed whenreleased and held(can’t remember exact wording) where you have isFinished(false) for the command by default. When holding the button or trigger wanted the motor to keep running. If return true for isFinished while the button is being held then the motor stopped running. Then we had behavior while a motor was running do a lift if we pressed another button to open the claw the motor doing the lift would stop even though we were still holding the button. I didn’t have time to dig into the docs but it appears that if you have a group of commands that have a dependency on a subsystem only one command can be active.

In an effort to try and another way since we didn’t have this issue when driving treated all motors as a 2 motor drive train and then in the special code it generates use the joystick to run the motor(s). As soon as we made this change the motors on our lift went twice as fast. It appears that when trying to run a motor from a command that it does not turn the motor on and wait for you to turn it off. It only stays on during the polling cycle of running the command mapped to a particular state of a joystick button.

We are also using pneumatics and found that while the compressor is running almost impossible to drive the robot. Figure it was a power issue but could be software related. We used robotbuilder to drag in the control and let it handle everything. There maybe a correct way to do this and a wrong way to do this in robot builder.

I like robot builder but definitely has some quirks and surprisingly not a great deal of examples.

I would separate out the part you dragged in for the controlling the compressor into it own subsystem and put pneumatics in different subsystems.

willishf:

As I’ve noted before, we have no compressor object in our top level code. Per the wpilib documentation, the Compressor object is created and managed by the wpilib code when we instantiate the double solenoids we use. We also don’t have a Compressor specified in our Robot Builder.

Our drives function well with or without the compressor running I believe, but will double check that tomorrow.

Thanks,

Merritt

Can you post that code for us to look over?

Will do so tomorrow, probably late afternoon. I’m at home now and code is on PC where we build.

garyk:

I archived the simple code from Eclipse and brought it home with me then realized I am not allowed to upload files here. What level of god to I have to be to be able to do that? If there is no way, I’ll have to copy and paste all the code in as I did with the larger project.

Sigh . . .

Merritt

GaryK:

Here is a link to an Eclipse archive of our simple pneumatics project. It has only the pneumatics subsystem and code to drive one double cylinder. It suffers from the same problem with the running compressor.

https://drive.google.com/open?id=12oe75LkmeNy0vd772tAW7fMgFmLdbE1o

Let me know if the link does not work for you. I’ve not tried this before.

Merritt

We’ve resolved this issue by instantiating a compressor object and then for each pneumatics command, we check to see if the compressor is in closed loop mode. If it is, we turn that off, run our command and then turn it back on.

This allows us to run the commands we need to without interruption. It isn’t optimum because it potentially allows us to run down the tank pressure to far for the solenoids to work. That shouldn’t happen in normal operation but it makes this solution less than ideal.

Thanks to everyone for at least looking at the code we posted and for your suggestions.

Merritt