Tuesday, August 30, 2016

FTC Robot Behavior Model (Part 5 - OpMode)

This is part 5 of a 5 part series on a robot behavior framework.

Behaviors are connected together with events to form more complex behaviors. In this simple example, pressing the y button on the joystick will trigger a change in the active behavior from driving the robot with an an arcade style input to driving the robot with a tank style input.


The OpMode software does the following:

It begins by setting up the behavior framework in the H1TeleOp_Js2() constructor or the opmode init() method as follows:

// ConstructorBehaviors_Joystick be;
GlobalData gd;
public H1TeleOp_Js2(){
    // Setup the behavior model    gd = new GlobalData();
    be = new Behaviors_Joystick(gd);
}

In our example, the behaviors framework is called Behaviors_Joystick(). GlobalData is needed to pass information back and forth in the loop() method for the opmode as follows:

// Run periodically when sensors are read@Overridepublic void loop() {
    // Pass Joystick to the behaviors    gd.jsLeftY = gamepad1.left_stick_y;
    gd.jsRightY = gamepad1.right_stick_y;
    gd.jsLeftX = -gamepad1.left_stick_x;
    gd.buttonX = gamepad1.x;
    gd.buttonY = gamepad1.y;

    // Pass time to the behaviors    gd.deltaTime = (float)time - gd.time;
    gd.time=(float)time;

    // Run the behaviors    be.onLoop();

    // write the values to the motors    motorRight.setPower(gd.rightCmd);
    motorLeft.setPower(gd.leftCmd);

    telemetry.addData("_Behavior", be.getActiveBehavior().getName());
    telemetry.addData("Power Left", Float.toString(gd.leftCmd));
    telemetry.addData("Power Right", Float.toString(gd.rightCmd));
    telemetry.addData("Left Js Y", Float.toString(gd.jsLeftY));
    telemetry.addData("Right Js Y", Float.toString(gd.jsLeftY));

    //DbgLog.msg("Run Mode");}

The method onLoop() calls the behavior framework. When the robot first starts up, it will begin by calling the Behavior_JsArcade behavior.

For full copies of this software, see: https://github.com/dlacres/GeekMyBot.git 

This github repository has the following behaviors defined:

  • Behavior_Forward - Drive forward
  • Behavior_Heading - Use the dpad and the gyro to turn the robot (demonstrates a simple PID control law)
  • Behavior_IrTurn - Turn toward the IR Beacon. Move forward and backward to match the signal strength.
  • Behavior_JsArcade - Drive using Arcade mode
  • Behavior_JsGyro - Drive using Arcade mode. Correct for drift with the gyro.
  • Behavior_JsLookup - Drive using Arcade mode. Provide better low speed turns using a lookup table to shape the commands.
  • Behavior_JsTank - Drive using Tank mode.
This github repository also has the following events defined:

  • Event_ButtonX - Transition on the rising edge of a X button push
  • Event_ButtonY - Transition on the rising edge of a Y button push
  • Event_Time - Transition after a period of time
 
If you use this behavior framework, I ask that you share the love. Print out a copy of the GeekMyBot logo and put it on your robot along with the http://geekmybot.blogspot.com/ URL address. Share this Blog with your friends.

If you develop a behavior that you are particularly proud of, I ask that you add a comment to this article and share your behavior along with a link to your software.


FTC Robot Behavior Model (Part 4 - Global Data)

This is part 4 of a 5 part series on a robot behavior framework.

Behaviors are connected together with events to form more complex behaviors. In this simple example, pressing the y button on the joystick will trigger a change in the active behavior from driving the robot with an an arcade style input to driving the robot with a tank style input.


This article describes how information is passed from the joystick, motors, and sensors into the behavior framework. The GlobalData class is a buffer between the robot opmode and the behavior classes. If we share behaviors and events as a community, the global data class lets us re-map the I/O between names used in the opmode and names used by different behaviors. Although this is not the most elegant solution, it is simple and fast to implement. Get and Set methods can be used instead of public data if desired.


There is no template or interface for the Global Data. Just create a class called GlobalData and define the data your behavior model needs and produces. Here is an example of the GlobalData class I used in my example:


package com.qualcomm.ftcrobotcontroller.geekmybot;

/** * Created by David Lempia on 8/20/2016. */public class GlobalData {
    public GlobalData(){
    }
    // Gyro    public float headingDot=0.0f, heading=0.0f, headingCmd=0.0f;

    // Motors    public float rightCmd=0.0f, leftCmd=0.0f, rightCmd1=0.0f, leftCmd1=0.0f;

    // Joystick    public float jsLeftX, jsLeftY, jsRightX, jsRightY;
    //public float throttleJs=0.0f, directionJs=0.0f;    public boolean buttonX, buttonY;
    public boolean dpadRt, dpadLt, dpadUp, dpadDn;

    // Time    public float time,enterTime;
    public float deltaTime=0.0f;

    // IR Seeker    public double irAngle,irStrength;
    public boolean irDetected;

    // Debug    public float debugFloat1=0.0f, debugFloat2=0.0f;
    public int debugInt1, debugInt2;
    public double debugDouble1, debugDouble2;
    public boolean debugBoolean1, debugBoolean2;
}

For full copies of this software, see: https://github.com/dlacres/GeekMyBot.git 
 
If you use this behavior framework, I ask that you share the love. 
Print out a copy of the GeekMyBot logo and put it on your robot along 
with the http://geekmybot.blogspot.com/ URL address. Share this Blog 
with your friends.
 
If you develop an event that you are 
particularly proud of, I ask that you add a comment to this article and 
share your behavior along with a link to your software.

FTC Robot Behavior Model (Part 3 - Behaviors)

This is part 3 of a 5 part series on on a robot behavior framework.



The behavior model is tied together in in the Behaviors class. The Behaviors class creates new instances of each behavior and event. It also defines which behavior is the active behavior to start with. Finally it connects the events to the behaviors

The Behaviors class implements the Behaviors interface. The methods onLoop() and getActiveBehavior() are used by Behaviors. Each method has a purpose in the framework as follows:

 - onLoop() runs each time the robots's opmode is run.
 - getActiveBehavior() is used by the framework to get and run the onLoop() for the active behavior.

In this example, the behaviors class will start running the Behavior_JsArcade class. This class drives the robot using the left joystick in arcade mode. When the Y joystick button is pressed, the behavior changes to the Behavior_JsTank class. This class drives the robot using the left and right joystick in tank mode. When the joystick Y button is pressed again. the behavior transitions back to the Behavior_JsArchade class. The following picture depicts this behavior:



To use Behaviors copy the Behaviors_Template.java shown below into a new class name. I start the name of all of my Behaviors classes with the naming convention Behaviors_XX where XX is the name of my Behaviors. Here is a copy of the template:

package com.qualcomm.ftcrobotcontroller.geekmybot;

import java.util.List;

/** * Created by David Lempia on 7/20/2015. */public class Behaviors_Template {

    // Public SM Inputs and Outputs
    // Declare the states and events
    // Add the states and events used in this state machine    public Behaviors_Template(GlobalData gd){
        // Create the states - Input is the name of the state for debug        //Behavior behavior?? = new Behavior_??(  gd, "?? Behavior");
        // Create the events - Behavior From, Event, Behavior To        //behavior??.addEvent( new Event_ButtonY(gd, behavior??));
        // The start state for the state machine        //activeBehavior = ??    }

    // Do not change this. This stays constant    private Behavior activeBehavior;
    public void onLoop(){

        List<Event> el = activeBehavior.getEventList();

        //Log.i("info", "Made it to 1");        for (Event el1 : el){
            //Log.i("info", "Made it to 2");            if (el1.isTriggered()){
                // If the event happened, run exit, step, and entry code                activeBehavior.onExit();
                el1.onTransition();

                // Update the active state                activeBehavior = el1.getToBehavior();
                activeBehavior.onEntry();
                break; // Do not check the rest of the transitions            }
        }
        // Run active state        activeBehavior.onLoop();
    }
    public Behavior getActiveBehavior(){
        return(this.activeBehavior);
    }
}

Begin by creating a new set of behaviors  in the Behaviors_Joystick2 creator as follows:
// Create the behaviors - Input is the name of the behavior for debugBehavior behaviorJsArcade = new Behavior_JsArcade(gd, "Js Arcade");
Behavior behaviorJsTank = new Behavior_JsTank(gd, "Js Tank");


Right after this software in the same module, create a set of events and define their transitions as follows:

// Create the events (lines)behaviorJsArcade.addEvent( new Event_ButtonY(gd, behaviorJsTank));
behaviorJsTank.addEvent( new Event_ButtonY( gd, behaviorJsArcade));

Finally, define the initial active behavior (The behavior the robot starts in) as follows:
// The start state for the state machineactiveBehavior = behaviorJsArcade;

The resulting Behaviors_Joystick2 class is shown below:

package com.qualcomm.ftcrobotcontroller.geekmybot;

import java.util.List;

/** * Created by David Lempia on 7/20/2015. */public class Behaviors_Joystick2 implements Behaviors {

    // Add the behaviors and events    Behavior activeBehavior;
    public Behaviors_Joystick2(GlobalData gd){

        // Create the behaviors - Input is the name of the behavior for debug        Behavior behaviorJsArcade = new Behavior_JsArcade(gd, "Js Arcade");
        Behavior behaviorJsTank = new Behavior_JsTank(gd, "Js Tank");

        // Create the events (lines)        behaviorJsArcade.addEvent( new Event_ButtonY(gd, behaviorJsTank));
        behaviorJsTank.addEvent( new Event_ButtonY( gd, behaviorJsArcade));

        // The start state for the state machine        activeBehavior = behaviorJsArcade;
    }

    // Do not change this. This stays constant    public void onLoop(){

        List<Event> el = activeBehavior.getEventList();

        //Log.i("info", "Made it to 1");        for (Event el1 : el){
            //Log.i("info", "Made it to 2");            if (el1.isTriggered()){
                // If the event happened, run exit, step, and entry code                activeBehavior.onExit();
                el1.onTransition();

                // Update the active state                activeBehavior = el1.getToBehavior();
                activeBehavior.onEntry();
                break; // Do not check the rest of the transitions            }
        }
        // Run active state        activeBehavior.onLoop();
    }
    public Behavior getActiveBehavior(){
        return(this.activeBehavior);
    }
}

For full copies of this software, see: https://github.com/dlacres/GeekMyBot.git
 
If you use this behavior framework, I ask that you share the love. Print out a copy of the GeekMyBot logo and put it on your robot along with the http://geekmybot.blogspot.com/ URL address. Share this Blog with your friends.

If you develop an event that you are particularly proud of, I ask that you add a comment to this article and share your behavior along with a link to your software.

 

FTC Robot Behavior Model (Part 2 - Events)

This is part 2 of a 5 part series on on a robot behavior framework.


Behaviors are connected together with events to form more complex behaviors. In this simple example, pressing the y button on the joystick will trigger a change in the active behavior from driving the robot with an an arcade style input to driving the robot with a tank style input.

The event class implements the event interface. The methods onTransition(), isTriggered(), and getToBehavior() are used by the behavior. Each method has a purpose in the framework as follows:

 - onTransition() runs only when the event is triggered resulting in a transition between behaviors. The order of transitions are set in the behaviors class. This will be covered in the part 3.
 - isTriggered() returns a boolean value. If the Boolean is True, the transition occurs.
 - getToBehavior() is used by the framework when it requests the destination behavior.


To use this behavior, copy the Event_Template shown below into a new class name. I start the name of all of my event classes with the name Event_xx. This naming convention helps when our team shares events for use in different programs. Here is a copy of the template:

package com.qualcomm.ftcrobotcontroller.geekmybot;

/** * Created by David Lempia on 8/2/2015. * * Copy this template and rename it with the name of your event. i.e. Event_ButtonX. * Inputs and Outputs are put in the Behaviors_xx file. Access them using gd.xx * Add the event to the Behaviors_xx file. * Add inputs and outputs to the Behaviors_xx file. * Pass parameters in through the Event_Template Constructor. */public class Event_Template implements Event {
    private Behavior toBehavior;

    // Returning true triggers the event    // Pass variables    public boolean isTriggered(){
        return(false);
    }

    // This runs if the event is triggered    public void onTransition(){

    }

    // Change Behaviors_XX to the name of your behaviors class    // Add parameters as needed    GlobalData gd;
    Event_Template(GlobalData gd, Behavior toBehavior){
        this.gd=gd;
        this.toBehavior = toBehavior;
    }

    // No change needed    public Behavior getToBehavior() {
        return(this.toBehavior);
    }
}

To create an event that transitions whenever the Y joystick button is pressed, add a new RiseEdgeTrigger to the constructor. Check for a button press in the isTriggered() method. Here is what the final sofware looks like for the Event_ButtonY.java class:

package com.qualcomm.ftcrobotcontroller.geekmybot;

/** * Created by David Lempia on 8/2/2015. */public class Event_ButtonY implements Event {

    // Returning true triggers the event    public boolean isTriggered(){
        boolean button_pressed = pressed.calculate(gd.buttonY);
        return(button_pressed);
    }

    // This runs if the event is triggered    public void onTransition(){

    }

    // No change needed    RiseEdgeTrigger pressed;
    private Behavior toBehavior;
    GlobalData gd;
    Event_ButtonY(GlobalData gd, Behavior toBehavior){
        this.gd = gd;
        this.toBehavior = toBehavior;
        pressed = new RiseEdgeTrigger();
    }

    // No change needed    public Behavior getToBehavior() {
        return(this.toBehavior);
    }
}

Here is the software for the RiseEdgeTrigger.java class:
 
package com.qualcomm.ftcrobotcontroller.geekmybot;

/** * Created by David Lempia on 1/17/2016. */public class RiseEdgeTrigger {
    private boolean z1=false;
    private boolean out=false;

    public boolean calculate(boolean in){

        if (in & !this.z1) this.out=true;
        else this.out=false;

        this.z1=in;

        return(this.out);
    }
}

For full copies of this software, see: https://github.com/dlacres/GeekMyBot.git 
 
If you use this behavior framework, I ask that you share the love. Print out a copy of the GeekMyBot logo and put it on your robot along with the http://geekmybot.blogspot.com/ URL address. Share this Blog with your friends.

If you develop an event that you are particularly proud of, I ask that you add a comment to this article and share your behavior along with a link to your software.

 

Monday, August 29, 2016

FTC Robot Behavior Model (Part 0)

This article is written for FTC robots using the Android Developer Studio. It describes a behavior model similar to a state machine that can be used to do very interesting things with a robot. For example, the behavior model can control a complex motion on an arm, autonomously drive the robot along a path, or interrupt a motion when a sensor detects an interfering robot. In this example I picked a very simple behavior to demonstrate how to use the behavior model. See the image below:







Pressing the Y button on the joystick will transition the drive mode of the robot from Arcade to Tank and back again.

If you use this behavior framework, I ask that you share the love. Print out a copy of the GeekMyBot logo and put it on your robot along with the http://geekmybot.blogspot.com/ URL address. Share this Blog with your friends.

If you develop a behavior that you are particularly proud of, I ask that you add a comment to this article and share your behavior along with a link to your software.

Robots are interesting when they perform a set of different behaviors. For example one behavior may be to drive using the joystick in tank mode. Another behavior may be to drive using the joystick in arcade mode.

Wouldn't it be nice if:
  • I could build a library of simple behaviors. When I need one, I just add it from the library.
  • I could build complicated behaviors by transitioning from one simple behavior to another behavior when an interesting event takes place.
  • I could re-use the behaviors in many different applications.

This article describes a simple robot behavior framework (set of Java Classes) that makes constructing behaviors and transitioning from one behavior to another easy. The article is written in 5 different parts as follows:

Part 1 - Behavior
Part 2 - Events
Part 3 - Behaviors
Part 4 - Global Data
Part 5 - OpModes


These articles are written for a two wheel drive robot that is typically used in FTC competitions. Here is a picture of the robot used in this example:






The robot has two drive motors and wheels, a left drive and a right drive. There is one omni-wheel in the back. The electronics are mounted vertically. From left to right in the picture above, the electronics are an android phone, The power distribution (the one shown is home-built using a USB hub and a 5 volt regulator), a Core Legacy Module, a Core Motor Controller, and a Core Device Interface. There is an IR seeker V3 and an integrating gyro sensor plugged into the Core Device Interface.

