; FRC Java Beta Testing - DOC
Documents
Resources
Learning Center
Upload
Plans & pricing Sign in
Sign Out
Your Federal Quarterly Tax Payments are due April 15th Get Help Now >>

FRC Java Beta Testing - DOC

VIEWS: 60 PAGES: 21

  • pg 1
									                      FRC Java Beta Testing
         Overview for Teams Considering Java Development
                      Team 1279 ColdFusion


1 The NetBeans Development Environment
      The NetBeans IDE is a great full featured development environment for Java. It is widely used and
free, so if you have any interest in Java definitely take a few minutes to get it and take a look. The
NetBeans site is http://www.netbeans.org, there are a wide variety of resources beyond just the downloads
we need. Same for the official Sun Java site http://java.sun.com.

1.1 Getting NetBeans & Java
        From the NetBeans and Java pages there are links to downloads, you want to make sure that you
download a package with Java ME (micro edition), at the moment it is bundled with the SE package and a
few other things. SE (standard edition) will give you things to play with while waiting for FIRST to release
the robot plug-ins for ME. You can go from the top-level page to Java SE (on the right hand side) or
directly to:

       http://java.sun.com/javase/downloads/index.jsp

       The exact version of the JDK and NetBeans changes regularly, download the 6.7.1 NetBeans and
JDK 6 Update 17 at the moment.
Select your OS and download speed on the next page, and press continue




You are offered a chance to login, but you can press 'skip this step'.
Depending on the security settings of your browser you may need to acknowledge a security warning to
allow downloads.




The package is 136MB, download took 5m 18s over a Comcast cable connection.




1.2 Installing NetBeans
We have installed NetBeans and the JDK on computers running Windows XP, Vista, and Ubuntu Linux.
Note that as of this time:
     Windows 7 is not supported
     You will need at least one Windows machine to run the LabView imaging tool.
Install time was roughly the same on each platform, and much quicker than installing with LabView from
DVD.
When you install you may get a security warning about the digital signature




You have to continue.




Accept the license agreement.
Accept or change the install directories




Register and agree to provide usage data if desired.
1.3 Configuring for FRC
       Please note that we are required by our NDA with FIRST not to publish the Programming Guide or
other beta documents. Hopefully FIRST will be making them available in early December again this year, I
strongly recommend you work with NetBeans while waiting and add the FIRST plugins as soon as they
become available.

When you first open NetBeans it will also ask you to register.

To configure for FRC use go to Tools->Plugins and choose the Settings tab. Use the button 'Add' to add the
path to the current set of plugins. This path has changed during Beta so that people can go back and forth
between versions.




Important:
    'Check for updates automatically' only checks, you must install them yourself!
    Development machines must be connected to the internet at least when you want to update.
After entering this information select the 'Available Plugins' tab. You will see the available plugins, you
want all the FRC ones. Then click 'Install'. You will need to accept the license agreement, ignore the fact
they aren't signed, and then restart the IDE.
Helpful Hint: if you deselect everything but FRC it will show only those plugins and you don't have to
scroll looking for them.

Then go to Tools->Options and select the Miscellaneous category and FRC Options tab to enter your team
number.




Helpful hint: note where the WPILibJ is stored, it is not with the rest of your source code.
1.4 Updates
       So far new cRIO images and Driver Station SW have required updated plugins, but there have been
plugin updates that don't need new images. I suggest that someone check daily. (last year there was a
mandatory C++ update the week before our first regional and I was doing it at the last minute because I
hadn't paid attention)
     To do this just check the 'Updates' tab periodically. You will also need to keep an eye on the FIRST
and WPI websites, if they change the URL of the plugins you will need to change it in settings, the IDE
won't know about it. So far changes have only been replacements, not additions to the current plugins.

2 Project Creation and Download
2.1 Creation from a Sample
       After installing the plugins there will be several sample projects available. Select File->New Project
and you will see several folders. The Robot projects are under FRC Java, and there are additional samples
under Samples/FRC Java, notably the vision code sample. We are going to derive a project from the
SimpleRobotTemplate project.




Click next and name your project and first class.
Helpful hint: note the directories where things are being stored to make it easy to find files to e-mail, back-
up, etc..
Open the project source tree in the project pane and double click on the .java file to open it in the editing
pane.
2.2 Editing
       The editor options, under Tools->Options, are many. Some very helpful, some a bit annoying, but
most people will disagree which is which. In general it has syntax highlighting, autocompletion, the ability
to jump to problems, and generally good suggestions when you run into trouble.
       I did run into one serious problem with copying over large blocks of C code. If the IDE freezes you
need to open a file browser and copy your source files elsewhere before killing it. It did zero out a file on
me in the aforementioned situation.

2.3 Adding Classes
       In Java classes (except internal classes within other classes) get their own files, so adding a class is
done through the project pane. Right click on the project and select New->Java class. Name your class, and
you will probably want it to be part of the same package.




In working with other developers I found it easiest to create empty classes and copy their files into my
workspace.

2.4 Downloading to the cRIO
      If you are connected to the robot you need only 'Run' or 'Debug' to transfer the code. What you
download will start next power cycle. Many teams using wireless reported a variety of problems. We
always used a wired connection and had no serious issues.

2.5 Looking at the WPILibJ
       The WPILibJ source is very useful when trying to figure out just what was intended in particular
classes. Be VERY careful if you modify anything and always make backups. Also, note any changes that
you really like, they will disappear after updates, and if the bug is still open you will need to recreate your
fix.

To get to the library go to File->Open Project
You can then browse the source code for any class of interest. No matter how good the documentation there
is no substitute for seeing the source code when questions or problems arise.

2.5.1 Generating Javadocs
         Even if you have no intention of ever touching the library code the Javadocs are an invaluable
