Programming the Clawbot¶

Objective:¶

This tutorial volition guide you through bones programming of the VEX Clawbot.

Intended Audience:¶

This tutorial is intended for developers with some programming experience, but with petty to no experience with the PROS library. If y'all haven't programmed before, we recommend checking out all the "Introduction and Basic C++ Features" sections of this tutorial series; be sure to check out the "Classes and Objects" department every bit well.

Goals:¶

At the end of this tutorial yous will accept:

  • Understood the basic organisation of an OkapiLib project
  • Programmed a bones chassis with "tank" control or "arcade" control
  • Programmed buttons to command the clawbot's lift
  • Programmed a joystick axis to command the clawbot's hook
  • Understood the standard subsystem module methodology
  • Programmed an encoder-based democratic routine

Here's the robot nosotros'll be programming:

../../../_images/clawbot1.jpg

Yous can follow VEX's tutorial for building this robot hither.

For the purposes of this tutorial, nosotros've plugged in our motors into the following ports:

Port Clarification Port Description
i Left Wheels 11
2 12
3 Hook Motor xiii
4 14
5 Vision Sensor 15
vi xvi
7 17
eight Arm Motor 18
nine nineteen
x Correct Wheels xx

Port 21: Radio

For the ADI:

Port Description Port Description
A Left Bumper E
B Correct Bumper F
C Grand
D H Arm Limit

To create, build, and upload a new project in PROS 3, run

                                prosv5                conduct                new                <                path_to_project                >                prosv5                make                prosv5                upload                prosv5                terminal              

The last 3 commands tin be simplified to prosv5 mut .

Tank/Arcade Command¶

OkapiLib uses something called a ChassisController to interact with a robot's chassis. This interface lets you utilize open up-loop control methods to drive the robot around with a joystick, like tank and arcade control. It also provides methods to move the robot programmatically, like driving in an arc or only powering one side of the chassis. It likewise provides closed-loop control methods to drive a specific altitude or plow a specific bending.

There are two main subclasses we tin can use: ChassisControllerIntegrated and ChassisControllerPID. ChassisControllerIntegrated uses the V5 motor's built-in position and velocity control to move the robot around. This class is the easiest to utilise, and should be used by default. The other class, ChassisControllerPID, uses two PID controllers running on the V5 encephalon and sends velocity commands to the motors.

Nosotros will be using ChassisControllerIntegrated for this tutorial. Let's initialize information technology with our two motors in ports 1 and 10 , with the motor in port i reversed.

                                                        using                            namespace                            okapi                            ;                            // Chassis Controller - lets us drive the robot effectually with open- or closed-loop control                            car                            drive                            =                            ChassisControllerFactory                            ::                            create                            (                            -                            1                            ,                            ten                            );                          

Next, allow's setup tank or arcade control. ChassisController provides methods for u.s.a. to apply, we just need to pass in joystick values which have been scaled to be in the range [-one, one] . OkapiLib'south Controller returns analog values in the range [-1, 1] , so we don't need to do any partition ourselves.

                              ane  2  3  iv  5  half dozen  seven  8  ix 10 11 12 thirteen
                                                            // Joystick to read analog values for tank or arcade command.                              // Primary controller by default.                              Controller                              masterController                              ;                              while                              (                              true                              )                              {                              // Tank drive with left and right sticks.                              bulldoze                              .                              tank                              (                              masterController                              .                              getAnalog                              (                              ControllerAnalog                              ::                              leftY                              ),                              masterController                              .                              getAnalog                              (                              ControllerAnalog                              ::                              rightY                              ));                              // Wait and requite upward the time nosotros don't need to other tasks.                              // Additionally, joystick values, motor telemetry, etc. all updates every 10 ms.                              pros                              ::                              filibuster                              (                              x                              );                              }                            
                              1  2  three  4  five  vi  7  8  9 x xi 12 13
                                                            // Joystick to read analog values for tank or arcade control.                              // Master controller past default.                              Controller                              masterController                              ;                              while                              (                              true                              )                              {                              // Arcade drive with the left stick.                              drive                              .                              arcade                              (                              masterController                              .                              getAnalog                              (                              ControllerAnalog                              ::                              leftY                              ),                              masterController                              .                              getAnalog                              (                              ControllerAnalog                              ::                              leftX                              ));                              // Wait and requite upward the time we don't need to other tasks.                              // Additionally, joystick values, motor telemetry, etc. all updates every 10 ms.                              pros                              ::                              filibuster                              (                              x                              );                              }                            

Arm Command¶

This section will focus on controlling the clawbot'southward arm. At that place are two parts to this: showtime, the arm has a limit switch at the lesser of its travel range, so we should use that button to tell when we've hit a hard stop; second, the arm should be user-controlled with two buttons on the controller.

