Driverstation / Dashboard in JAVA

We cannot seem to get the Dashboard to work in Java. It works in LabView but when we build or open the Driverstation - everything is 0 and never changes. We tested the hardware on another cRIO imaged for LabView and everything works there (Analog In, Digital In / Out, Solenoid interface).

We tried the DashboardDemo and it gives a compile error about the solenoid class.

The new Dashboard GUI will not even load. It is as if the cRIO is hexed against JAVA. We used JAVA last year without incident but this year the libraries just do not seem to work.

The display shows all green lights but no sensor data is displayed.

What I ended up doing was grabbing the updateDashboard method from the Dashboard Example, and copying and pasting it into a new class. I then spun off a thread of that class to keep the dashboard constantly updated.


Dstation station;

robotInit() {
    station = new Dstation();
    new Thread(station).start();
}

That in the main class. Then create a new class Dstation. I’m using that class to consolidate all the dashboard and driver station commands into more simplified forms (please ignore my sarcastic comments in the code :stuck_out_tongue: :


package edu.wpi.first.wpilibj.templates;

/**
 * @author   William Dell
 * @author   Team 647
 * @version  v5, January 26, 2011
 * @version  FRC Java version 2011.4

import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.DriverStationLCD;
import edu.wpi.first.wpilibj.Dashboard;
import edu.wpi.first.wpilibj.AnalogModule;
import edu.wpi.first.wpilibj.DigitalModule;
import edu.wpi.first.wpilibj.Solenoid;

/**
 * The routines for dealing with the driver station are ridiculously complicated
 * and cryptic.  Hopefully this class will simplify the process by replacing them
 * with shorter, more obvious methods.
 */
public class DStation implements Runnable {

    // going to treat the LCD as a stack, in reverse here because
    // new lines appear on the bottom and scroll upwards (mostly)
    DriverStationLCD.Line] lcdLines = {
        DriverStationLCD.Line.kUser6, // bottom line
        DriverStationLCD.Line.kUser5,
        DriverStationLCD.Line.kUser4,
        DriverStationLCD.Line.kUser3,
        DriverStationLCD.Line.kUser2,
        DriverStationLCD.Line.kMain6 // top line
    };
    String] lcdHistory = new String[6];  // array to scroll lcd display
    String clearLine = "                     "; // 21 spaces to clear a line

    // empty constructor
    public DStation() {
    } // end constructor

    /**
     * When run, the class starts a continuous loop to update the dashboard
     * constantly.  This is probably a bad way to do it.
     */
    public void run() {
        
        // caution, infinite loop, this could be bad....
        while (1 == 1) {
            updateDashboard();
        } // end while
        // but it actually works!
        
    } // end method run()

    /**
     * Messages to the LCD must be 21 characters long or you get artifacts
     * from previous lines.  This should pad the desired message out to 
     * the proper length.
     * 
     * @param msg  the message to be padded out
     * @return  line  the message line padded out to 21 characters
     */
    private String padMsg(String msg) {
        String line = msg;
        if (line.length() < 21) {  // if the message is already 21 or more do nothing
            // otherwise tack on however many spaces we are short
            for (int i = msg.length() + 1; i <= 21; i++) {
                line += " ";
            } // end for
        } // end if
        line = line.substring(0, 21); // make sure we are only 21 long
        return line; // and return the new, padded out line
        
    } // end method padMsg()

    /**
     * Does just what it says, clears the driver station LCD.
     */
    public void clearLCD() {
        for (int i = 0; i < 6; i++) {
            lcdHistory* = clearLine; // clear the lcd "memory"
            // and then use the cleared memory to clear the actual display
            DriverStationLCD.getInstance().println(lcdLines*, 1, lcdHistory*);
        } // end for
        DriverStationLCD.getInstance().updateLCD();  // display the screen
        
    } // end method clearLCD()

    /**
     * Simplified messages to the LCD, with scrolling; new messages appear at
     * the bottom of the screen and scroll up.
     * 
     * @param msg  the message to be sent to the screen
     */
    public void sendToLCD(String msg) {

        // scroll down the history;  iterate backwards!
        for (int i = 5; i > 0; i--) {
            lcdHistory* = clearLine;
            lcdHistory* = lcdHistory*;
        } // end for
        lcdHistory[0] = clearLine; // clear the bottom line of the screen
        lcdHistory[0] = padMsg(msg); // insert new line at the bottom, padded out to 21 chars

        // set up updated screen by rewriting all lines
        for (int i = 0; i < 6; i++) {
            DriverStationLCD.getInstance().println(lcdLines*, 1, lcdHistory*);
        } // end for
        DriverStationLCD.getInstance().updateLCD(); // display the screen

    } // end method sendToLCD()

    /** 
     * This makes it easier to send message to a specific line.  Takes the 
     * desired line number (top to bottom, 1-6) and the message to print as
     * arguments.
     * 
     * @param line  which line of the LCD the message should be displayed on
     * @param msg   the message to be displayed
     */
    public void toLCDLine(int line, String msg) {

        int index = 6 - line; // array is set up bottom to top, this reverses it
        DriverStationLCD.getInstance().println(lcdLines[index], 1, padMsg(msg));
        DriverStationLCD.getInstance().updateLCD(); // keep forgetting this, d'oh!

    } // end method toLCDLine()

    /*
     * From here down it's stolen from DashboardExampleProject, and I'm not
     * sure how it works.  Looks like this mess should be replaceable with
     * SmartDashboard, but as usual the documentation sucks.  I've started
     * deciphering what all this means, but for now it just works.
     */
    void updateDashboard() {
        Dashboard lowDashData = DriverStation.getInstance().getDashboardPackerLow();
        
        // add the overall container for the data
        lowDashData.addCluster();  // overall container
        {
            // add the cluster containing the analog modules
            lowDashData.addCluster();
            {
                // analog module 0
                lowDashData.addCluster();
                {
                    for (int i = 1; i <= 8; i++) {
                        lowDashData.addFloat((float) AnalogModule.getInstance(1).getAverageVoltage(i));
                    }
                }
                lowDashData.finalizeCluster();
                
                // analog module 1
                lowDashData.addCluster();
                {
                    for (int i = 1; i <= 8; i++) {
                        lowDashData.addFloat((float) AnalogModule.getInstance(2).getAverageVoltage(i));
                    }
                }
                lowDashData.finalizeCluster();
            }
            lowDashData.finalizeCluster();

            // add the cluster containing the digital modules
            lowDashData.addCluster();
            { 
                // digital cluster 1
                lowDashData.addCluster();
                {
                    // digital module 0
                    lowDashData.addCluster();
                    {
                        int module = 4;
                        lowDashData.addByte(DigitalModule.getInstance(module).getRelayForward());
                        lowDashData.addByte(DigitalModule.getInstance(module).getRelayForward());
                        lowDashData.addShort(DigitalModule.getInstance(module).getAllDIO());
                        lowDashData.addShort(DigitalModule.getInstance(module).getDIODirection());
                        
                        // PWM cluster 1
                        lowDashData.addCluster();
                        {
                            for (int i = 1; i <= 10; i++) {
                                lowDashData.addByte((byte) DigitalModule.getInstance(module).getPWM(i));
                            }
                        }
                        lowDashData.finalizeCluster();
                    }
                    lowDashData.finalizeCluster();
                }
                lowDashData.finalizeCluster();

                // digital cluster 2
                lowDashData.addCluster();
                {
                    // digital module 1
                    lowDashData.addCluster();
                    {
                        int module = 6;
                        lowDashData.addByte(DigitalModule.getInstance(module).getRelayForward());
                        lowDashData.addByte(DigitalModule.getInstance(module).getRelayReverse());
                        lowDashData.addShort(DigitalModule.getInstance(module).getAllDIO());
                        lowDashData.addShort(DigitalModule.getInstance(module).getDIODirection());
                        
                        // PWM cluster 2
                        lowDashData.addCluster();
                        {
                            for (int i = 1; i <= 10; i++) {
                                lowDashData.addByte((byte) DigitalModule.getInstance(module).getPWM(i));
                            }
                        }
                        lowDashData.finalizeCluster();
                    }
                    lowDashData.finalizeCluster();
                }
                lowDashData.finalizeCluster();

            }
            lowDashData.finalizeCluster();

            // add the solenoid cluster
            lowDashData.addByte(Solenoid.getAll());
        }
        lowDashData.finalizeCluster();
        
        // send the new data array to the dashboard
        lowDashData.commit();

    } // end method updateDashboard()
    
} // end class DStation

That makes the dashboard work (still working on the camera), and also lets you send messages to the driver station by just doing

station.sendToLCD("This is a message");

Personal gripe: the “examples” are hardly commented at all, making them extremely difficult to decipher. Please people, use clear variable names (maximumDistance instead of m_maxDist1) and comment your code heavily. You’ll make life much better for those who come after you.********

Thank you. What you show makes sense. I note that you import each sensor class separately. Is that intentional or just happenstance?

I agree with your peeve on the demo code. There was a post on the main page about test codes being posted without comments but a demo program without comments is really annoying. I once worked with a mathematician who said he did not put comments in his code because any GOOD programmer should be able to read the code & understand the algorithm.

Danny

The line “lowDashData.addByte(Solenoid.getAll()); // solenoid cluster” will not compile in version 2011.4. The getAll() method is no longer static. I’m really disappointed FIRST released code that breaks the example.

Worked for me last night :confused:

Yah, that was mine :slight_smile:

I imported each sensor class separately as a teaching tool. I don’t want my students to get in the habit of using wild cards and just importing everything. That’s fine if you are slapping together something quickly, but I don’t think it’s a good practice for production level code. Also, I wasn’t sure how wild cards would impact memory, so I opted for what I thought would be the lower memory model. If I’m mistaken there please correct me, as wild cards would definitely keep me from messing up because I forgot to import something.

