This year, I have to code the programs for my robotics team in Java instead of RobotC, so it can work with Androids. For the autonomous code, I want to make a basic template where any member of the team can create different programs through a list. I have tried to look up how to work with lists, but I haven't found anything useful. This is the code I would do in TI-BASIC
Code:
:{1,10,2,23,3,17,4,7,3→∟AUTO //numbers inside list is just an example of the editable part of the code
:For(X,1,dim(∟AUTO)/2
:If ∟AUTO(2X-1)=1
:Then
://Code for robot moving straight
:End
:If ∟AUTO(2X-1)=2
:Then
://Code for robot turning left
:End
://Other If statements for right, back, and stop
://Wait ∟AUTO(2X) intervals of time
:End
How would this code translate to Java? I mainly need to know how to set the series of numbers to a list and how to find how long a list is.
This is an interesting solution to the problem. Although you could do it this way, I would strongly recommend using methods to perform each of the actions - like you would do with a functions in RobotC.

If you still want to do it this way, Java uses arrays just like RobotC. You can begin by defining auto with an int array literal:

Code:
int[] auto = {1,10,2,23,3,17,4,7,3};

You can then use a for each loop to loop through each element of the array, and a switch statement to perform the desired actions:

Code:
for(int action : auto) {
    switch(action) {
        case 1:
            //perform action 1
            break;
        case 2:
            //perform action 2
            break;
        case n:
            //perform action n
            break; //this last break is technically not necessary
    }
}


If you have any questions, I know both Java and RobotC pretty well.
jonbush wrote:
This is an interesting solution to the problem. Although you could do it this way, I would strongly recommend using methods to perform each of the actions - like you would do with a functions in RobotC.
I have never done anything more complicated than If statements in RobotC, so what do you mean by methods?
A method is, in essence, a function contained within a class definition. e.g.


Code:

public class Robot {
public Robot() {
// this is a special kind of method called a constructor. It constructs variables of type Robot
}

public void hi() {
// This is a method that ostensibly you would fill in code to say hi
}
}


Also, depending on your use case, you may want an actual List, rather than an array. In that case you should look at the Javadocs for the java.util package, which has several implementations of List.
Re: jonbush's post: Just to make sure that you learn optimal form, magic numbers are to be avoided as much as possible. You'd want to define some constants like COMMAND_LEFT, COMMAND_RIGHT, COMMAND_FWD, etc, or even better, use an enumeration:
Code:
public enum Commands {
    ESTOP = 0,
    LEFT,
    RIGHT,
    FWD,
    REV,
    SENSE,
    STOP
}

public class Robot {
[... other code ...]
public void runSequence(int[] auto) {
[...]
for(int action : auto) {
    performAction(action);
}
[...]
}

public void performAction(int action) {
    switch(action) {
        case Command.ESTOP:
            //perform an emergency stop
            break;
        case Command.LEFT:
            //perform action 1
            break;
        case command.RIGHT:
            //perform action 2
            break;
        case command.WHATEVER:
            //perform action n
            break;
        default:  // Handle any undefined command. Display a warning?
            break; //this last break is technically not necessary
    }
}
KermMartian wrote:
Re: jonbush's post: Just to make sure that you learn optimal form, magic numbers are to be avoided as much as possible. You'd want to define some constants like COMMAND_LEFT, COMMAND_RIGHT, COMMAND_FWD, etc, or even better, use an enumeration:


I believe the for(int action : auto) in Kerm's post is misplaced. You would need to have another method that iterates through the list of commands and calls performAction() for each. If you are using any sensors, it may also be useful to create other classes to handle sensor input.
Thanks for catching that; I corrected my post. I do think a vector/array type would probably better for this than a static int[] array, as elfprince mentioned. Also Runer112 suggested on IRC that making the enumeration part of the Robot class and attaching a method to each enumeration item would be a more Java-y, OOPy solution, and I agree, but that approach might be slightly out of scope for a Javascript beginner.
KermMartian wrote:
Thanks for catching that; I corrected my post. I do think a vector/array type would probably better for this than a static int[] array, as elfprince mentioned. Also Runer112 suggested on IRC that making the enumeration part of the Robot class and attaching a method to each enumeration item would be a more Java-y, OOPy solution, and I agree, but that approach might be slightly out of scope for a Javascript beginner.


Yes, that would be a better solution. Overall, if you are using methods, none of this is really necessary because you could just write out the method names in the order you want to call them. This would also allow for easily passing different parameters to methods. In many ways, the current solution is just making things more complicated than they need to be.
joblo wrote:
Yes, that would be a better solution. Overall, if you are using methods, none of this is really necessary because you could just write out the method names in the order you want to call them. This would also allow for easily passing different parameters to methods. In many ways, the current solution is just making things more complicated than they need to be.


I would tend to agree with this. Instead of defining an enum, an array, and iterating through that to call methods, you could call the methods directly:


Code:
public class Autonomous implements Runnable {

    /**
     * Move forward for a specified distance
     * @param dist Distance in centimeters
     */
    private void moveForward(double dist){
        //code to move forward for dist
    }

    private void moveBackward(double dist){
        //code to move backward for dist
    }

    /**
     * Perform some kind of action
     * @param str What you want the robot to do
     * @returns true if the action was completed successfully
     */
    private boolean doSomething(String str){
        //code do do some action
    }

    /**
     * Perform these actions when the class is run as a thread
     */
    public void run() {
        moveForward(128);
        doSomething("fun");
        moveBackward(64);
    }

}
FrozenFire49 wrote:
This year, I have to code the programs for my robotics team in Java instead of RobotC, so it can work with Androids. For the autonomous code, I want to make a basic template where any member of the team can create different programs through a list. I have tried to look up how to work with lists, but I haven't found anything useful. This is the code I would do in TI-BASIC
Code:
:{1,10,2,23,3,17,4,7,3→∟AUTO //numbers inside list is just an example of the editable part of the code
:For(X,1,dim(∟AUTO)/2
:If ∟AUTO(2X-1)=1
:Then
://Code for robot moving straight
:End
:If ∟AUTO(2X-1)=2
:Then
://Code for robot turning left
:End
://Other If statements for right, back, and stop
://Wait ∟AUTO(2X) intervals of time
:End
How would this code translate to Java? I mainly need to know how to set the series of numbers to a list and how to find how long a list is.


Is this FRC or FTC? FRC libraries have an easier way to do things with the Command Based template, which is much more powerful in the long run, anyways.

EDIT:
@FrozenFire also RobotBuilder and such.
@Everyone Else: your code is great for one of the two options for FRC programming, the event-based one, but as I said, the command-based option is the better choice, and you have to do things a bit differently.
Thanks for all of the responses.
pimathbrainiac wrote:
Is this FRC or FTC? FRC libraries have an easier way to do things with the Command Based template, which is much more powerful in the long run, anyways.

I'm doing this for FTC, so I don't think we have those libraries.
jonbush wrote:
joblo wrote:
Yes, that would be a better solution. Overall, if you are using methods, none of this is really necessary because you could just write out the method names in the order you want to call them. This would also allow for easily passing different parameters to methods. In many ways, the current solution is just making things more complicated than they need to be.


I would tend to agree with this. Instead of defining an enum, an array, and iterating through that to call methods, you could call the methods directly

I guess I could try to set up separate OP mode classes for each motion of the robot (If I understand you guys correctly), but then I think it would be easier just to copy and paste the motorPower command, since that's the only thing the classes are going to consist of.

I don't really mind how unoptimized it is, I just want it to work and be easy to understand and create, and be easier to modify and have many separate programs than just copying what each motor does and how long to wait over and over.
FrozenFire49 wrote:

I guess I could try to set up separate OP mode classes for each motion of the robot (If I understand you guys correctly), but then I think it would be easier just to copy and paste the motorPower command, since that's the only thing the classes are going to consist of.

I don't really mind how unoptimized it is, I just want it to work and be easy to understand and create, and be easier to modify and have many separate programs than just copying what each motor does and how long to wait over and over.


I don't think you really need to create a separate class for each action. You can probably create methods using the motorPower command and then call those. The methods could be useful for more complicated actions like turning. If you are setting the power for multiple motors it can also be very redundant and annoying having to put motorPower four times every time you want to change the speed. If you create methods for the different kinds of movements, you can more easily create functional autonomous programs.

This was done with RobotC, but it still used many functions to handle the all of the different sensor inputs and motor commands:



EDIT: I haven't done this, but another interesting approach to autonomous development would be to log all of the inputs from a human controlled run, and then read the file back during the autonomous mode to simulate the same inputs. If you are using sensors, this obviously wouldn't be useful for everything, but it might be cool to try.
Our robot will only be using 2 motors to drive, but I see what you're saying. I won't be able to test anything though until Wednesday at our next meeting. Until then I'll try to learn some more Java so I can see the purpose of all of the example codes.

Doing a human controlled run does sound interesting, but I think it's currently above my level

Also, do you know why our motors a have an all or nothing response? Anything between 0 and 1 the motors go at full power one way, and between 0 and -1 they go the other way at full power. We have the variable that the motor power is being set to being displayed on the phone, so we know it is being set at the decimals between -1 and 1 depending on the joystick position. Additionally, if we quickly switch the joystick from up to down or vise versa, the motor can continue to go in the same direction, and a random amount of time later (usually between 1 and 3 seconds) the motor finally updates and goes in the right direction. Are these coding issues or motor issues?
FrozenFire49 wrote:
Also, do you know why our motors a have an all or nothing response? Anything between 0 and 1 the motors go at full power one way, and between 0 and -1 they go the other way at full power. We have the variable that the motor power is being set to being displayed on the phone, so we know it is being set at the decimals between -1 and 1 depending on the joystick position. Additionally, if we quickly switch the joystick from up to down or vise versa, the motor can continue to go in the same direction, and a random amount of time later (usually between 1 and 3 seconds) the motor finally updates and goes in the right direction. Are these coding issues or motor issues?


This sounds like a coding issue. Perhaps you could put your code into Pastebin and post a link so we could look over it. Smile Make sure you are keeping track of this mentoring in your engineering notebook.
Unfortunately I won't be able to have access to the actual code that we have until Wednesday, but here is what we have the code doing (Leaving technical stuff out):
Code:
left_joystick_Y → left
right_joystick_Y → right

left → Motor1
right → Motor2

Display left (on phone)
Display right
FrozenFire49 wrote:

Code:
right_joystick_Y → right

left → Motor1
right → Motor2

Display left (on phone)
Display right


I found this rather primitive implementation of a Mecanum drive algorithm that you may want to take a look at: http://ftckey.com/programming/tele-op/. Although it isn't the same drive type, the general principles behind reading the joystick and setting the power should be the same.

If this doesn't fix your problem, it may be related to having a PID controller active with no encoder input. If you have PID control enabled for your motors and do not have encoders, the controller will ramp the power to 100% because it thinks that the target speed has not been reached.
This is the code that we are using for teleop. We got the code from some other source, so I made the parts that I think are unneeded into comments.

Code:
/* Copyright (c) 2014 Qualcomm Technologies Inc

All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted (subject to the limitations in the disclaimer below) provided that
the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

Neither the name of Qualcomm Technologies Inc nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS
LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

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;

public class TankDriveOp extends OpMode {
   double servoPosition = 0.5;
   DcMotor motorRight;
   DcMotor motorLeft;
   Servo servo;
   public TankDriveOp() {

   }
   @Override
   public void init() {

      motorRight = hardwareMap.dcMotor.get("motor1");
      motorLeft = hardwareMap.dcMotor.get("motor2");
      motorLeft.setDirection(DcMotor.Direction.REVERSE);
      servo = hardwareMap.servo.get("servo1");
   }
   @Override
   public void loop() {

      double left = -gamepad1.left_stick_y;
      double right = -gamepad1.right_stick_y;
      if (gamepad1.left_bumper)  {
         servoPosition = servoPosition - 0.01;
      }
      if (gamepad1.right_bumper) {
         servoPosition = servoPosition + 0.01;
      }
      servoPosition = Range.clip(servoPosition, 0, 1);
      // 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);
      //right = right/10;
      //left = left/10;
      
      // write the values to the motors
      motorLeft.setPower(left);
      motorRight.setPower(right);
      servo.setPosition(servoPosition);

      /*
       * 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("left tgt pwr",  "left  pwr: " + String.format("%.2f", left));
        telemetry.addData("right tgt pwr", "right pwr: " + String.format("%.2f", right));
      telemetry.addData("servo", "servo: " + String.format("%.2f", servoPosition));
   }
   @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);
      if (index < 0) {
         index = -index;
      } else if (index > 16) {
         index = 16;
      }
      
      double dScale = 0.0;
      if (dVal < 0) {
         dScale = -scaleArray[index];
      } else {
         dScale = scaleArray[index];
      }
      
      return dScale;

   }
*/
}
FrozenFire49 wrote:
This is the code that we are using for teleop. We got the code from some other source, so I made the parts that I think are unneeded into comments.

Code:

   /*
    * 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);
      if (index < 0) {
         index = -index;
      } else if (index > 16) {
         index = 16;
      }
      
      double dScale = 0.0;
      if (dVal < 0) {
         dScale = -scaleArray[index];
      } else {
         dScale = scaleArray[index];
      }
      
      return dScale;

   }
*/
}


This method can be rewritten to be a bit more efficient, imo. Also instead of an indexed array, I suggest you use a quadratic function. If you still want the index, you should instantiate the variable outside the method, so you only instantiate once instead of every loop.

Here's how I would write the code:

Code:

double scaleInput(double dVal)
{
    double dScale = Math.pow(dVal, 2);
    if(dScale < 0)
    {
        dScale = -1.0 * dScale;
    }
    return dScale;
}


If you want the index you have, here's how I'd rewrite it for efficiency:

Code:

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 };

double scaleInput(double dVal)
{
    int index = Math.abs((int) (dVal * 16.0));
   
    double dScale;
    if (dVal < 0)
    {
        dScale = -1.0 * scaleArray[index];
    }
    else
    {
        dScale = scaleArray[index];
    }
   
    return dScale;
}
That was in the original code that we are using and making modifications on. I didn't really see a point in that part of the code either, so I made it a comment in case we did end up needing it later. I think a function would be better too, but I'm just leaving it as linear for now until we can get the motors working not all-or-nothing. This is the code without the comments:
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;

public class TankDriveOp extends OpMode {
   double servoPosition = 0.5;
   DcMotor motorRight;
   DcMotor motorLeft;
   Servo servo;
   public TankDriveOp() {

   }
   @Override
   public void init() {

      motorRight = hardwareMap.dcMotor.get("motor1");
      motorLeft = hardwareMap.dcMotor.get("motor2");
      motorLeft.setDirection(DcMotor.Direction.REVERSE);
      servo = hardwareMap.servo.get("servo1");
   }
   @Override
   public void loop() {

      double left = -gamepad1.left_stick_y;
      double right = -gamepad1.right_stick_y;
      if (gamepad1.left_bumper)  {
         servoPosition = servoPosition - 0.01;
      }
      if (gamepad1.right_bumper) {
         servoPosition = servoPosition + 0.01;
      }
      servoPosition = Range.clip(servoPosition, 0, 1);
       
      motorLeft.setPower(left);
      motorRight.setPower(right);
      servo.setPosition(servoPosition);

        telemetry.addData("Text", "*** Robot Data***");
        telemetry.addData("left tgt pwr",  "left  pwr: " + String.format("%.2f", left));
        telemetry.addData("right tgt pwr", "right pwr: " + String.format("%.2f", right));
      telemetry.addData("servo", "servo: " + String.format("%.2f", servoPosition));
   }
   @Override
   public void stop() {

   }
}
Okay, in FRC, you control motors via motor controllers. Are you doing that? If so, there's the DcMotorController class that you should look in to (just read stuff on the FTC API. It's not too different).

EDIT: the DcMotorController's setMotorPowerFloat(int motor) method could be of use.

EDIT 2: or DcMotor's setPowerFloat() method
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement