Log in

View Full Version : Joystick 2/Program issue


miw14
20-02-2014, 20:50
Hello! My team is having quite a bit of problems with our 2nd joystick. We are using joystick 1 for driving and joystick 2 for our launcher. Our 2nd joystick doesn't seem to work at all. The driver station recognizes it, but we are unable to do anything with it. I hope it's just a simple code mistake. Could anyone help us out? Any help is greatly appreciated! Here is the code:


/*----------------------------------------------------------------------------*/ /* 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.SimpleRobot;
import edu.wpi.first.wpilibj.Joystick;
import edu.wpi.first.wpilibj.RobotDrive;
import edu.wpi.first.wpilibj.Talon;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.Victor;
/** * The VM is configured to automatically run this class, and to call the * functions corresponding to each mode, as described in the SimpleRobot * 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 Drive extends SimpleRobot {
private RobotDrive myDrive, Shooter;
private Joystick driveStick, driveStick2;
private Talon FrontRight, FrontLeft, BackRight, BackLeft;
private Victor M1, M2;
/** * This function is called once each time the robot enters autonomous mode. */
public void robotInit()
{
FrontRight = new Talon(1);
BackLeft = new Talon(2);
FrontLeft = new Talon(3);
BackRight = new Talon(4);
myDrive = new RobotDrive(FrontLeft, BackLeft, FrontRight, BackRight); myDrive.setInvertedMotor(RobotDrive.MotorType.kFro ntRight,true);
M1 = new Victor(5);
M2 = new Victor(6);
Shooter = new RobotDrive(M1, M2);
driveStick = new Joystick(1);
driveStick2 = new Joystick(2);

}
public void autonomous()
{
while(isAutonomous() && isEnabled())
myDrive.drive(-.5, 0.0);
Timer.delay(2.0);
myDrive.drive(0.0,0.0);

}
/** * This function is called once each time the robot enters operator control. */

public void operatorControl()
{
while(isOperatorControl() && isEnabled())
myDrive.arcadeDrive(driveStick);
Timer.delay(0.01);
Shooter.arcadeDrive(driveStick2);
Timer.delay(0.01); }

}

mwtidd
20-02-2014, 21:03
Have you tried using robotbuilder? I know our newer programmers had a lot of success using it. It helps you to avoid programming in a way that wpi doesn't support.

I was first skeptical of generating code that way, but I have since come around, and am now a big fan.

I would also recommend trying to only use one drive, and only have one timer delay. You only need one timer delay per iteration.

SousVide
20-02-2014, 21:36
What is the purpose of M1 and M2 (connected to victor 5 and victor 6) ?

Are they two motors connected to the same gearbox ? If that's the case, then arcade drive would run one of the motors forward and the other backwards - unless if you have one of the motor outputs from one of the victors wired in reverse, the motors will be running against each other in the gear box...

You can also check the output led on victors 5 and 6 also - changes in the led color and flash rate can help debug the motor drive system...

http://wpilib.screenstepslive.com/s/3120/m/8559/l/101397-light-codes-on-control-system-components

miw14
20-02-2014, 21:49
We have not tried robotbuilder, but I appreciate the suggestion and will explore it. Thanks!


M1 and M2 are motors connected to the Victor motor controls 5 and 6. The problem is that when we use Joystick 2 to move the motors, nothing happens. We have it wired properly because the lights are are solid orange on the Victor controllers. Could it be an issue with the USB port number? Or anything with the code?

SousVide
21-02-2014, 01:59
More importantly:

1. Are the 2 motors mounted into the same gearbox, or do they sit outside and mounted independent from each other ?

2. When you move joystick 2, do the victors' leds turn off or go to solid green or solid red or do anything besides solid orange ?



We have not tried robotbuilder, but I appreciate the suggestion and will explore it. Thanks!


M1 and M2 are motors connected to the Victor motor controls 5 and 6. The problem is that when we use Joystick 2 to move the motors, nothing happens. We have it wired properly because the lights are are solid orange on the Victor controllers. Could it be an issue with the USB port number? Or anything with the code?

miw14
21-02-2014, 08:46
1.) The motors are mounted independent of each other.

2.) The Victors stayed orange the whole time.

