Motors/solenoids won't work; Can't print to console

I don’t know what to do. I’m out of ideas. I go to a small, rural high school, that doesn’t offer any programming classes, so I’ve taught myself some coding over the past few months. My code looks fine, and I can’t find any mistakes in it, but for whatever reason, nothing on the robot (other than driving) will work. None of the solenoids extend, none of the window motors turn…nothing. I’ve nested a few print statements throughout my code, but they aren’t printing to the console when the robot is running. Can someone take a look at my code, and tell me if there are any glaring mistakes? I know it’s a lot to ask, but I don’t have any other options at this point. Thank you all so much in advance. (By the way, our robot has a pneumatic-powered arm, sort of like a tractor backhoe or excavator. The arm rotates on a window motor. It also shoots by pushing the ball with a solenoid into 2 spinning motors.)


#include "WPILib.h"
#include <stdio.h>

class Robot: public IterativeRobot
{
	RobotDrive myRobot;
	Joystick stick;
	Joystick stick2;
	DoubleSolenoid solenoid1;
	DoubleSolenoid solenoid2;
	Solenoid shooter_piston;
	Solenoid claw;
	Relay shooter_motors;
	Relay arm_rotator;
	LiveWindow* lw;
	int autoloopcounter;

	const int button2 = 2;
	const int button3 = 3;
	const int button4 = 4;
	const int button5 = 5;
public:
	Robot() :
		myRobot(0,1,2,3),
		stick(0),
		stick2(1),
		solenoid1(1, 2),
		solenoid2(3, 4),
		shooter_piston(5),
		claw(6),
		shooter_motors(0),
		arm_rotator(1),
		lw(LiveWindow::GetInstance()),
		autoloopcounter(0)
	{
		myRobot.SetExpiration(0.1);
	}

		void RobotInit() {
				CameraServer::GetInstance()->SetQuality(50);
				CameraServer::GetInstance()->      StartAutomaticCapture("cam0");

				chooser = new SendableChooser();
										chooser->AddDefault(autoNameDefault, (void*)&autoNameDefault);
										chooser->AddObject(autoNameCustom, (void*)&autoNameCustom);
										SmartDashboard::PutData("Auto Modes", chooser);
			}

private:
	SendableChooser *chooser;
	const std::string autoNameDefault = "Default";
	const std::string autoNameCustom = "My Auto";
	std::string autoSelected;

	void AutonomousInit()
	{
		autoSelected = *((std::string*)chooser->GetSelected());
		std::cout << "Auto selected: " << autoSelected << std::endl;

		if(autoSelected == autoNameCustom){
			//Custom Auto goes here
		} else {
			//Default Auto goes here
		}
	}

	void AutonomousPeriodic()
	{
		if(autoSelected == autoNameCustom){
			//Custom Auto goes here
		} else {
			//Default Auto goes here
		}
	}

	void TeleopInit()
	{

	}

	void TeleopPeriodic()
	{
///////////ARM CODE////////////////////////////////////////////////
		//Code that lifts the entire arm (boom)
	double joystick2Y;
	joystick2Y = stick2.GetY();
	if (joystick2Y > 0.1) {
		printf ("Joystick 2 activated for arm");
		solenoid1.Set(DoubleSolenoid::kForward); }
	else if (joystick2Y < -0.1) {
		printf ("Joystick 2 activated for arm (negative)");
		solenoid1.Set(DoubleSolenoid::kReverse); }

		//Code that extends the arm
	if (stick2.GetRawButton(button2)) {
		printf ("Button 2 pressed for arm");
		solenoid2.Set(DoubleSolenoid::kForward); }
	else if (stick2.GetRawButton(button3)) {
		printf ("Button 3 pressed for arm");
		solenoid2.Set(DoubleSolenoid::kReverse); }
	else {
		solenoid2.Set(DoubleSolenoid::kOff); }

		//Code that rotates the arm
    double joystick2X;
    joystick2X = stick2.GetX();
    if (joystick2X > 0.1) {
    	printf ("Joystick 2 activated for rotation");
    	arm_rotator.Set(Relay::kForward); }
    else if (joystick2X < -0.1) {
    	printf ("Joystick 2 activated for rotation (reverse)");
    	arm_rotator.Set(Relay::kReverse); }
    else {
    	arm_rotator.Set(Relay::kOff); }

		//Code that operates the claw
	claw.Set(stick2.GetTrigger());

///////////SHOOTER CODE////////////////////////////////////////////////
		//Code that operates the shooting motors
	if (stick.GetRawButton(button2)) {
		printf ("Button 2 pressed for shooter motors");
		shooter_motors.Set(Relay::kForward); }
    else if (stick2.GetRawButton(button3)) {
    	printf ("Button 3 pressed for shooter motors");
    	shooter_motors.Set(Relay::kReverse); }
    else {
    	shooter_motors.Set(Relay::kOff); }

		//Code that initiates the shooter piston
	shooter_piston.Set(stick.GetTrigger());

/////////DRIVE CODE//////////////////////////////////////////////////////
		//Code that drives the robot
		myRobot.ArcadeDrive(stick);
	}

	void TestPeriodic()
	{
		lw->Run();
	}
};

START_ROBOT_CLASS(Robot)


I’m more used to looking at Java than C++, so maybe I’m just missing it, but I don’t see where either stick or stick2 are constructed. I would expect this code to throw null pointer exceptions all over the place.