First, let'south focus on the limit switch at the bottom of the arm's travel range. When the arm hits this button, the arm motor should finish trying to make the arm move downwards. Nosotros can accomplish this using an if-statement that checks whether the button is pressed.

We can define our button as an ADIButton:

                                    ADIButton                  armLimitSwitch                  (                  'H'                  );                

And the arm motor:

The _mtr syntax is called a user-defined literal. Information technology's a succinct style of initializing a motor, and is equivalent to calling the normal constructor. For case,

                                    Motor                  foo                  =                  1                  _mtr                  ;                  // Motor in port 1                  Motor                  foo                  (                  i                  );                  // Motor in port 1                  Motor                  bar                  =                  ane                  _rmtr                  ;                  // Reversed motor in port 1                  Motor                  bar                  (                  one                  ,                  true                  );                  // Reversed motor in port 1                

And then we can cheque if it's pressed and finish powering the arm motor:

                                    // Don't power the arm if it is all the way downwards                  if                  (                  armLimitSwitch                  .                  isPressed                  ())                  {                  armMotor                  .                  moveVoltage                  (                  0                  );                  }                  else                  {                  // Normal arm control                  }                

Adjacent, let's add the logic to make the arm user-controller with 2 buttons on the controller. Get-go, we need to define our two controller buttons equally ControllerButton instances:

                                    ControllerButton                  armUpButton                  (                  ControllerDigital                  ::                  A                  );                  ControllerButton                  armDownButton                  (                  ControllerDigital                  ::                  B                  );                

Then we tin use them along with our limit switch logic from above to control the arm:

                            1  2  three  4  v  6  7  8  ix 10 11 12 13
                                                        // Don't ability the arm if information technology is all the fashion down                            if                            (                            armLimitSwitch                            .                            isPressed                            ())                            {                            armMotor                            .                            moveVoltage                            (                            0                            );                            }                            else                            {                            // Else, the arm isn't all the manner downward                            if                            (                            armUpButton                            .                            isPressed                            ())                            {                            armMotor                            .                            moveVoltage                            (                            12000                            );                            // 12,000 millivolts                            }                            else                            if                            (                            armDownButton                            .                            isPressed                            ())                            {                            armMotor                            .                            moveVoltage                            (                            -                            12000                            );                            // -12,000 millivolts                            }                            else                            {                            armMotor                            .                            moveVoltage                            (                            0                            );                            // 0 millivolts, the motor will coast                            }                            }                          

Autonomous Routine¶

To illustrate the airtight-loop control method that ChassisController has, allow'due south brand a simple autonomous routine to drive in a square.

Writing an autonomous routine is much easier when distances and turns can be done with real life units, so let'southward configure the ChassisController with the clawbot chassis'due south dimensions. This will require a change to the bulldoze's constructors; 2 additional parameters are needed. The first is the gearset of the motors on the chassis, in this example we will utilise the standard Green cartridges. The second is a list containing firstly the wheel diameter (iv") and secondly, the width of the wheel track (11.5").

                                                        // Chassis Controller - lets united states of america bulldoze the robot around with open- or airtight-loop command                            car                            drive                            =                            ChassisControllerFactory                            ::                            create                            (                            ane                            ,                            10                            ,                            AbstractMotor                            ::                            gearset                            ::                            green                            ,                            {                            4                            _in                            ,                            11.5                            _in                            }                            );                          

Subsequently this, you tin can movement the chassis in actual units, such as inches and degrees.

                                                        for                            (                            int                            i                            =                            0                            ;                            i                            <                            4                            ;                            i                            ++                            )                            {                            drive                            .                            moveDistance                            (                            12                            _in                            );                            // Drive forward 12 inches                            drive                            .                            turnAngle                            (                            90                            _deg                            );                            // Turn in place xc degrees                            }                          

Wrap Up¶

This is the final product from this tutorial.

                              ane  ii  3  iv  five  6  vii  8  9 10 11 12 13 14 15 xvi 17 18 19 20 21 22 23 24 25 26 27 28 29 xxx 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
                                                            #include                              "okapi/api.hpp"                                                            using                              namespace                              okapi                              ;                              // Chassis Controller - lets u.s.a. drive the robot around with open up- or closed-loop control                              auto                              drive                              =                              ChassisControllerFactory                              ::                              create                              (                              one                              ,                              10                              ,                              AbstractMotor                              ::                              gearset                              ::                              green                              ,                              {                              4                              _in                              ,                              11.5                              _in                              }                              );                              void                              opcontrol                              ()                              {                              // Joystick to read analog values for tank or arcade control                              // Master controller by default                              Controller                              masterController                              ;                              // Arm related objects                              ADIButton                              armLimitSwitch                              (                              'H'                              );                              ControllerButton                              armUpButton                              (                              ControllerDigital                              ::                              A                              );                              ControllerButton                              armDownButton                              (                              ControllerDigital                              ::                              B                              );                              Motor                              armMotor                              =                              8                              _rmtr                              ;                              // Button to run our sample autonomous routine                              ControllerButton                              runAutoButton                              (                              ControllerDigital                              ::                              X                              );                              while                              (                              true                              )                              {                              // Tank drive with left and right sticks                              drive                              .                              tank                              (                              masterController                              .                              getAnalog                              (                              ControllerAnalog                              ::                              leftY                              ),                              masterController                              .                              getAnalog                              (                              ControllerAnalog                              ::                              rightY                              ));                              // Don't power the arm if it is all the style down                              if                              (                              armLimitSwitch                              .                              isPressed                              ())                              {                              armMotor                              .                              moveVoltage                              (                              0                              );                              }                              else                              {                              // Else, the arm isn't all the way downward                              if                              (                              armUpButton                              .                              isPressed                              ())                              {                              armMotor                              .                              moveVoltage                              (                              12000                              );                              }                              else                              if                              (                              armDownButton                              .                              isPressed                              ())                              {                              armMotor                              .                              moveVoltage                              (                              -                              12000                              );                              }                              else                              {                              armMotor                              .                              moveVoltage                              (                              0                              );                              }                              }                              // Run the examination autonomous routine if nosotros press the button                              if                              (                              runAutoButton                              .                              changedToPressed                              ())                              {                              // Bulldoze the robot in a square design using closed-loop control                              for                              (                              int                              i                              =                              0                              ;                              i                              <                              four                              ;                              i                              ++                              )                              {                              bulldoze                              .                              moveDistance                              (                              12                              _in                              );                              // Drive frontwards 12 inches                              bulldoze                              .                              turnAngle                              (                              90                              _deg                              );                              // Turn in place 90 degrees                              }                              }                              // Look and requite up the time we don't need to other tasks.                              // Additionally, joystick values, motor telemetry, etc. all updates every 10 ms.                              pros                              ::                              delay                              (                              x                              );                              }                              }                            
                              1  2  3  4  v  6  7  viii  9 10 11 12 13 14 xv 16 17 xviii 19 twenty 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
                                                            #include                              "okapi/api.hpp"                                                            using                              namespace                              okapi                              ;                              // Chassis Controller - lets united states of america drive the robot around with open- or closed-loop control                              auto                              bulldoze                              =                              ChassisControllerFactory                              ::                              create                              (                              1                              ,                              10                              ,                              AbstractMotor                              ::                              gearset                              ::                              green                              ,                              {                              4                              _in                              ,                              11.5                              _in                              }                              );                              void                              opcontrol                              ()                              {                              // Joystick to read analog values for tank or arcade command                              // Master controller by default                              Controller                              masterController                              ;                              // Arm related objects                              ADIButton                              armLimitSwitch                              (                              'H'                              );                              ControllerButton                              armUpButton                              (                              ControllerDigital                              ::                              A                              );                              ControllerButton                              armDownButton                              (                              ControllerDigital                              ::                              B                              );                              Motor                              armMotor                              =                              8                              _rmtr                              ;                              // Push button to run our sample autonomous routine                              ControllerButton                              runAutoButton                              (                              ControllerDigital                              ::                              X                              );                              while                              (                              true                              )                              {                              // Arcade drive with the left stick                              drive                              .                              arcade                              (                              masterController                              .                              getAnalog                              (                              ControllerAnalog                              ::                              leftY                              ),                              masterController                              .                              getAnalog                              (                              ControllerAnalog                              ::                              rightY                              ));                              // Don't ability the arm if it is all the way down                              if                              (                              armLimitSwitch                              .                              isPressed                              ())                              {                              armMotor                              .                              moveVoltage                              (                              0                              );                              }                              else                              {                              // Else, the arm isn't all the way down                              if                              (                              armUpButton                              .                              isPressed                              ())                              {                              armMotor                              .                              moveVoltage                              (                              12000                              );                              }                              else                              if                              (                              armDownButton                              .                              isPressed                              ())                              {                              armMotor                              .                              moveVoltage                              (                              -                              12000                              );                              }                              else                              {                              armMotor                              .                              moveVoltage                              (                              0                              );                              }                              }                              // Run the examination autonomous routine if we press the button                              if                              (                              runAutoButton                              .                              changedToPressed                              ())                              {                              // Drive the robot in a square design using airtight-loop control                              for                              (                              int                              i                              =                              0                              ;                              i                              <                              4                              ;                              i                              ++                              )                              {                              drive                              .                              moveDistance                              (                              12                              _in                              );                              // Drive forward 12 inches                              bulldoze                              .                              turnAngle                              (                              xc                              _deg                              );                              // Turn in place 90 degrees                              }                              }                              // Expect and requite up the time we don't demand to other tasks.                              // Additionally, joystick values, motor telemetry, etc. all updates every 10 ms.                              pros                              ::                              delay                              (                              x                              );                              }                              }