We switched the ports on the Victor controllers to 1 and 4 to see if it would work on Joystick 1 and it worked fine.

Joe Ross
21-02-2014, 12:14
Does Joystick 2 work if you use Joystick Explorer (http://wpilib.screenstepslive.com/s/3120/m/7912/l/133053-joysticks)?

I agree with SousVide, you probably do not want to use Arcade Drive for a shooter. This isn't causing your problem, but will once you start getting joystick 2 data. You should set both Victors individually.

SousVide
21-02-2014, 15:45
try this,

with the DriverStation in Teleop and Enabled... drive a bit with Joystick one.
Now unplug Joystick one from the laptop, does the DriverStation's Joystick light remain lit ?

Also, have you checked the joystick assignments in the DriverStation itself ?

miw14
22-02-2014, 11:14
Looks like joystick 2 is working again! Played around with the code and the dashboard, and it looks like things are working. Thanks for the help everyone!

As for not using arcade drive for the shooter, what would you recommend?

nyaculak
22-02-2014, 18:33
As for not using arcade drive for the shooter, what would you recommend?

You could use the victor.set(double speed) method. It works similar to the RobotDrive functions, expecting a value in the range of [-1, 1].

Better yet, you could use some object orientation magic to create a class that defines the behavior you want to see in your launcher. You can see team 53's implementation of this here (https://github.com/erhs-robotics/frc2014/blob/develop/src/org/erhsroboticsclub/frc2014/Catapult.java).

For the future, it will help you tremendously to gain a solid working knowledge of Java and other programming languages. You'll have a much better understanding of your own code and the wpilib libraries if you learn object oriented programming.

miw14
22-02-2014, 21:41
I'm taking AP CS online, so I do now a little bit of OOP, but nothing nearly as advanced as what you posted.

For the victor.set(double speed) method, what is the purpose? Is it to set a consistent speed when the joystick is pushed forward?

Thanks for the help! I really appreciate it. Our team has no mentors, so the entire build session has been very stressful.

pblankenbaker
23-02-2014, 08:00
I like to think of the set(power) methods on the SpeedController classes (like Victor, Talon and Jaguar) as the way to control how much power the speed controller lets through.

The power value can range from -1.0 (full reverse) to +1.0 (full foward).

For example:

victor.set(1.0); // Run motor "forwards" at full power
victor.set(0.5); // Run motor "forwards" at half power
victor.set(0.0); // Turn motor off (if Victor is calibrated)
victor.set(-0.25); // Run motor "backwards" at quarter power
victor.set(-1.0); // Run motor "backwards" at full power


The term "forwards" and "backwards" are virtual directions. Depending on how your motors are wired and mechanically connected, you may need to invert your power levels (use negative values for "forwards" and positive for "backwards") to get your physical device to move/rotate in the actual desired direction.
If your speed controller has not been calibrated, then setting a value of 0.0 may not fully stop the motor. See: http://content.vexrobotics.com/docs/217-2769-Victor888UserManual.pdf for directions on calibrating a Victor.


Hope that helps.

miw14
23-02-2014, 09:36
I kinda understand what you're saying. So the set method allows for a constant speed to be received to the motors? How would the program drive with the set method? Would I still use arcade drive? or would I use something else?

Thanks for help!

pblankenbaker
23-02-2014, 11:01
For your shooter, I would not use the RobotDrive class but recommend that your read values from your joysticks and then apply the current values to your shooter motors. Here's an example of a slight refactoring of some of your code:

public void operatorControl() {
while(isOperatorControl() && isEnabled()) {
myDrive.arcadeDrive(driveStick);
updateShooterPower();
Timer.delay(0.01);
}

// Stop motors
myDrive.stopMotor();
M1.set(0);
M2.set(0);
}

private void updateShooterPower() {
// Read in joystick values from second game pad
// (returns values in range of -1.0 to +1.0)
double m1Power = driveStick2.getRawAxis(2);
double m2Power = driveStick2.getRawAxis(4);

// You might need/want to adjust power values here, the following example
// treats values close to 0 as being zero

if (Math.abs(m1Power) < 0.05) {
m1Power = 0;
}

if (Math.abs(m2Power) < 0.05) {
m2Power = 0;
}

// Apply power to shooter motors
M1.set(m1Power);
M2.set(m2Power);

// If the joystick values or motor connections end up being the opposite of
// what you expect, you may need to invert the power applied to one or
// both of the motors.
// Commented example of how to invert the power applied to both motors:
//M1.set(-m1Power);
//M2.set(-m2Power);

}


NOTE:


You will need to experiment with the Joystick axis values (I showed 2 and 4 above, 1, 3 and 5 are also available).
If you want to apply the same power to both shooter motors you will only need to read one joystick axis.
You may need to negate (invert) the power applied to one or both of your motors in order to get them to spin in the proper direction.
The Y-axis on gamepads tends to return -1.0 when pushed all the way up and +1.0 when pulled all the way down.

miw14
23-02-2014, 11:36
I really appreciate your time and effort, thank you very much. I still have a few more questions.

What do the axis numbers represent? Are they button numbers? I thought that there are only 2 axes on the joystick.
We do want the motors running at the same power, so we would only need one axis.

Also for the code you posted, how would we shoot in autonomous?

Lastly, where would we set the Victor power? And if we set them once, would they be set for the same in both autonomous and teleoperated?

Thank you once again!

pblankenbaker
23-02-2014, 13:05
The axis numbers are different than the button numbers. The axis numbers refer to the analog inputs (things that can be moved or twisted to different positions) on the input device where as the button numbers refer to the digital buttons (things that can only be pressed on/off).

So, if you are using a gamepad as your controller. It will typically have two "sticks" on it that you can move up/down and left/right to many different positions. This corresponds to 4 axis values (left stick right/left axis, left stick up/down axis, right stick right/left axis and right stick up/down axis).

If you are using a non-gamepad joystick. You will have one axis for the left/right direction, another for the up/down direction and possibly others for twisting motions or throttle dials.

When you write your software, part of the challenge will be determining which axis you want to read in order to set your shooter speed. For example, axis 2 might be the up/down axis on a gamepad's left stick. However, if 2 is not the correct number, you may need to experiment and try other values (1, 2, 3, 4, or 5).

For autonomous, you would need to set specific motor powers (you would not want to read them from the joystick/gamepad).

It may also turn out that you don't need to vary the speed with a joystick while under operator control (in which case you would not need to use the joystick either).

I'm still not entirely clear on what your use cases are. From your last message, it sounded like you were more interested in being able to turn the shooter motors (Victors) on and off for the entire autonomous and operator control periods.

Here is an example of setting your shooter motors to a specific power level and leaving them set to that level during all of autonomous and all of teleop (and also turning them off at the end). This example assumes you don't need/want to vary the speed of the shooter motors using a joystick/gamepad:


public void autonomous() {
// Turn on shooters for all of autonomous period
startShooters();

// Turn off drive safety so we can use long timer delays before
// changing drive power (if you don't do this, your program
// may get interrupted and killed during autonomous)
myDrive.setSafetyEnabled(false);

// Example of driving at half power for 3 seconds (not sure if this
// will be forward or backwards on your robot)
myDrive.drive(-.5, 0.0);
Timer.delay(3.0);

// Stop everything
stopAll();
}

public void operatorControl() {
// Turns shooter motors on for all of operator control period
startShooters();

// You can enable the drive safety check here (optional) as you
// should be calling the arcadeDrive() method very frequently)
myDrive.setSafetyEnabled(true);

while(isOperatorControl() && isEnabled()) {
// Let driver control robot
myDrive.arcadeDrive(driveStick);
Timer.delay(0.01);
}

// Stop everything
stopAll();
}

private void stopAll() {
// Stop drive motors and shooter
myDrive.stopMotor();
stopShooters();
}

private void stopShooters() {
// Set output power to 0 to both shooter motors
setShooterPower(0);
}

private void startShooters() {
// Determine a reasonable power level for your shooter motors
// (you will need to experiment)
setShooterPower(0.5);
}

private void setShooterPower(double shooterPower) {
// Apply power to shooter motors
M1.set(shooterPower);
M2.set(shooterPower);

// IMPORTANT: If one or both of the motor connections end up being the
// opposite of what you expect, you may need to invert the power applied
// to one or both of the motors.

// Commented example of how to invert the power applied to both motors:
// (this would replace the set methods above)
//M1.set(-shooterPower);
//M2.set(-shooterPower);
}

miw14
23-02-2014, 13:45
For our use, in auto we would like to drive, stop driving, fire, and then stop completely.
For teleop, we would like to drive and have the ability to launch our launcher forward and reset it.

I'm getting closer to understanding what's going on, but I am still uncertain with a few things. How would we declare the launcher in the constructor? How do we control it in the autonomous period? I know with the drive we can select the power and put on a delay. But with the shooter, how would we control when it fires, if the shooter is running the entire time? Lastly, in the telop period, if the power is set at .5 at all times, would our launcher only be able to go forward or backwards? How could we reset our launcher each time?


Sorry for the plethora of questions, I just want to make sure that we have no issues. Thank you again!

SousVide
23-02-2014, 14:14
oh. hope it's not flaky joystick cable or usb port...

Looks like joystick 2 is working again! Played around with the code and the dashboard, and it looks like things are working. Thanks for the help everyone!

As for not using arcade drive for the shooter, what would you recommend?

pblankenbaker
23-02-2014, 15:10
Can you describe your shooting mechanism?

How are the two motors controlled by the Victors used (are they just spinning wheels that the ball drops into and shoots out of, or are they used to crank down a catapult, etc)?

Are there any other sensors or mechanisms required to shoot the ball (you mentioned a laucher of some type but did not describe how the launcher is controlled)?

miw14
23-02-2014, 15:40
Our launcher uses the two Victor controllers to control two CIM motors. The motors are used to operate our belt system, which can lift the launcher and also return the launcher to rest position if put in reverse. Sorry for any confusion. If you need me to clear anything else up, let me know.

pblankenbaker
23-02-2014, 17:15
That helps to know that the two Victors are used to operate a belt and that running them in one direction will lift the launcher and that running them in the other direction will cause them to lower the launcher.

However, I don't understand how you know when to stop? If you keep running the Victors to lift the launcher, how will you know when you are at the launch point? If the Victors run too long, will it damage your robot?

From what I know so far, it sounds like your only option is to run your Victors at certain power levels for a specific time period and hope for the best.

Here's an example which has a autonomous routine that drives for a bit, then raises your launcher for a period of time and then stops (I don't know what you need to do to actually fire).