This is an extremely unproductive response. If you’d bothered to look at which version of the plugins are installed on your system, you could at least have said “version blah works for me.”

You must have 2011.3. Don’t install the plugin update to 2011.4, or that line of code will break. I’ve looked at multiple systems.

No, I am using 2011.4. No errors, builds and loads fine.

As for the curt answer, I was going back to check and see if I could reproduce your problem, which I cannot. I have no errors and no warnings on that line, or any other line in that class. I deployed this to my test bot last night and it worked fine.

Updated the DStation class above with a cleaned up, and hopefully better commented copy. I still need to flesh out exactly what the updateDashboard method is doing, but I think I’ve got a handle on it now, including how to extend it. Maybe :yikes:

Confirmed. I just finished running my test rig up and down the school hall (noon CST), and the DStation code performed as expected. Sorry frasnow, I’m not sure why it’s not working for you, but no problems here.

I just started making my own Dashboard in Java and am skipping the protocol they designed entirely (and having the cRIO send stuff with SocketConnection). To be honest, the current system is too much of a pain to consider using.

It’s so strange that 2011.4 works on your system, but none of the 4 systems I’ve tried.

Today I tried this:

  1. Uninstalled all the FRC plugins from Netbeans.
  2. Installed what is called version 4.8 on FIRST forge (version 2011.3). With this configuration Solenoid.getAll() is fine and is even declared Static as it should be.
  3. Uninstalled version 4.8 from FIRST forge and downloaded & installed version 4.9 (version 2011.4). I get the Solenoid.getAll() is non-static error. Looking in the code, it is indeed not declared as static.

All my other systems are using the automatic updates. I just can’t understand how your 2011.4 is different from the one on all my systems. It’s not an OS problem; I’ve used Windows 7, Windows XP, Mac OSX, and Linux. It’s not a Netbeans version problem; I’ve tried 6.7, 6.8 and 6.9.1.

hmm. I’m using Netbeans 7.0 beta, but that shouldn’t make any kind of difference.

You could try replacing the solenoid line with:

byte thisBytes = 0;
lowDashData.addByte(thisBytes);

Basically forcing the solenoids to always be zeroed.

I’ve just checked using Eclipse, and the error you have is showing up there. I have no idea why it works when I use Netbeans. I may have to actually hunt down where the libraries are stored on my disk and physically delete them, then re-update.

Wow! I really appreciate your tenacity in trying to reproduce my problem. Hopefully FIRST will fix it soon. I was so astounded by them breaking the example code that I tried to send a message to Derek White at Oracle. He’s listed on FIRST Forge as one of the project administrators.

I’m having my students try the 0 byte thing tonight, since I won’t be there to mentor them. Have you already confirmed it works? My other idea is to waste one of the solenoid connections in order to get an instance variable to call the non-static getAll(), which should allow it to display the state of the solenoids.

It’s in the wpilib tracker http://firstforge.wpi.edu/sf/go/artf1322

I completely eradicated Netbeans from my computer and reinstalled… twice. Found the problem. Whatever is going on, even though my machine was claiming it had 2011.4 installed it hadn’t actually updated the libraries. Got it sussed now, and yes, that line is broken.

Haven’t had a chance to test the 0 byte workaround, won’t be near my lab for a couple hours yet.

Thanks Joe!

The zero byte workaround is good. You don’t get a reading for the Solenoids on the dashboard, but you don’t get error messages either.

With version 2011.4 I observed that the posted dashboard code does not properly map the digital i/o pins on the sidecar to the leds on the dashboard gpio state and gpio output enable. First two leds are always off and led 3 maps to digital i/o 14. i/o 1 and 2 do not change any led on the dashboard.

The following code works properly:

                        
                        int dioData = 0;
                        for( int i = 1; i <= 14; i++)
                        {
                            if( DigitalModule.getInstance( module ).getDIO( i ) )
                            {
                                dioData |= ( 1 << i-1 );
                            }
                        }
                        lowDashData.addShort((short)dioData);
                        int dioDir = 0;
                        for( int i = 1; i <= 14; i++)
                        {
                            if( DigitalModule.getInstance( module ).getDIODirection( i ) )
                            {
                                dioDir |= ( 1 << i-1 );
                            }
                        }
                        lowDashData.addShort((short)dioDir);

There seems to be a problem with getAllDIO() and getDIODirection().

We are getting the problem that it is looking for v_20 and we already updated to v_25. We tried the above code and everything worked except the version error. Any ideas?