All software can be downloaded from - https://github.com/dlacres/GeekMyBot.git





FTC Robot Behavior Model (Part 1 - Behavior)

This is part 1 of a 5 part series on a robot behavior framework. Read Introduction to the FTC Robot Behavior Model to learn more.

The basic building block of this behavior framework is a behavior. A great behavior does one thing (behavior) and does it robustly. A behavior is active when it's onLoop() method is run by the opMode for the robot. A behavior is inactive when it is waiting for a trigger.

Events transition from one behavior to the next behavior. Events are covered in part 2 of this article.

The behavior class implements the behavior interface. The methods onEntry(), onExit(), onLoop(), addEvent(), getName(), and getEventList() are used by the framework. Each method has a purpose in the framework as follows:

 - onEntry() runs when any event results in a transition into the behavior.
 - onExit() runs when any event results in a transition out of the behavior.
 - onLoop() runs each time the robot's opmode is run.
 - addEvent() is used by the framework to add events that transition from this behavior to a list
 - getName() is used by the framework to return the name of the active behavior for display
 - getEventList() is used by the framework to return the list of events. This list is used to check if the isTriggered() method is true resulting in a transitioning to a new active behavior.

To use this behavior, copy the Behavior_Template shown below into a new class name. I start the name of all of my event classes with the name Behavior_xx where xx is a description of the behavior. This naming convention helps when our team shares behaviors for use in different programs. Here is a copy of the template:


package com.qualcomm.ftcrobotcontroller.geekmybot;

import java.util.ArrayList;
import java.util.List;

/** * Created by david lempia on 7/20/2015. * * Copy this template and rename it with the name of your behavior. i.e. Behavior_Forward. * Inputs and Outputs are put in the Behaviors_xx file. Access them using gd.xx * Add the behavior to the Behaviors_xx file. * Add inputs and outputs to the Behaviors_xx file. * Pass parameters in through the Event_Template Constructor. */public class Behavior_Template implements Behavior {
    // Change the name of this behavior (for diagnostics)    String behaviorName="none";

    // Add code for onEntry. This method is called one time when entering the behavior.    public void onEntry(){

    }
    // Add code for onExit. This method is called one time when exiting the behavior.    public void onExit(){

    }
    // Add code for onLoop. This method is called from loop as long as the behavior is active.    public void onLoop(){

    }

    // Add new classes as needed    List <Event> eventList;
    GlobalData gd;
    public Behavior_Template(GlobalData gd, String behaviorName){
        this.gd=gd;
        eventList=new ArrayList<Event>();
        this.behaviorName=behaviorName;
    }
    public List<Event> getEventList(){
        return(eventList);
    }
    public void addEvent(Event newEv){
        eventList.add(newEv);
    }

    @Override    public String getName() {
        return(this.behaviorName);
    }
}

Next, add the following code to the onLoop method:

// Drive calculations using Joystick inputs;float throttle = gd.jsLeftY/2.0f;
float direction = gd.jsLeftX/3.0f;
float right =  throttle - direction;
float left = throttle + direction;
gd.rightCmd = Range.clip(right, -1, 1);
gd.leftCmd = Range.clip(left, -1, 1);


Also, change the name of this behavior:

// Change the name of this behavior (for diagnostics)
String behaviorName="JS Arcade";



This string will be sent to the android phone connected to the joystick to indicate which behavior is active.



The JsTank behavior can likewise be created. Copy this template into a new class titled Behavior_JsTank. Add the following code to the onLoop method:

// Drive calculations using Joystick inputs;gd.rightCmd = gd.jsRightY;
gd.leftCmd = gd.jsLeftY;

 Also, change the name of this behavior:

// Change the name of this behavior (for diagnostics)
String behaviorName="JS Tank";


For full copies of this software, see: https://github.com/dlacres/GeekMyBot.git 
 
If you use this behavior framework, I ask that you share the love. Print out a copy of the GeekMyBot logo and put it on your robot along with the http://geekmybot.blogspot.com/ URL address. Share this Blog with your friends.

If you develop a behavior that you are particularly proud of, I ask that you add a comment to this article and share your behavior along with a link to your software.