The operator control has been adjusted slightly so that it uses two buttons on the joystick so the operator should be able to raise or lower the launcher depending which button they hold down (when they release both buttons it should stop). There are several comments flagged with TODO indicating that there are values that will need to be determined/adjusted.


package edu.wpi.first.wpilibj.templates;

import edu.wpi.first.wpilibj.SimpleRobot;
import edu.wpi.first.wpilibj.Joystick;
import edu.wpi.first.wpilibj.RobotDrive;
import edu.wpi.first.wpilibj.Talon;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.Victor;

/**
* * The VM is configured to automatically run this class, and to call the *
* functions corresponding to each mode, as described in the SimpleRobot *
* 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 Drive extends SimpleRobot {

private RobotDrive myDrive, Shooter;
private Joystick driveStick, driveStick2;
private Talon FrontRight, FrontLeft, BackRight, BackLeft;
private Victor M1, M2;

/**
* * This function is called once each time the robot enters autonomous
* mode.
*/
public void robotInit() {
FrontRight = new Talon(1);
BackLeft = new Talon(2);
FrontLeft = new Talon(3);
BackRight = new Talon(4);
myDrive = new RobotDrive(FrontLeft, BackLeft, FrontRight, BackRight);
myDrive.setInvertedMotor(RobotDrive.MotorType.kFro ntRight, true);
M1 = new Victor(5);
M2 = new Victor(6);
Shooter = new RobotDrive(M1, M2);
driveStick = new Joystick(1);
driveStick2 = new Joystick(2);

}

public void autonomous() {

// Turn off drive safety so we can use long timer delays before
// changing drive power (if you don't do this, your program
// may get interrupted and killed during autonomous)
myDrive.setSafetyEnabled(false);

// Example of driving at half power for 3 seconds (not sure if this
// will be forward or backwards on your robot)
myDrive.drive(-.5, 0.0);
Timer.delay(3.0);
// Stop drive motors
myDrive.stopMotor();

// Raise the launcher for one and a half seconds
// TODO: Determine time value or better yet add a switch so you
// know when launcher is in position
startRaisingLauncher();
Timer.delay(1.5);
stopMovingLauncher();

// TODO: INSERT FIRE OPERATION HERE

// Stop everything
stopAll();
}

public void operatorControl() {
// You can enable the drive safety check here (optional) as you
// should be calling the arcadeDrive() method very frequently)
myDrive.setSafetyEnabled(true);

while (isOperatorControl() && isEnabled()) {
// Let driver control robot
myDrive.arcadeDrive(driveStick);

// Check to see if operator is raising or lowering the launcher
checkLauncherControl();

Timer.delay(0.01);
}

// Stop everything
stopAll();
}

/**
* Allow operator to raise/lower launcher using two buttons (stops if neither pressed).
*/
private void checkLauncherControl() {
int RAISE_BUTTON = 1;
int LOWER_BUTTON = 2;

if (driveStick2.getRawButton(RAISE_BUTTON) == true) {
startRaisingLauncher();
} else if (driveStick2.getRawButton(LOWER_BUTTON) == true) {
startLoweringLauncher();
} else {
stopMovingLauncher();
}
}


