Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Programming (http://www.chiefdelphi.com/forums/forumdisplay.php?f=51)
-   -   no control of bot when kicker is operating (http://www.chiefdelphi.com/forums/showthread.php?t=86070)

Ether 11-06-2010 22:59

Re: no control of bot when kicker is operating
 
What you've posted is essentially a state machine, where the state variable is the value of kickTimer.

A generic state machine might look like this:


Quote:

// Set kicking loop to start when button 7 on gamepad is pressed and not in loop already


switch(kickState) {

case 0: // kicking is not in progress

if(gamePad.getRawButton(7) == true) {
start_the_kick_sequence_and_initialize_variables_a s_necessary();
kickState = 1;
}
break;

case 1:

if case_1_timer_or_event_has occurred(){
perform_case_1_action();
initialize_variables_for_case_2_as_necessary();
kickState=2;
}
break;

case 2:

if case_2_timer_or_event_has occurred(){
perform_case_2_action();
initialize_variables_for_case_3_as_necessary();
kickState=3;
}
break;

.
.
.


case n:

if case_n_timer_or_event_has occurred(){
perform_casen2_action();
initialize_variables_for_case_0_as_necessary();
kickState=0;
}
break;

}


The above has the advantage that it's a little easier to see how to use events (like limit switches etc) to change states, instead of being strictly timer-based.


~

synth3tk 12-06-2010 00:44

Re: no control of bot when kicker is operating
 
Thanks for the suggestions. I should have also stated:

I'm a non-student member (I guess a mentor, in some ways), and our team is extremely small. I couldn't even coerce any students to learn programming, so I had to learn Java with some small help from the team mentor (who knew very little more about Java than I did) and the internet starting 2 days from Kick-Off.

We were just getting the bare minimum working. But I'll keep that in mind for the future, if/when we teach the new programmers.

frasnow 12-06-2010 16:16

Re: no control of bot when kicker is operating
 
One solution for solving this in Java is threads. Team 997’s kicker this year takes 4.5 seconds to reload. It was extremely important for us to make sure the driver maintained control during this time. I’ve copied in some of our code below and removed most of the extra stuff it for you to see how we did threading on our robot.

A couple things to keep in mind.
1. It is vital your each thread of execution have either a Thread.yield() and/or a Timer.delay(). These are required to ensure each thread gets time on the CPU. Otherwise one thread could starve (not get any time on the CPU).
2. Put things like kicking that take a long time in separate threads, but keep quick things in the main thread. I accidentally put our gear shift in the kicker thread and the driver couldn’t shift while the kicker was reloading. :o We fixed this after regionals.

Main thread that starts kicker thread:
Code:

public class RobotMain extends SimpleRobot {

    final int Preload = 1;
    final int Retract = 0;
    final int Latch = 1;
    final int Unlatch = 0;
    private Joystick leftStick = new Joystick(1);
    private Joystick rightStick = new Joystick(2);
   
    public RobotMain() {
    }

 
    public void operatorControl() {
       
        getWatchdog().setEnabled(true);
     
        KickerThread kickerThread = new KickerThread(this);
        kickerThread.start();
        while (true && isOperatorControl() && isEnabled()) {
           
            drivetrain.tankDrive(leftStick, rightStick);
            getWatchdog().feed();
           
            // DO NOT remove this yield. Required for kicker thread to execute.
            Thread.yield();
        }
        try {
            kickerThread.join();
        } catch (InterruptedException ex) {
            System.out.println(ex.getMessage());
        }

    }

    /**
    * Gets the right joystick
    * @return The right joystick
    */
    public Joystick getRightStick() {
        return rightStick;
    }

    /**
    * Gets the robot ready for the big kick.
    */
    private void makeReadyForKick() {
        //Not latched and needs to be preloaded.
        if ((preloaded == false) && (latched == false)) {
            driveLatchSolenoid(Latch);
            Timer.delay(1);
            driveShooterSolenoid(Preload);
            Timer.delay(1);
        }
        //Latched, but needs to preload.
        if ((preloaded == false) && (latched == true)) {
            driveShooterSolenoid(Preload);
            Timer.delay(1);
        }
        //Preloaded, but needs to latch.
        if ((preloaded == true) && (latched == false)) {
            driveShooterSolenoid(Retract);
            Timer.delay(2);
            driveLatchSolenoid(Latch);
            Timer.delay(1);
            driveShooterSolenoid(Preload);
            Timer.delay(1);
        }
    }

    /**
    * Peforms the kick routine.  First loads the kicker if needed.
    * After kicking it loads the kicker for the next big kick.
    */
    public void performKick() {
        makeReadyForKick();
        //Kick!
        driveLatchSolenoid(Unlatch);
        Timer.delay(.5); // If this changed, change the delay in autoKick!!!
        //Reload for big kick.
        driveShooterSolenoid(Retract);
        Timer.delay(2);
        driveLatchSolenoid(Latch);
        Timer.delay(1);
        driveShooterSolenoid(Preload);
        Timer.delay(1);
        System.out.println("Kick Performed");
    }

}

Kicker Thread:
Code:

public class KickerThread extends Thread {
    private RobotMain mRobot997;
    private Joystick mRightStick;
    public KickerThread(RobotMain robot) {
        mRobot997 = robot;
        mRightStick = mRobot997.getRightStick();
    }

    public void run() {
        while (mRobot997.isOperatorControl() && mRobot997.isEnabled()) {
            if (mRightStick.getTrigger()) {
                mRobot997.performKick();
            }
            Thread.yield();
        }
    }
}

In order to allow us to drive to the next ball in autonomous while reloading, we also used threads. The main thread just set a flag on the autonomous kicker thread's class to let it know when to go ahead and perform the kick. Does require being sure to write thread safe code.

frasnow 12-06-2010 16:36

Re: no control of bot when kicker is operating
 
One point of clarification, since multithreading can be a confusing topic for some. Event though the performKick() method is located in the RobotMain class, the call to performKick() located in the KickerThread class' run() method still executes on the second thread. Any methods called during the While loop in the operatorControl() method are executing on the main thread.

Ether 12-06-2010 16:59

Re: no control of bot when kicker is operating
 
Hey, welcome aboard frasnow. Check your Private Message inbox, I had a question about your post. :-)

virtuald 13-06-2010 03:18

Re: no control of bot when kicker is operating
 
1 Attachment(s)
I'm not sure if Java has the same thing, but in C++ another easy way to do something like this (without having to worry about yielding, since it does it for you automatically) in a different thread is via the Notifier class. It calls a function every N seconds (we specified 0.0025 seconds) on a different thread. Then you just have your state machine in a single function and have it do the right thing (ie, operate the right switches and such) every time the function gets called. And as the other poster said, you have a different function that gets called by the main thread that touches the state variables.

Of course, a key thing when dealing with multiple threads is to make sure you deal with potential synchronization problems, by using the appropriate locking mechanisms. In C++, you can use the Synchronized class to do that.

I've attached our Kicker code in C++. The full version of our 2010 code is at http://www.virtualroadside.com/FRC/

Ether 13-06-2010 09:10

Re: no control of bot when kicker is operating
 
Some thoughts for discussion:

Threads in C++ can be preemptive, regardless of whether or not they are created by the Notifier class. In any case, using cooperative multitasking techniques like releasing the CPU to service other tasks while waiting for an event or timer (block waiting) is good programming practice. It makes your code more responsive and avoids wasting CPU resources.

If the kicker code is properly implemented as a state machine, you don't need concurrency, and you don't need to worry about synchronization.

~

Ether 13-06-2010 09:51

Re: no control of bot when kicker is operating
 
I've seen the following kicker approach successfully implemented in LabVIEW. The same approach could be used in Java or C++.

put the following code in a separate concurrent periodic task using your language of choice. for a kicker, 20Hz is probably plenty fast enough.

Code:

/*
to establish the 50ms period (20Hz frequency) put your code here
to block wait for 50ms to elapse, releasing the CPU so this task
does not run at high speed and use CPU resources unnecessarily
when not kicking
*/

if (kickRequested && !kicking) {

kicking=1; // prevent reentrancy

/*
put your sequential kicking code here.

if your code has places where it needs to wait for an event,
like elapsed time or a limit switch for example,
make sure you code it so that the CPU will be released
to use that time to service other tasks
while waiting for the event.

if your code uses data from other tasks,
make sure the access is protected.
*/

kicking=0;

}


"kickRequested" is a global boolean that is used by your code in Autononmous and/or TeleOp to request that a kick be performed.

"kicking" is a local boolean to control reentrancy: If a kick is presently in progress when the request is made, the request will be ignored (so as not to interrupt the ongoing kick cycle)

timothyb89 17-06-2010 02:29

Re: no control of bot when kicker is operating
 
One thing I liked doing for the kicker code was making sure you couldn't violate the timing rules (2 seconds between extensions out of the main robot body), and tossing in a few extra threads made it fit together nicely. Obviously reload time can make this unneeded, so it might not even be needed, depending.

Example code here.


All times are GMT -5. The time now is 23:19.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi