Preseason Lesson5: Difference between revisions

From 1511Wookiee
Jump to navigationJump to search
No edit summary
No edit summary
Line 1: Line 1:
<div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><div class="mw-parser-output"><span style="font-size: large;">'''Read encoder while&nbsp;motor moves'''</span></div> <div class="mw-parser-output">
= Goal =
The goal is to read an enocder while a motor is turning. Stop the motor after it turns one revolution. You will also print the encoder's value to the Driver Station.
The goal of this lesson is to read an encoder while a motor is turning and use it to stop the motor after turns a specific amount. Encoders are sensors that can count revolutions;  this can be used to determine a distance of travel of whatever the motor is powering.  Some encoders can sense direction of revolution as well as amount of rotation.


You will use a different motor (called a window&nbsp;motor), because that one has the encoder attached to it.
== Detailed Introduction ==
* Before starting this lesson,  you should have completed [[Preseason Lesson4|Lesson 4]] have that code available.  Use it as a starting point for this lesson.
* We will keep all existing code we did in prior lessons in place and add entirely new code for this lesson.
* A new motor connected to a new type of motor controller, a Jaguar, will be used for this lesson.
* The encoder we will use for this lesson is connected directly to the motor's output shaft.  This is good for our testing here, but in a typical use on a robot it might be connected to a wheel or other mechanism to sense the movement of the system directly rather than the direct rotation of the motor.


&nbsp;
== Detailed Goals ==
* When '''button 2''' on the controller (the one we used in Lessons 2 and 3, not the joystick from lesson 4) is pressed, you will spin the motor for exactly one revolution.
** '''We only want to start ONE revolution turn when the button is initially pressed down!'''
** Put another way -- if you press and hold the button, it should do one complete revolution turn no matter how long the button is held
* The motor to use is on a secondary board to the main test board.
** The motor is powered by a new type of motor controller, a Jaguar.
** The Jaguar is wired to a PWM port on the roborio.  '''The ID for the PWM port controlling the Jaguar and motor we want is number 2'''
* You can see the encoder sensor we will use mounted on top of the motor.
** The encoder is a quadrature encoder which means it can track both direction and distance/revolutions
** This type of encoder will register 256 counts per full revolution
** The encoder is connected to the RoboRIO on '''two digital input ports'' numbered 4 and 5
* When turning the motor to achieve the rotation, you can spin the motor at any speed you like -- this particular motor spins very slowly even at full speed.


It is expected that you completed [http://penfieldrobotics.com/wiki/Preseason%20Lesson4 <font color="#0066cc">Lesson 4</font>] and have the code available.
= Guided Help =
== Create Jaguar motor controller ==
* The class you will use to talk to the Jaguar motor controller is "frc::Jaguar".  It is part of WPILib and is defined in the header file ''frc/jaguar.h''
* Create a Jaguar object to use to control the motor in your Robot class (robot.h).  Do this similar to how you created other objects in past lessons.  Remember the ID of the Jaguar we want to use is 2.
** You can name your motor controller object whatever you like; these instructions will refer to it as "jagMotor".


&nbsp;
== Create Encoder object ==
* To read the encoder, we will use the "frc::Encoder" class.  This is part of WPILib and is defined in ''frc/Encoder.h''.
** Here is [https://first.wpi.edu/FRC/roborio/release/docs/cpp/classfrc_1_1Encoder.html the documentation for the encoder class]]
** Look at the constructor for the Encoder class.  You will see that it needs at least '''two arguments ''', an integer ID representing "channel a" and "channel b".  This is the numeric (int) identifiers for the two digital inputs that the encoder is connected to.
** Supply both IDs when you create your encoder object.
** You can name your encoder whatever you like; these instructions will refer to it as "encoder".


Link to the encoder documentation: [https://first.wpi.edu/FRC/roborio/release/docs/cpp/classfrc_1_1Encoder.html Encoder]
== Tracking if we are mid-rotation or not ==
* We will need to keep track of if we are in the midst of performing a single rotation or not since we are not requiring a consistent user command throughout the motion (not requiring a button to be held down oor other input we can constantly look at.
** This is called keeping track of '''state''
** We can use a bool variable to do this since we have only two states to track -- we are either rotating (true) or not (false)
** However, we '''cannot''' use a local bool variable for this!  Recall that Local variables only keep their value during the code block in which they are declared;  when the block is exited, the variable ceases to exist and loses whatever value it had!
* We can use a variable in our class instead!
** This is just a variable that is declared as part of our class definition, just like our motor controllers and our joystick objects.
** Class variables keep their value as long as the object of the class exists.
** Our class is the Robot class;  our Robot object will exist for the entire run of our program so any variable we put in it will work and keep its current value for the life of the program running
* Declare a bool variable in your Robot class to hold the state of rotating or not.  You can name it whatever you like;  these instructions will use the name "rotationRunning"
** When declaring simple types, you can supply a single argument to give the initial value for the variable
** Since we will not be rotating when the program starts up, we should initialize to '''false'''


An encoder is a counter that increments. The counter goes up the same amount for 1 revolution. Our test board has a 256 count encoder, which means it will count up by 256 for each full revolution. When the robot is powered up, the encoder is not at a know value. You will need to read the value to know where it is starting from.
== Seeing if a button was just pressed on the controller ==
* We will be starting our 1-revolution spin when the button on the controller is pressed down.
* '''We do not want to be constantly restarting our motion if the button is held down!''' This means that we cannot simply use GetRawButton() like in earlier lessons as it does not differentiate between an initial press and the button being held down.
* The Joystick class we are using has a different method - ''GetRawButtonPressed(int button)'' - that can be used to see if a button has gone from not pressed to pressed since the last time it was called!
** This method returns bool - true if the button has just been pressed, false if not.
** You will use this in combination with appropriate if statements to decide to start a revolution or not, '''but read the next section before doing this'''


&nbsp;
== Using the Encoder ==
* The encoder simply increments a count as the encoder's shaft is turned (by the motor in our setup).
* The count starts at 0 and goes up by 1 every 1/256th of a revolution - so a full revolution will yield a count of 256.
* Look again at the Encoder documentation for the following notable methods:
** '''Reset()''' is a method that will cause the internal count of the Encoder object to reset back to zero
** '''Get()''' is a method that will return an int that is the current internal count of the encoder.


&nbsp;
== Putting it all together ==
* Begin by looking at the controller. If the button is newly pressed (see above section), you will start a new rotation!
** Set your rotation state to indicate you are in a rotation
** Zero our encoder so we are starting a fresh revolution!
* If you are in a rotation, you will want to check if the rotation has been completed!  Remember this is when a count of 256 or more is achieved.  Use if statements to decide!
** When the rotation is done, set your state to indicate you are no longer rotating
* Control the motor based on if you are mid-rotation
** The previous 2 steps have set up an accurate state of if you are working on a rotation or not.
** You can use that state to set the output to the motor to either run or not


In Robot.h you will need an object/variable that is the encoder. The class/object type is: '''frc::Encoder'''.&nbsp;You will name the objects: '''m_encoder'''.&nbsp;Add this to the&nbsp;'private:' section as you have done for other objects/variables. Pay attention to the parameters for the constructor.
= Testing =
 
* Enable the robot - the motor should not run at all
In Robot.h you will need an object/variable for the window&nbsp;motor. The motor is connected to a Talon, but for 2019 preseason we just move the connector so we could&nbsp;use a Jaguar (like the previous lessons). If the Talon is used, then the class/object type is: TalonSRX. Notice, there is no frc:: in front of it. API documentation is here: [http://www.ctr-electronics.com/downloads/api/cpp/html/classctre_1_1phoenix_1_1motorcontrol_1_1can_1_1_talon_s_r_x.html TalonSRX].&nbsp;You will need to add an include for this at the top of the file (after any existing includes):
* Press button 2 - the motor should turn on then off and stay off after a single revolution
<pre>#include <ctre/Phoenix.h></pre>
* Now press '''and hold down''' button 2. The motor should do '''the same thing as the prior test''' - turn once and stop.
 
* Now repeatedly tap the button over and over. The motor should start a rotation and continue running forever as long as you are tapping the button (since each tap restarts the revolution)
If it doesn't compile, then you will need to install the library for it:
 
*Download&nbsp;from here:&nbsp;[http://www.ctr-electronics.com/control-system/hro.html#product_tabs_technical_resources CTRE Phoenix Toolsuite]
*click the newest ZIP next to "Installer"
*run the exe that is in the ZIP, and follow the prompts
*TBD: need to add this to the VS IDE
 
&nbsp;
 
In Robot.cpp, you will want to get the encoder position and store it in a variable. The variable can be declared at the top of the Robot::OperatorControl() method (i.e. the first line). Refer to the encoder documentation to see what data type Get() returns. You will call Get() and save what it returned into your varaible. You will need two variables: one to store the initial value and one to store the current value.
 
&nbsp;
 
To print out the encoder position to the Driver Station's console, you will&nbsp;use the method 'printf()'.
 
For example: printf("Encoder:&nbsp;%d&nbsp;%d\n", (int)''initialposition'', (int)''currentposition'');
 
The text in the double quotes is want is printed. The first&nbsp;'%d'&nbsp;indicates the first variable&nbsp;parameter (in this example ''initialposition'') is an integer, so it will format the value in ''initialposition'' and print that. The second '%d' indicates the second variable&nbsp;parameter (in this example ''currentposition'') is an integer.&nbsp;The '\n' indicates to print&nbsp;a newline (i.e. like hitting the Enter key when typing to put the cursor on a new line).
 
&nbsp;
 
<span style="color: rgb(231, 76, 60);">declare initial position variable
declare current position variable
get current encoder's initial position</span>
while (IsOperatorControl() && IsEnabled()) {
  if (joystick trigger is pressed) {
      <span style="color: rgb(231, 76, 60);">assign your variable the encoder's current position
      print the encoder's initial and current positions</span>
      if <span style="color: rgb(231, 76, 60);">(encoder has not turned a full revolution)</span> {
          spin <span style="color: rgb(231, 76, 60);">window </span>motor forward<span style="color: rgb(231, 76, 60);"> 0.2</span>
      }
      else {
          stop <span style="color: rgb(231, 76, 60);">window </span>motor
      }
  }
  else {
      stop <span style="color: rgb(231, 76, 60);">window </span>motor
      <span style="color: rgb(231, 76, 60);">re-get current </span><font color="#e74c3c">encoder's initial position</font>
  }
  frc::Wait(0.005);
}
 
&nbsp;
 
&nbsp;
 
After you have modified Robot.h and Robot.cpp, build the project. Once project builds without errors, let instructor know you are ready to try to delpoy and test. Do not deploy until told to.
 
&nbsp;
 
<u><span style="font-size: large;">Test</span></u>
 
#pull trigger and watch the window motor turn
#the motor should stop when the motor has turn one full revolution  
#release the trigger
 
&nbsp;
</div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div>

Revision as of 15:33, 30 December 2021

Goal

The goal of this lesson is to read an encoder while a motor is turning and use it to stop the motor after turns a specific amount. Encoders are sensors that can count revolutions; this can be used to determine a distance of travel of whatever the motor is powering. Some encoders can sense direction of revolution as well as amount of rotation.

Detailed Introduction

  • Before starting this lesson, you should have completed Lesson 4 have that code available. Use it as a starting point for this lesson.
  • We will keep all existing code we did in prior lessons in place and add entirely new code for this lesson.
  • A new motor connected to a new type of motor controller, a Jaguar, will be used for this lesson.
  • The encoder we will use for this lesson is connected directly to the motor's output shaft. This is good for our testing here, but in a typical use on a robot it might be connected to a wheel or other mechanism to sense the movement of the system directly rather than the direct rotation of the motor.

Detailed Goals

  • When button 2 on the controller (the one we used in Lessons 2 and 3, not the joystick from lesson 4) is pressed, you will spin the motor for exactly one revolution.
    • We only want to start ONE revolution turn when the button is initially pressed down!
    • Put another way -- if you press and hold the button, it should do one complete revolution turn no matter how long the button is held
  • The motor to use is on a secondary board to the main test board.
    • The motor is powered by a new type of motor controller, a Jaguar.
    • The Jaguar is wired to a PWM port on the roborio. The ID for the PWM port controlling the Jaguar and motor we want is number 2
  • You can see the encoder sensor we will use mounted on top of the motor.
    • The encoder is a quadrature encoder which means it can track both direction and distance/revolutions
    • This type of encoder will register 256 counts per full revolution
    • The encoder is connected to the RoboRIO on 'two digital input ports numbered 4 and 5
  • When turning the motor to achieve the rotation, you can spin the motor at any speed you like -- this particular motor spins very slowly even at full speed.

Guided Help

Create Jaguar motor controller

  • The class you will use to talk to the Jaguar motor controller is "frc::Jaguar". It is part of WPILib and is defined in the header file frc/jaguar.h
  • Create a Jaguar object to use to control the motor in your Robot class (robot.h). Do this similar to how you created other objects in past lessons. Remember the ID of the Jaguar we want to use is 2.
    • You can name your motor controller object whatever you like; these instructions will refer to it as "jagMotor".

Create Encoder object

  • To read the encoder, we will use the "frc::Encoder" class. This is part of WPILib and is defined in frc/Encoder.h.
    • Here is the documentation for the encoder class]
    • Look at the constructor for the Encoder class. You will see that it needs at least two arguments , an integer ID representing "channel a" and "channel b". This is the numeric (int) identifiers for the two digital inputs that the encoder is connected to.
    • Supply both IDs when you create your encoder object.
    • You can name your encoder whatever you like; these instructions will refer to it as "encoder".

Tracking if we are mid-rotation or not

  • We will need to keep track of if we are in the midst of performing a single rotation or not since we are not requiring a consistent user command throughout the motion (not requiring a button to be held down oor other input we can constantly look at.
    • This is called keeping track of 'state
    • We can use a bool variable to do this since we have only two states to track -- we are either rotating (true) or not (false)
    • However, we cannot use a local bool variable for this! Recall that Local variables only keep their value during the code block in which they are declared; when the block is exited, the variable ceases to exist and loses whatever value it had!
  • We can use a variable in our class instead!
    • This is just a variable that is declared as part of our class definition, just like our motor controllers and our joystick objects.
    • Class variables keep their value as long as the object of the class exists.
    • Our class is the Robot class; our Robot object will exist for the entire run of our program so any variable we put in it will work and keep its current value for the life of the program running
  • Declare a bool variable in your Robot class to hold the state of rotating or not. You can name it whatever you like; these instructions will use the name "rotationRunning"
    • When declaring simple types, you can supply a single argument to give the initial value for the variable
    • Since we will not be rotating when the program starts up, we should initialize to false

Seeing if a button was just pressed on the controller

  • We will be starting our 1-revolution spin when the button on the controller is pressed down.
  • We do not want to be constantly restarting our motion if the button is held down! This means that we cannot simply use GetRawButton() like in earlier lessons as it does not differentiate between an initial press and the button being held down.
  • The Joystick class we are using has a different method - GetRawButtonPressed(int button) - that can be used to see if a button has gone from not pressed to pressed since the last time it was called!
    • This method returns bool - true if the button has just been pressed, false if not.
    • You will use this in combination with appropriate if statements to decide to start a revolution or not, but read the next section before doing this

Using the Encoder

  • The encoder simply increments a count as the encoder's shaft is turned (by the motor in our setup).
  • The count starts at 0 and goes up by 1 every 1/256th of a revolution - so a full revolution will yield a count of 256.
  • Look again at the Encoder documentation for the following notable methods:
    • Reset() is a method that will cause the internal count of the Encoder object to reset back to zero
    • Get() is a method that will return an int that is the current internal count of the encoder.

Putting it all together

  • Begin by looking at the controller. If the button is newly pressed (see above section), you will start a new rotation!
    • Set your rotation state to indicate you are in a rotation
    • Zero our encoder so we are starting a fresh revolution!
  • If you are in a rotation, you will want to check if the rotation has been completed! Remember this is when a count of 256 or more is achieved. Use if statements to decide!
    • When the rotation is done, set your state to indicate you are no longer rotating
  • Control the motor based on if you are mid-rotation
    • The previous 2 steps have set up an accurate state of if you are working on a rotation or not.
    • You can use that state to set the output to the motor to either run or not

Testing

  • Enable the robot - the motor should not run at all
  • Press button 2 - the motor should turn on then off and stay off after a single revolution
  • Now press and hold down button 2. The motor should do the same thing as the prior test - turn once and stop.
  • Now repeatedly tap the button over and over. The motor should start a rotation and continue running forever as long as you are tapping the button (since each tap restarts the revolution)