/**
* Helper method to stop all motors on the robot.
*/
private void stopAll() {
myDrive.stopMotor();
stopMovingLauncher();
}

/**
* Set output power to 0 to both launcher motors that move the lift.
*/
private void stopMovingLauncher() {
setLiftPower(0);
}

/**
* Turn launcher motors on so launcher starts going up.
*/
private void startRaisingLauncher() {
// TODO: Determine a reasonable power level for your shooter motors
// (you will need to experiment)
setLiftPower(0.5);
}

/**
* Turn launcher motors on so launcher starts going down.
*/
private void startLoweringLauncher() {
// TODO: Determine a reasonable power level for your shooter motors
// (you will need to experiment)
setLiftPower(-0.5);
}

/**
* Set the power on the motors that raise and lower the launcher.
*
* @param power The power level in the range of [-1.0, +1.0] where
* negative values will lower the launcher and positive values will
* lift it.
*/
private void setLiftPower(double power) {
// Apply power to shooter motors
// TODO: Determine if one or both power values need to be inverted
// (see comment block below)
M1.set(power);
M2.set(power);

// IMPORTANT: If one or both of the motor connections end up being the
// opposite of what you expect, you may need to invert the power applied
// to one or both of the motors.
// Commented example of how to invert the power applied to both motors:
// (this would replace the set methods above)
//M1.set(-power);
//M2.set(-power);
}
}


The above code does not actually fire the ball (unless your ball automatically fires once the launcher has been lifted to a certain height).

Let me mention again that it is typically desirable to add limit switches so you can tell when the launcher has reached a certain point and should not be raised or lowered any more. The is especially important if moving the lift too far could damage the robot.

miw14
23-02-2014, 17:57
Thank you so much! I truly appreciate all of your help. You have been a godsend. As for the stopping mechanism, I'm not sure how that's going to work. I think our build team is coming up with ideas on it, so hopefully we'll have something figured out. I, too, am worried about potential damages. We will be sure to keep that in mind. Once again, thank you! I can not express my gratitude. You have been a mentor to a team lacking any mentors. Thank you!

pblankenbaker
23-02-2014, 20:35
No worries - I'm glad my input was useful.

I'm really impressed that a new team without any mentors could produce a robot. I am a mentor who joined an established team and I was pretty lost for the first season. Your team should be proud to have gotten through a build season on its own.

Good luck and have fun at your regionals.

pblankenbaker
24-02-2014, 04:47
Just a heads up, in the autonomous example, I had an error in the code that was suppose to drive for three seconds. The original code would start driving, wait for 3 seconds, but fail to stop driving afterwards. This would have resulted in your robot to continue driving for the next 1.5 seconds as it raised its launcher (until stopAll() was reached).

I've corrected the example in the previous post. Here is the fragment of code that was corrected with the addition of myDrive.stopMotor() (it will stop driving before raising the launcher):


// Example of driving at half power for 3 seconds (not sure if this
// will be forward or backwards on your robot)
myDrive.drive(-.5, 0.0);
Timer.delay(3.0);
// Stop drive motors
myDrive.stopMotor();