This year as part of our climber we want to hook up a Current Sensor to monitor when the motor hits the rung (to shut it off).
In my Subsystem I setup the sensor as an AnalogChannel on channel 1, However whenever I run said code it crashes and give a "Analog Channel 1 on Module 1 is already allocated. I have no idea why this is happening… Help is much appreciated!!!
I will post the important files below, need anymore and I will gladly post them too.
Subsystem:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.wpilibj.templates.subsystems;
import edu.wpi.first.wpilibj.AnalogChannel;
import edu.wpi.first.wpilibj.command.Subsystem;
import edu.wpi.first.wpilibj.templates.commands.PrintCurrent;
/**
*
* @author Gustave Michel
*/
public class CurrentDetector extends Subsystem {
// Put methods for controlling this subsystem
// here. Call these from Commands.
AnalogChannel sensor;
public CurrentDetector() {
sensor = new AnalogChannel(2);
}
public void initDefaultCommand() {
// Set the default command for a subsystem here.
//setDefaultCommand(new MySpecialCommand());
setDefaultCommand(new PrintCurrent());
}
public double get() {
return sensor.getVoltage();
}
}
CommandBase
package edu.wpi.first.wpilibj.templates.commands;
import edu.wpi.first.wpilibj.Gyro;
import edu.wpi.first.wpilibj.command.Command;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.wpilibj.templates.OI;
import edu.wpi.first.wpilibj.templates.subsystems.CurrentDetector;
import edu.wpi.first.wpilibj.templates.subsystems.ExampleSubsystem;
import edu.wpi.first.wpilibj.templates.subsystems.SpikeLoad;
/**
* The base for all commands. All atomic commands should subclass CommandBase.
* CommandBase stores creates and stores each control system. To access a
* subsystem elsewhere in your code in your code use CommandBase.exampleSubsystem
* @author Author
*/
public abstract class CommandBase extends Command {
public static OI oi;
// Create a single static instance of all of your subsystems
public static ExampleSubsystem exampleSubsystem = new ExampleSubsystem();
CurrentDetector currentDetector = new CurrentDetector();
SpikeLoad spikeLoad = new SpikeLoad();
public static void init() {
// This MUST be here. If the OI creates Commands (which it very likely
// will), constructing it during the construction of CommandBase (from
// which commands extend), subsystems are not guaranteed to be
// yet. Thus, their requires() statements may grab null pointers. Bad
// news. Don't move it.
oi = new OI();
// Show what command your subsystem is running on the SmartDashboard
SmartDashboard.putData(exampleSubsystem);
}
public CommandBase(String name) {
super(name);
}
public CommandBase() {
super();
}
}
Command:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.wpilibj.templates.commands;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
/**
*
* @author Gustave Michel
*/
public class PrintCurrent extends CommandBase {
public PrintCurrent() {
// Use requires() here to declare subsystem dependencies
// eg. requires(chassis);
requires(currentDetector);
}
// Called just before this Command runs the first time
protected void initialize() {
}
// Called repeatedly when this Command is scheduled to run
protected void execute() {
SmartDashboard.putNumber("CurrentDetector", currentDetector.get());
}
// Make this return true when this Command no longer needs to run execute()
protected boolean isFinished() {
return false;
}
// Called once after isFinished returns true
protected void end() {
}
// Called when another command which requires one or more of the same
// subsystems is scheduled to run
protected void interrupted() {
}
}
In your posted code it’s initializing to analog 2, but I assume that’s either a typo or you put it in place for a test. If it says that analog 1 is already allocated, you must have another AnalogChannel in your code using that same port. It doesn’t seem to be in your posted code, so you’ll have to go through the rest of your code to check. Keep in mind that certain other things, like Gyros, also use AnalogChannels internally.
Oh yeah, I tried changing the port to see if it did the same thing (the port I used for the Current Sensor is the number that shows up in the error, always.)
There is only one other subsystem:
SpikeLoad:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.wpilibj.templates.subsystems;
import edu.wpi.first.wpilibj.Relay;
import edu.wpi.first.wpilibj.command.Subsystem;
import edu.wpi.first.wpilibj.templates.commands.StopSpike;
/**
*
* @author Gustave Michel
*/
public class SpikeLoad extends Subsystem {
// Put methods for controlling this subsystem
// here. Call these from Commands.
Relay relay = new Relay(1);
public void initDefaultCommand() {
// Set the default command for a subsystem here.
//setDefaultCommand(new MySpecialCommand());
setDefaultCommand(new StopSpike());
}
public void set(Relay.Value value) {
relay.set(value);
}
}
and its commands:
RunSpike:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.wpilibj.templates.commands;
import edu.wpi.first.wpilibj.Relay;
/**
*
* @author Gustave Michel
*/
public class RunSpike extends CommandBase {
public RunSpike() {
// Use requires() here to declare subsystem dependencies
// eg. requires(chassis);
requires(spikeLoad);
}
// Called just before this Command runs the first time
protected void initialize() {
}
// Called repeatedly when this Command is scheduled to run
protected void execute() {
spikeLoad.set(Relay.Value.kForward);
}
// Make this return true when this Command no longer needs to run execute()
protected boolean isFinished() {
return false;
}
// Called once after isFinished returns true
protected void end() {
}
// Called when another command which requires one or more of the same
// subsystems is scheduled to run
protected void interrupted() {
}
}
StopSpike:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.wpilibj.templates.commands;
import edu.wpi.first.wpilibj.Relay;
/**
*
* @author Gustave Michel
*/
public class StopSpike extends CommandBase {
public StopSpike() {
// Use requires() here to declare subsystem dependencies
// eg. requires(chassis);
requires(spikeLoad);
}
// Called just before this Command runs the first time
protected void initialize() {
}
// Called repeatedly when this Command is scheduled to run
protected void execute() {
spikeLoad.set(Relay.Value.kOff);
}
// Make this return true when this Command no longer needs to run execute()
protected boolean isFinished() {
return false;
}
// Called once after isFinished returns true
protected void end() {
}
// Called when another command which requires one or more of the same
// subsystems is scheduled to run
protected void interrupted() {
}
}
OI:
package edu.wpi.first.wpilibj.templates;
import edu.wpi.first.wpilibj.Joystick;
import edu.wpi.first.wpilibj.buttons.Button;
import edu.wpi.first.wpilibj.buttons.JoystickButton;
import edu.wpi.first.wpilibj.templates.commands.RunSpike;
/**
* 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);
// Another type of button you can create is a DigitalIOButton, which is
// a button or switch hooked up to the cypress module. These are useful if
// you want to build a customized operator interface.
// Button button = new DigitalIOButton(1);
// 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());
Joystick joystick = new Joystick(1);
Button spike = new JoystickButton(joystick, 1);
public OI() {
spike.whileHeld(new RunSpike());
}
}
Main Robot Class:
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.templates;
import edu.wpi.first.wpilibj.IterativeRobot;
import edu.wpi.first.wpilibj.command.Command;
import edu.wpi.first.wpilibj.command.Scheduler;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.templates.commands.CommandBase;
import edu.wpi.first.wpilibj.templates.commands.StopSpike;
/**
* The VM is configured to automatically run this class, and to call the
* functions corresponding to each mode, as described in the IterativeRobot
* documentation. If you change the name of this class or the package after
* creating this project, you must also update the manifest file in the resource
* directory.
*/
public class RobotTemplate extends IterativeRobot {
Command autonomousCommand;
/**
* This function is run when the robot is first started up and should be
* used for any initialization code.
*/
public void robotInit() {
// instantiate the command used for the autonomous period
autonomousCommand = new StopSpike();
// Initialize all subsystems
CommandBase.init();
}
public void autonomousInit() {
// schedule the autonomous command (example)
autonomousCommand.start();
}
/**
* This function is called periodically during autonomous
*/
public void autonomousPeriodic() {
Scheduler.getInstance().run();
}
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.
autonomousCommand.cancel();
}
/**
* This function is called periodically during operator control
*/
public void teleopPeriodic() {
Scheduler.getInstance().run();
}
/**
* This function is called periodically during test mode
*/
public void testPeriodic() {
LiveWindow.run();
}
}
RobotMap is empty, and that is every class in the project.
The problem here is that you are creating one instance of CurrentDetector for every instance of CommandBase.
// Create a single static instance of all of your subsystems
public static ExampleSubsystem exampleSubsystem = new ExampleSubsystem();
CurrentDetector currentDetector = new CurrentDetector();
SpikeLoad spikeLoad = new SpikeLoad();
Since you have multiple classes that extend CommandBase, you have multiple instances of CurrentDetector and SpikeLoad.
Each time you create a new instance of CurrentDetector, it tries to allocate Analog Channel 2. The error you are getting is that the channel is being allocated multiple times.
To fix this problem, you should make the instances of CurrentDetector and SpikeLoad static:
// Create a single static instance of all of your subsystems
public static ExampleSubsystem exampleSubsystem = new ExampleSubsystem();
public static CurrentDetector currentDetector = new CurrentDetector();
public static SpikeLoad spikeLoad = new SpikeLoad();