Hello, world! I'm new to android studio and text based programming in general. I've used the K9Teleop as a template for our robot's code, and whenever I attempt to run it using the Driver Station and Robot Controller, I get the following message:
Error: User code threw an uncaught exception: NullPointerException
I'm assuming this is due to an error in my code not caught by android's debugging system. I looked through it for an hour or so and can't find any errors. Here is what I've written:
Code:
package com.qualcomm.ftcrobotcontroller.opmodes;
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.Servo;
import com.qualcomm.robotcore.util.Range;
/**
* Created by Parker on 11/19/2015.
*/
public class TeleOp1 extends OpMode {
/*
* Note: the configuration of the servos is such that
* as the scoopGate servo approaches 0, the scoopGate position moves up (away from the floor).
* Also, as the mexicanHand servo approaches 0, the mexicanHand opens up (drops the game element).
*/
// TETRIX VALUES.
final static double scoopGate_MIN_RANGE = 0;
final static double scoopGate_MAX_RANGE = 1;
final static double mexicanHand_MIN_RANGE = 0;
final static double mexicanHand_MAX_RANGE = 1;
// position of the scoopGate servo.
double scoopGatePosition;
// amount to change the scoopGate servo position.
double scoopGateDelta = 1;
// position of the mexicanHand servo
double mexicanHandPosition;
// amount to change the mexicanHand servo position by
double mexicanHandDelta = 1;
DcMotor driveRight;
DcMotor driveLeft;
DcMotor scoopArm;
DcMotor scoopIntake;
Servo scoopGate;
DcMotor liftScissor;
DcMotor liftWinch;
Servo mexicanHand;
/**
* Constructor
*/
public TeleOp1() {
}
/*
* Code to run when the op mode is first enabled goes here
*
* @see com.qualcomm.robotcore.eventloop.opmode.OpMode#start()
*/
@Override
public void init() {
/*
* Use the hardwareMap to get the dc motors and servos by name. Note
* that the names of the devices must match the names used when you
* configured your robot and created the configuration file.
*/
driveRight = hardwareMap.dcMotor.get("motor_2");
driveLeft = hardwareMap.dcMotor.get("motor_1");
driveLeft.setDirection(DcMotor.Direction.REVERSE);
scoopArm = hardwareMap.dcMotor.get("motor_3");
scoopIntake = hardwareMap.dcMotor.get("motor_4");
scoopGate = hardwareMap.servo.get("servo_1");
liftWinch = hardwareMap.dcMotor.get("motor_6");
mexicanHand = hardwareMap.servo.get("servo_2");
// assign the starting position of the scoopGate and mexicanHand
scoopGatePosition = 0;
mexicanHandPosition = 0;
}
/*
* This method will be called repeatedly in a loop
*
* @see com.qualcomm.robotcore.eventloop.opmode.OpMode#run()
*/
@Override
public void loop() {
/*
* Gamepad 1
*
* Gamepad 1 controls the motors via the left and right sticks
*/
// tank drive
// note that if y equal -1 then joystick is pushed all of the way forward.
float left = -gamepad1.left_stick_y;
float right = -gamepad1.right_stick_y;
// clip the right/left values so that the values never exceed +/- 1
right = Range.clip(right, -1, 1);
left = Range.clip(left, -1, 1);
// scale the joystick value to make it easier to control
// the robot more precisely at slower speeds.
right = (float)scaleInput(right);
left = (float)scaleInput(left);
// write the values to the motors
driveRight.setPower(right);
driveLeft.setPower(left);
/*
* Gamepad 2
*
* Gamepad 2 controls the motors via the left stick, and it controls the
* scoopGate/mexicanHand via the dpad_down, dpad_up/a, b buttons
*/
// define leftBumper and rightBumper as boolean variables on gamepad2
boolean leftBumper = gamepad2.left_bumper;
boolean rightBumper = gamepad2.right_bumper;
// update the direction of the liftWinch
if (leftBumper) {
// if the right_bumper on gamepad 2 is pushed, extend the liftWinch
liftWinch.setPower(1);
} else {
liftWinch.setPower (0);
}
if (rightBumper) {
// if the right_bumper on gamepad 2 is pushed, retract the liftWinch
liftWinch.setPower(-1);
} else {
liftWinch.setPower(0);
}
// define leftTrigger and rightTrigger as float variables on gamepad2
float leftTrigger = -gamepad2.left_trigger;
float rightTrigger = gamepad2.right_trigger;
// clip the trigger values so that the values never exceed +/- 1
leftTrigger = Range.clip(leftTrigger, -1, 1);
rightTrigger = Range.clip(rightTrigger, -1, 1);
// scale the trigger values to make it easier to control
// the scissor lift
leftTrigger = (float)scaleInput(leftTrigger);
rightTrigger = (float)scaleInput(rightTrigger);
// write the values to the motors
liftScissor.setPower(leftTrigger);
liftScissor.setPower(rightTrigger);
// update the direction of the scoopIntake
if (gamepad2.a) {
// if the A button is pushed on gamepad2, spin the scoopIntake inwards
scoopIntake.setPower(1);
} else {
scoopIntake.setPower(0);
}
if (gamepad2.b) {
// if the B button is pushed on gamepad2, spin the scoopIntake outwards
scoopIntake.setPower(-1);
} else {
scoopIntake.setPower(0);
}
// update the position of the scoopArm
if (gamepad2.dpad_left) {
// if the dpad_left button is pushed on gamepad 2, move the scoopArm in
scoopArm.setPower(-0.5);
} else {
scoopArm.setPower(0);
}
if (gamepad2.dpad_right) {
// if the dpad_right button is pushed on gamepad 2, move the scoopArm out
scoopArm.setPower(0.5);
} else {
scoopArm.setPower(0);
}
// update the position of the scoopGate.
if (gamepad2.dpad_up) {
// if the dpad_up button is pushed on gamepad2, increment the position of
// the scoopGate servo.
scoopGatePosition += scoopGateDelta;
}
if (gamepad2.dpad_down) {
// if the dpad_down button is pushed on gamepad2, decrease the position of
// the scoopGate servo.
scoopGatePosition -= scoopGateDelta;
}
// update the position of the mexicanHand
if (gamepad2.y) {
// if the Y button is pushed on gamepad2, increment the position of
// the mexicanHandPosition
mexicanHandPosition += mexicanHandDelta;
}
if (gamepad2.x) {
// if the X button is pushed on gamepad2, decrease the position of
// the mexicanHandPosition
mexicanHandPosition -= mexicanHandDelta;
}
// clip the position values so that they never exceed their allowed range.
scoopGatePosition = Range.clip(scoopGatePosition, scoopGate_MIN_RANGE, scoopGate_MAX_RANGE);
mexicanHandPosition = Range.clip(mexicanHandPosition, mexicanHand_MIN_RANGE, mexicanHand_MAX_RANGE);
// write position values to the scoopGate and mexicanHand servo
scoopGate.setPosition(scoopGatePosition);
mexicanHand.setPosition(mexicanHandPosition);
/*
* Send telemetry data back to driver station. Note that if we are using
* a legacy NXT-compatible motor controller, then the getPower() method
* will return a null value. The legacy NXT-compatible motor controllers
* are currently write only.
*/
telemetry.addData("Text", "*** Robot Data***");
telemetry.addData("scoopGate", "scoopGate: " + String.format("%.2f", scoopGatePosition));
telemetry.addData("mexicanHand", "mexicanHand: " + String.format("%.2f", mexicanHandPosition));
telemetry.addData("left tgt pwr", "left pwr: " + String.format("%.2f", left));
telemetry.addData("right tgt pwr", "right pwr: " + String.format("%.2f", right));
}
/*
* Code to run when the op mode is first disabled goes here
*
* @see com.qualcomm.robotcore.eventloop.opmode.OpMode#stop()
*/
@Override
public void stop() {
}
/*
* This method scales the joystick input so for low joystick values, the
* scaled value is less than linear. This is to make it easier to drive
* the robot more precisely at slower speeds.
*/
double scaleInput(double dVal) {
double[] scaleArray = { 0.0, 0.05, 0.09, 0.10, 0.12, 0.15, 0.18, 0.24,
0.30, 0.36, 0.43, 0.50, 0.60, 0.72, 0.85, 1.00, 1.00 };
// get the corresponding index for the scaleInput array.
int index = (int) (dVal * 16.0);
// index should be positive.
if (index < 0) {
index = -index;
}
// index cannot exceed size of array minus 1.
if (index > 16) {
index = 16;
}
// get value from the array.
double dScale = 0.0;
if (dVal < 0) {
dScale = -scaleArray[index];
} else {
dScale = scaleArray[index];
}
// return scaled value.
return dScale;
}
}
Any help provided would be greatly appreciated. Thank you in advance for reading.