resource. You can generate up-to-date documentation after each update by right clicking on the project and
selecting 'Generate Javadoc'. It creates a searchable html reference that is convenient beyond words. Make
a bookmark to the page,` you will go back often.
2.5.2 Changing Code
    In the course of testing there were two items I felt should be different in the WPI library that have not
been addressed as of the 11/8/09 update:

        The Timer class has a microsecond and millisecond method, but only the microsecond is public.
        The DriverStation class has a getStickAxis method that returns 127/128 instead of 1.0 at the
         positive extreme.

    Neither is earth-shaking, but both are easily changed and so I did. Only to find that you cannot then
recompile the WPILibJ completely. The changed files recompile fine but the same half dozen other classes
consistently fail a manual recompile. Fortunately the NetBeans IDE tries to compile all projects at start up
and that compile always succeeds. This was supposed to be fixed but is still broken. So don't panic if
suddenly don't compile after trying a manual recompile of the library.

3 Porting from C/C++
      First off, don't be nervous, there is nothing that Java does that you couldn't code in C. If you create a
structure that contains function pointers to the functions that are used to manipulate the structure members,
and are rigorous about using only those, you have 90% of what Java tries to do for you.
Java gives you 'free' what good programmers usually do for themselves anyway, careful range checking,
consistent access methods to data, safe use of pointers and memory.

3.1 cRIO Image
       You will not be able to use Java on your until FIRST makes the official cRIO image and loader
available. One it is available, if you find you need to go back to last year's code you need to go back into
the LabView 8.5 folders to find the original image and loader. If you have a critical need for a working
robot you probably want to make sure you have a copy of the images, loader, and source code from last
year archived.
To revert to the old image and code, go to the old LabView tool in:

          \Program Files\National Instruments\LabView 8.5\project\CRIO Tool


run it, it should look like this:
Note there is no Java entry, so you know you are in the right place. Now download the LabView or C++
image as appropriate. Full instructions are in last year's documents, Control System section 5.1.
Open last year's LabView or WindRiver project and download it as appropriate.

3.2 Naming Conventions
        Java uses uppercase initial characters for class names and lower case for methods. This is slightly
annoying in that almost every C++ function is available as a Java method, and differs by a single character
in the name.

3.3 Replacing #define
       Java doesn't use preprocessor statements like #define, but that is easily worked around. Within a
class you can use a 'final' variable, e.g.:

         public static final int BALL_FIRE_STICK = 1;


         This isn't as efficient as preprocessor substitution, but works the same from a coding standpoint: it
can be changed in one spot, it can't be changed at runtime, and it replaces a number with meaningful text.
The problem is that it is only valid within the class where it is defined or derived classes. In the case of
slots and channels it would be nice to have a single set of definitions across classes.
3.3.1 Your Own
         Our solution to a consistent set of defines for things we want to be 'globally' consistent was to
create an interface and have all of our classes implement it. See section 3.4.3 for an example.

3.3.2 WPILibJ's
The WPILibJ uses constants in many areas for instance:

       ballPickup.setDirection(Relay.Direction.kBoth);

This can be aliased as

         public static final Relay.Direction R_BOTH = Relay.Direction.kBoth;

and used thus
         ballPickup.setDirection(R_BOTH);

I am not sure this is actually an advantage, as it hides the real type and its origin, but it is an option that
reduces typing and adds to readability.

3.4 Uses of Java's Interface Type
3.4.1 WPILibJ Interfaces
         WPILibJ interfaces can be identified in the javadocs listing, they are italicized. The interfaces
most likely to be of interest to teams are PIDOutput/Source and SpeedController.

3.4.1.1 CounterBase
         Implemented by Counter, Encoder, and Geartooth. All common sensors to use this are
implemented, but teams may find it useful if they use a custom sensor to count things like the number of
balls picked up.

3.4.1.2 DMAChannelDescriptors
           Used by many lower level functions, it is unlikely that teams will need to implement this interface,
it is included for the sake of completeness.

3.4.1.3 ExpectedFPGASignature
         Used by many lower level functions, it is unlikely that teams will need to implement this interface.
It might possibly come in handy for teams with multiple cRIOs of different vintages that desire a single
code base for all of them. It is included for the sake of completeness.

3.4.1.4 NiRioConstants
         Used by many lower level functions, it is unlikely that most teams will need to implement this
interface, but it may be useful in debugging system level problems. It is mostly included for the sake of
completeness.

3.4.1.5 PIDOutput
         Implemented by the Victor and Jaguar classes currently. This will be useful in PID programming.

3.4.1.6 PIDSource
         Implemented by the Accelerometer, AnalogChannel, Gyro, and Ultrasonic classes currently. This
will be useful in PID programming.
3.4.1.7 SortedVectorComparator
         Implemented by SortedVector. A useful utility class and interface for sorting arrays of objects.

3.4.1.8 SpeedController
        This is actually a sub interface of PIDOutput. It is implemented by the Jaguar and Victor classes.
Right now the Victors and Jaguars are identical, but that is almost certainly going to change; the Jaguars
have many more capabilities. See the Runtime Binding section for an example of how this could come in
handy.

3.4.2 For Runtime Binding
          It is often necessary to change or adapt to some situation without re-downloading code to the
robot. For instance, during beta testing we were also testing the new Black Jaguars. We were nervous,
having blown a regular Jaguar up last year, so we wanted to be able to switch from Jaguar to Victor by
flipping setting a rotary switch. In C/C++ you would typically use void pointers and cast them as necessary,
e.g.:

         void *Controller1 = NULL;
         Victor VictorController;
         Jaguar JagController;
         ...
         if (switch1 == VICTOR_PRESENT) Controller1 = &VictorController;
         else Controller1 = &JaguarController;

In Java you can do this:

         //assign actual controllers to interface objects
         if (red_blueSW.getVoltage() > 2.5){
             //autonomous 3-5 for Victors
             leftWheel     = new Victor(1);
             rightWheel    = new Victor(3);
         } else {
             //autonomous 0-2 for Jaguars
             leftWheel     = new Jaguar(1);
             rightWheel    = new Jaguar(3);
         }

Now there are some limitations, in the SpeedController interface currently only get() and set() methods are
supported. But it does allow you to assign specific types late and pass them from class to class.



3.4.3 For Readability
      Implementing an interface means you don't need to qualify the methods and variables, which can
improve readability (possibly at the expense of clarity). For example we created a RobotConstants interface
and implemented all of our classes with it, so code can look like this:

       /**
        *
        * @author emily osmond
        */
       public interface RobotConstants {
       ...
         public static final int DSC_LEFT_SLOT = 4;
         public static final int DSC_RIGHT_SLOT = 6;

         public   static   final   int   BALL_PICKUP_CHANNEL = 1;
         public   static   final   int   BOTTOM_SHOOTER_CHANNEL = 3;
         public   static   final   int   BALL_ELEVATOR_CHANNEL = 6;
         public   static   final   int   TOP_SHOOTER_CHANNEL = 5;
         public static final int BALL_PICKUP_MOTOR = 1;
         public static final int BOTTOM_SHOOTER_MOTOR = 2;
       ...
       }
       /**
        *
        * @author gerard osmond
        */
       public class BallHandler implements RobotConstants {
       ...
         private void initBallMechanism() {
                ballPickup = new Relay(DSC_LEFT_SLOT, BALL_PICKUP_CHANNEL);
                bottomShooter = new Relay(DSC_LEFT_SLOT, BOTTOM_SHOOTER_CHANNEL);
                ballElevator = new Victor(DSC_LEFT_SLOT, BALL_ELEVATOR_CHANNEL);
                topShooter = new Victor(DSC_LEFT_SLOT, TOP_SHOOTER_CHANNEL);
                ballPickup.setDirection(Relay.Direction.kBoth);
                bottomShooter.setDirection(Relay.Direction.kBoth);
         }
       ...
       }

rather than this:

         private void initBallMechanism() {
                ballPickup = new Relay(RobotConstants.DSC_LEFT_SLOT,
         RobotConstants.BALL_PICKUP_CHANNEL);
                bottomShooter = new Relay(RobotConstants.DSC_LEFT_SLOT,
         RobotConstants.BOTTOM_SHOOTER_CHANNEL);
                ballElevator = new Victor(RobotConstants.DSC_LEFT_SLOT,
         RobotConstants.BALL_ELEVATOR_CHANNEL);
                topShooter = new Victor(RobotConstants.DSC_LEFT_SLOT,
         RobotConstants.TOP_SHOOTER_CHANNEL);
                ballPickup.setDirection(Relay.Direction.kBoth);
                bottomShooter.setDirection(Relay.Direction.kBoth);
         }


or, worse, this:

         private void initBallMechanism() {
                ballPickup = new Relay(4, 1);
                bottomShooter = new Relay(4, 3);
                ballElevator = new Victor(4, 6);
                topShooter = new Victor(4, 5);
                ballPickup.setDirection(Relay.Direction.kBoth);
                bottomShooter.setDirection(Relay.Direction.kBoth);
         }


A small but convenient difference.

3.5 Creating Classes
        Using Java's classes and interfaces can greatly smooth development. Because classes in Java are
really independent compared to C++ (each class must be defined in a separate file, for instance) splitting
development duties can be done easily and naturally.

3.5.1 Constructors
          Constructors create new instances of objects, Java provides a default constructor that simply
'zeros' everything, that is sufficient for simple classes (e.g a class that just replaces a C/C++ structure).
Often it is useful to create several constructors, for instance the standard constructors for cRIO channels
that can use a slot argument when you have multiple modules of the same type or omit it when there is only
one.
For instance in our BallHandler class:
          public BallHandler(){
              ds = DriverStation.getInstance();
              js = new Joystick(BALL_FIRE_STICK);
              initBallMechanism();
          }

          public BallHandler(Joystick joystick) {
              ds = DriverStation.getInstance();
              js = joystick;
              initBallMechanism();
          }

          public BallHandler(DriverStation driverStation) {
              ds = driverStation;
              js = new Joystick(BALL_FIRE_STICK);
              initBallMechanism();
          }

          public BallHandler(DriverStation driverStation, Joystick joystick) {
              ds = driverStation;
              js = joystick;
              initBallMechanism();
          }

          These multiple ways of instantiating object from the class allow great flexibility to use the
methods and variables of the class in many different contexts. At the opposite end of things you may want
to force only one instance of a class to ever be created, and everyone to access the same one. The WPI
classes that have a getInstance() method use this approach. We don't do this but making your constructor
private and calling it only once from the getInstance method can accomplish this:

         public class MySingletonClass{
                private static MySingletonClass theOnlyInstance = null;

                   private MySingletonClass {
                       //stuff everyone should refer to the same copy of
                       //this can be used to provide the equivalent
                       //of static variables across classes
                   }

                   public static MySingletonClass getInstance {
                      if (theOnlyInstance == null) theOnlyInstance = new MySingletonClass;
                       return theOnlyInstance;
                   }
         }

When an object of MySingletonClass is needed it is simply assigned with getInstance rather than 'new'.

3.6 Try and Catch
        Early in the robot construction cycle there may be things that don't work or aren't installed. Or there
may be features of it, the Java VM, or underlying OS that don't always work, either from bugs or resource
limitations. In cases where something fails often enough to be a concern you can use the try-catch pair of
Java commands. For 1279 the cRIO and camera aren't always in the same place. If you try to do a
getInstance() on your camera when it is not attached there is along time-out and then a cascade of errors.
We have to live with the timeout, but there is an easy way to work without having to download different
code to ignore the camera.

In the constructor :

          try {
              ac = AxisCamera.getInstance();
          }
          catch(NIVisionException e) {
              ac = null;
              System.out.println("Camera not found! e=" + e);
          }

          if (ac == null ) cameraPresent = true;
          else cameraPresent = false;

then in methods that depend on the camera

         public Targeted findTarget(double volts){

                   if (!cameraPresent) return null;


4 Debugging Techniques
     Under Java you can use 'Run' to download for normal purposes and you will be able to see the printlns
you have put in the code in the output window. Or if not connected to NetBeans in the console. In order to
connect the debugger you must choose debug, which downloads an image with hooks for the debugger.

4.1 println
        The Java standard System.out.println() method is used almost exactly as you would use printf
(except for the nice, if obtuse, format specifiers). There are a few downsides, the most important is that it is
expensive. Write a 1000x loop that prints the time every loop. Then write one that prints the time before
and after rather than during. You will not want leave any printlns active in your final code.
        Also there were problems seeing the printlns in the NetBeans output pane during early construction
of the SimpleRobot derived class. I was measuring about a 1.5 second delay before output was redirected
from the console to the TCP/IP port.

4.2 stdout stderr to files
       File I/O is allegedly working right now, but I have not had a chance to check it. The created files
would be ftp'ed back to your PC after a run for examination. Be careful if you use file logging to check and
clean up your files. You don't want to fill up the filesystem at an inopportune moment.

4.3 Setting Breakpoints
4.4 Connecting the Debugger
     Interactive debugging is very nice under NetBeans, the remote target can have conditional and non-
conditional breakpoints, you can watch variables, step through and over method calls. In short, everything
that you would expect from a host platform debugger you can do on the embedded target.

        Make sure your project is the Main Project, or set it by right clicking on the project name.
        Set at least one break point (that will definitely trigger if conditional)
        Right click the project and select Debug. It will take about a minute for the debug image to fully
         load.
        When you see "Waiting for Connection from Debugger..." select Attach Debugger from the menu
         or toolbar.

   Once connected you will see new icons on the toolbar to the right of the debug icon. Hovering the
mouse will show what each does.
4.5 Watching a variable
      When the debugger is attached you will see Variables and Breakpoints tabs have been added to the
output pane. The bottom icon in the left hand column allows you to add watch expressions. These can be
single variables or combinations or several. The value only updates in the display when a breakpoint is hit,
but it is monitored constantly.

5 Pitfalls
5.1 Improvements
         Read through as much of the docs and example code as possible and note things that are convenient
and potentially useful. While porting I spent an hour writing code to do my own maintenance and sorting of
'hit lists' of ParticleAnalysisReports. I then happened across the getOrderedParticleAnalysisReports()
function and realized they had improved much of the image handling code. Quite a bit of fiddling was
replaced with essentially two lines of code.

        The Java image processing and camera functions seem better than last years C++ (I don't know if
parallel improvements were made there as well). There are certain issues however. We initialize the Axis
camera in one of our class constructors and if the camera is not connected the time out is quite long. Some
teams reported this as a crash, but we found that if you wait long enough, and don't try to use the camera
object later, that the rest of the code ran fine after timing out.

5.2 Timing and Overhead
        We ran a number of timing tests and found a wider than expected (wider than last year's C++)
variation in timing for our main teleoperated loop. The loops take longer, seem to vary more, and are I/O
sensitive. That said, the actual performance of the robot in competition did not seem to suffer.
        Last year's robot was able to do all our main loop processing in less than 20ms with image
processing rates of 25FPS. That would mean an image was processed every other loop. The Java code was
modified to a 30ms main loop. At that rate is only broke real-time about once every two or three seconds.
       I strongly recommend profiling the timing characteristics of your system if you have any
integrations or measurements that might be sensitive to variations.

5.3 Using free()
      Certain lower level functionality, including a lot of the image processing functions are handled
outside the JVM in C. As a result the normal garbage collection process doesn't realize memory has been
allocated and won't cause it to be automatically freed. An explicit call to free() on the object will result in
the appropriate cleanup taking place. You should carefully check the documentation when using methods
that return objects, and see if a free is necessary. When programming our image processing we ran out of
memory in about 90 seconds. Here is the code, with the added free()s everything can run forever.

          ColorImage cameraImage;
          if (ac.freshImage()) cameraImage = ac.getImage();
          else return false;

          BinaryImage imageMask = null;
          imageMask = cameraImage.thresholdHSL(td.hue.minValue,
                                               td.hue.maxValue,
                                        td.saturation.minValue,
                                        td.saturation.maxValue,
                                         td.luminance.minValue,
                                         td.luminance.maxValue);
          if (cameraImage == null) return false;
          else cameraImage.free();
          /* get largest particles that meet criteria */
          /* GetLargestParticles fills out only the indices in the hitReport */
         hitReport.pars = imageMask.getOrderedParticleAnalysisReports(numberHitsRequested);

        if (imageMask == null) return false;
         else imageMask.free();


6 Q&A
7 Reference Material
     Keep an eye on the various forums for comments and code by the various teams, some are doing very
systematic examination of the environment, libraries, and JVM. We at 1279 are certainly indebted to all
those whose comments and code helped us along the way.

7.1 Contact Info
Our Beta Testing Team was:

Emily Osmond - mentor/parent
Gerard Osmond - mentor/parent
Jim O'Malley - mentor/parent
Brian Osmond - student
John Osmond - student
Stephen Simon - student
Peter Stadmueller - student

With the gracious assistance of the rest of team 1279's mentors, parents, and students, our General Manager
teacher Marika Foreman, and the administration and staff of Immaculata.

Visit us at http://www.coldfusion1279.com/index.htm

You can contact us with programming questions at jamesomalley (-at-) comcast.net.

								
To top