They’re constructed under the Robot class definition, right?


class Robot: public IterativeRobot
{
	RobotDrive myRobot;
	Joystick stick;                      //Aren't they declared here...
	Joystick stick2;
	DoubleSolenoid solenoid1;
	DoubleSolenoid solenoid2;
	Solenoid shooter_piston;
	Solenoid claw;
	Relay shooter_motors;
	Relay arm_rotator;
	LiveWindow* lw;
	int autoloopcounter;

	const int button2 = 2;
	const int button3 = 3;
	const int button4 = 4;
	const int button5 = 5;
public:
	Robot() :
		myRobot(0,1,2,3)
		stick(0),                         //and initialized here?
		stick2(1),                                
		solenoid1(1, 2),
		solenoid2(3, 4),
		shooter_piston(5),
		claw(6),
		shooter_motors(0),
		arm_rotator(1),
		lw(LiveWindow::GetInstance()),
		autoloopcounter(0)

Any messages or in the console log? Maybe a “timeout expired”? I don’t see any calls to enable or disable motor safety.

Check the mapping of the joystick in the driver’s station and make sure it works by monitoring it in the driver’s station diagnostics.

I would put some prints in some obvious places that always called to make sure your code is getting compiled and deployed successfully, for example, print out the value of joystick2Y before comparing it. You could also print “Hey I’m alive!” in TeleopInit()

Yeah, we get the timeout expired one occasionally. And I’ve nested a few more print statements. What do you mean by enable/disable motor safety?

I don’t see anything obviously wrong with the code. How’s your wiring?

Seriously, where do you have the motors wired to? I assume they’re Spike relay modules, but which connectors? What are the Spikes’ LED indicators doing? How do you have the wires run between the Spike and roboRIO?

Similarly with the pneumatic solenoids, what are they connected to? Assuming it’s a PCM, what are its LEDs showing you?

I got the solenoids working. The motors are wired into the spike relays, and the spikes are wired into the power distribution board and the Relay ports on the roboRIO. We’re pretty sure that our spikes are broken somehow. I wrote this block that should just turn on the motors and leave them spinning as long as TeleOp is enabled. I’ve tried a few variations of this, and the motors still won’t turn on. Logic dictates that if the relays were working, they’d be continuously running, right?


void TeleopPeriodic()
	{
		shooter_motors.Set(Relay::kOn);  
		arm_rotator.Set(Relay::kOn);
		if (true) {
			cout << "A motor should be on" << endl;
			shooter_motors.Set(Relay::kForward);
			arm_rotator.Set(Relay::kForward);
		}

		myRobot.ArcadeDrive(stick);
	}

Did you check to see if the fuses in the spikes were blown? You do have a fuse or breaker installed in each, right?

You’re not describing your wiring with enough detail to help us help you. There are lots of ways to wire Spikes to motors and power and roboRIO ports that won’t work. If you can’t tell us exactly where each of seven wires (GND, 12V, M+, M-, white, red, and black) is going, perhaps you can post a clear picture of each connection.

You also aren’t telling us what the Spike’s LED is doing. What color is it when you apply power? What color is it when you enable the robot? What color is it when you’re trying to run the motor?

I wrote this block that should just turn on the motors and leave them spinning as long as TeleOp is enabled. I’ve tried a few variations of this, and the motors still won’t turn on. Logic dictates that if the relays were working, they’d be continuously running, right?

You’re probably abusing your Spikes with that code. You’re setting both outputs to 12V for an instant, then immediately commanding the M- output to GND, every time through the Teleop loop. If it’s wired properly, you might hear the M- relay trying to buzz, and you should see the LED shining green, perhaps with a barely perceptible flicker. Depending on the physical response time of the relay, and on the magnetic decay characteristics of the coil, the M- output might never actually get connected to ground while the M+ relay is at 12V, and the motor will not run.

Do you see the “A motor should be on” message printing 50 times a second?

We checked our wiring with the diagrams, and it all matches. The LED on the relays is either off, or orange. Are there any guides or pictures online for wiring a spike relay?

Do you have the spike blue manual? (linked from the Vex page where the relay is sold).

If the LED goes straight from orange to black, this means that both sides of the relay are switching at the same time (or that you’re losing power). It appears you are using kForward not kOn, so I’ll move on to hardware. The first thing I can think of is that the red and white wires on your “PWM” data cable are shorted to each other, or that there is a similar short in your RIO or Spike. If the cable tests OK, look in the connector wells for swarf (metal shavings) or other conductive material.

Edit: If you get through all of those, put a meter or the output of the data cable and see what you get. When the motor is supposed to be going forward, you should get 0V on red and 5V on white (using the black data wire as a reference). It looks like you are having both go to 5V at the same time.

:confused:

If you don’t know how to wire a Spike, how can you say that it matches? You might not be understanding the right way to do it. Please answer the questions and let us help you. Tell us exactly where and what each of the seven connections on the Spike (GND, 12V, M+, M-, white, red, and black) is wired to. Be more specific and detailed than you think you need to, including everything that you think you’re doing right, because you might be wrong about what right means.

The LED on the relays is either off, or orange.

But when is it those colors? Please answer the questions and let us help you. What color is it when you turn on the robot? What color is it when you enable the robot using the Driver Station? What color is it when you’re trying to run the motor?

Also show us the rest of your code, so we can verify that you’re defining and initializing the relay objects properly.