how to control servo motor with arduino - c++

I saw many many videos on pwn and servo motor coding but can't understand how exactly the servo motor code works in arduino.
my main confusion is what is the exact purpose of delay in the below code.
when we say servo.write(180); doesn't it mean go to 180 degrees?
what is the use of the delay here?
some milliseconds cause the servo to work properly or jitter or vibrate not move or incorrect rotations etc.
include
Servo myservo; // create servo object to control a servo
// twelve servo objects can be created on most boards
int pos = 0; // variable to store the servo position
void setup() {
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
void loop() {
for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(10); // waits 15ms for the servo to reach the position
}

The code attempts to get the servo to move relatively slowly from 0 to 180 degrees. 10 ms times 181 steps equals 1.81 seconds.
Most if not all servos are significantly faster than that if you just move straight from 0 to 180 in one go.
One problem with this code is that you don't know what the servo's initial position is. For instance, if the initial position is 180, it will quickly jump to 0 and then slowly move back to 180.
Also note that most servos are controlled with a signal every 20 ms or so, so changing the signal more often than that could lead to problems (like jitter/vibrations/noise/...).

Related

Delaying Movement of Servo after button press - Arduino

Recently I have been working on a project where the main goal is to move a servo on a model rocket to deploy a parachute. I want to make is so that 10 seconds after I press the button the parachute is released. I have some code for this already but It is not working, as it stops the code completely. Does anyone know how to fix this?
#include <Servo.h>
// constants won't change
const int BUTTON_PIN = 7; // Arduino pin connected to button's pin
const int SERVO_PIN = 9; // Arduino pin connected to servo motor's pin
Servo servo; // create servo object to control a servo
// variables will change:
int angle = 0; // the current angle of servo motor
int lastButtonState; // the previous state of button
int currentButtonState; // the current state of button
void setup() {
Serial.begin(9600); // initialize serial
pinMode(BUTTON_PIN, INPUT_PULLUP); // set arduino pin to input pull-up mode
servo.attach(SERVO_PIN); // attaches the servo on pin 9 to the servo object
servo.write(angle);
currentButtonState = digitalRead(BUTTON_PIN);
}
void loop() {
lastButtonState = currentButtonState; // save the last state
currentButtonState = digitalRead(BUTTON_PIN); // read new state
if(lastButtonState == HIGH && currentButtonState == LOW) {
Serial.println("The button is pressed");
time.delay(10000)
// change angle of servo motor
if(angle == 0)
angle = 90;
else
if(angle == 90)
angle = 0;
// control servo motor arccoding to the angle
servo.write(angle);
}
}
In Arduino, a delay is usually done with delay(10000); (for 10 seconds). I've never seen or heard of the time.delay() function, so that might be the issue. Otherwise the code looks like it should work as you want.
It also might depend on the board you're running it on. I remember having issues using delay() for long periods on an ESP8266 although I'm pretty sure that it is fine for tens of seconds.

Issue with servo motor and potentiometer: not moving when program is inserted into board

This code is meant to utilize a potentiometer to turn a servomotor. When I tried to insert it into the program the servo didn't move at all, and I don't know if it is a result of my board, my wiring, or my code. If anyone could help or provide some assistance to the matter, it would much be appreciated. The board I am using is a Nucleo STM L476RG board and the motor is a micro SG90.
#include "mbed.h"
#include "Servo.h"
#include "iostream"
Servo myservo(D6);
AnalogOut MyPot(A1);
int main() {
float PotReading;
PotReading = MyPot.read();
while(1) {
for(int i=0; i<100; i++) {
myservo.SetPosition(PotReading);
wait(0.01);
}
}
}
Also, the code I was using had this code in the published library servo listed as Servo.h
#ifndef MBED_SERVO_H
#define MBED_SERVO_H
#include "mbed.h"
/** Class to control a servo on any pin, without using pwm
*
* Example:
* #code
* // Keep sweeping servo from left to right
* #include "mbed.h"
* #include "Servo.h"
*
* Servo Servo1(p20);
*
* Servo1.Enable(1500,20000);
*
* while(1) {
* for (int pos = 1000; pos < 2000; pos += 25) {
* Servo1.SetPosition(pos);
* wait_ms(20);
* }
* for (int pos = 2000; pos > 1000; pos -= 25) {
* Servo1.SetPosition(pos);
* wait_ms(20);
* }
* }
* #endcode
*/
class Servo {
public:
/** Create a new Servo object on any mbed pin
*
* #param Pin Pin on mbed to connect servo to
*/
Servo(PinName Pin);
/** Change the position of the servo. Position in us
*
* #param NewPos The new value of the servos position (us)
*/
void SetPosition(int NewPos);
/** Enable the servo. Without enabling the servo won't be running. Startposition and period both in us.
*
* #param StartPos The position of the servo to start (us)
* #param Period The time between every pulse. 20000 us = 50 Hz(standard) (us)
*/
void Enable(int StartPos, int Period);
/** Disable the servo. After disabling the servo won't get any signal anymore
*
*/
void Disable();
private:
void StartPulse();
void EndPulse();
int Position;
DigitalOut ServoPin;
Ticker Pulse;
Timeout PulseStop;
};
#endif
It also had a .cpp file in the same place as it so if anyone needs it as a reference I'll post it as an edit. I will also put the wiring just in case
The servo is an SG90.
The wiring of the board:
The first thing to understand is how the servo motor works. From the data sheet it requires a 50Hz PWM with a pulse width from 1 to 2ms. The pulse width determines the position, so a width of 1ms will position the servo at one end of its travel, a pulse of 2ms will set the position at the other end, and 1.5ms will set the centre position.
Second you need to read the documentation (in the comments) for the Servo class you are using. It even has example code. First you need to instantiate a Servo object (which you have done), then you need to Enable it by setting its pulse interval and initial pulse width (or position):
Servo output( D6 ) ;
output.Enable( 1500, 20000 ) ; // Centre position, 50Hz
Then if you want to read an analogue input, clearly you need an AnalogIn object:
AnalogOut input(A1);
Then you need to understand that a closed-loop control system must continuously read its input to adjust the output. Here you only read the potentiometer once before the control loop, so in the loop it never changes value so the position will not change. Moreover you have an entirely unnecessary inner loop that appears for come from the example code for an entirely different Servo implementation here - that example was not a closed-loop control system - it simply continuously cycles the servo back-and forth over its full range - that is not what you are trying to achieve in this case and it is just cargo cult programming.
In closed-loop control you continuously:
_______
| |
V |
get-input | <repeat>
set-output |
|_______|
Finally you need to understand that the units of the input measurement in this case are not the same as the units of the output setting - they need scaling so that the full scale input range maps to the full scale output range. The mbed AnalogIn class has two read functions; AnalogIn::read() returns a float in the range 0.0 to 1.0 and AnalogIn::read_u16 returns an uint16_t value 0 to 65535. Personally I'd use the integer version, but the STM32F4 parts have a single precision FPU, so the lack of hardware floating point is not an issue in this case - although there are other reasons for avoiding floating point. Then the Servo::setPosition() function takes a position argument in terms of the pulse width, and as explained above this relates to a position scale 0 to 20000 given the suggested initialisation. So you need either:
float set_point = input.read() ;
output.SetPosition( (int)( (set_point * 1000) + 1000 ) ; // Scale to 1 to 2ms
or
uint16_t set_point = input.read_u16() ;
output.SetPosition( ((set_point * 1000) >> 16) + 1000 ) ;
Putting all that together (with a few other refinements):
#include "mbed.h"
#include "Servo.h"
int main()
{
// Hardware parameters
static const int SERVO_FREQ = 50 ; // Hz
static const int SERVO_PERIOD = 1000000 / SERVO_FREQ ; // microseconds
static const int SERVO_MIN = 1000 ; // 1ms in microseconds
static const int SERVO_MAX = 2000 ; // 2ms in microseconds
static const int SERVO_RANGE = SERVO_MAX - SERVO_MIN ;
// I/O configuration
AnalogIn input( A1 ) ;
Servo output( D6 ) ;
output.Enable( SERVO_MIN, SERVO_PERIOD ) ;
// Control loop
for(;;)
{
float set_point = input.read() ; // 0.0 to 1.0
output.SetPosition( set_point * SERVO_RANGE + SERVO_MIN ) ; // 1 to 2ms
wait_us( SERVO_PERIOD ) ; // wait for one complete PWM cycle.
}
}
The fixed point version would have:
uint16_t set_point = input.read_u16() ; // 0 to 2^16
output.SetPosition( ((set_point * SERVO_RANGE) >> 16) // 1 to 2ms
+ SERVO_MIN ) ;
in the loop.
Note that this is not the most elegant Servo class implementation. It is little more than a PWM class. It would be better if the min/max pulse width were passed to the constructor along with the period so that you could just give it a zero to n set-point rather than an absolute pulse width. That way the somewhat arcane output value calculation would be simplified because the Servo class would do that for you with suitable range checks. In fact if the position parameter were a uint16_t and the range 0 to 65535, then all possible input values would be valid and you could pass the output of AnalogIn::read_u16() to it directly so your loop could just contain:
output.SetPosition_u16( input.read_u16() ) ;
wait_us( SERVO_PERIOD ) ;
In other words - get a better Servo class or write your own - this is doing little for you in terms of encapsulating servo control expertise.
Immediate observations
I see five issues right now, ranging from "maybe a problem" to "likely a problem". I was able to make out the pin labels on your photograph, and your pin assignments appear to be correct. Assuming there's no weird wire or voltage issues:
Your analog pin should be an AnalogIn, not an AnalogOut. While AnalogOut has the ability to read, that's used for feedback to make sure that your output is what you expect it to be. Right now, as an AnalogOut, you're actually acting as a voltage source on this pin and setting the voltage instead of measuring the voltage.
You're not calling Servo::Enable. The documentation tells you how to call Servo::Enable. Make sure to call it. You are even required to specify a starting position for the servo, and this will allow you to troubleshoot your output and servo (see troubleshooting later).
AnalogIn::read returns a float between [0.0, 1.0] to represent the ratio between the voltage read on the input line and the system voltage (5V or 3.3V usually). However, Servo::SetPosition expects an integer that represents the length (as an int in microseconds - between 0 and 20,000 in your case) of the positive part of the pulse signal. If you try to pass the result of AnalogIn::read to Servo::SetPosition, then your float will be converted to a 0 (except for the one single rare case when it's 1). You need to translate your analog input into an integer output.
Right now in your code you're only reading the status of the analog input pin at the very start of your program. You enter an infinite loop and never read this analog input again. You can twist that knob to your heart's content but it will never affect the program. You need to read the analog input many times. Move this inside of your loop.
Just a style thing, but you don't need that inner for loop. It doesn't do anything except clutter your code. If you're expecting to use the value of i at some point in the future then leave this in, but otherwise ditch it.
Troubleshooting
Luckily, many systems can be thought of as many boxes (subsystems) with arrows drawn between them. If all the boxes are doing their job correctly and they're plugged into the correct next box, then the entire system as a whole works. Your system looks like this:
+-----+ +-----+ +----------------+ +-------------+ +--------------------+ +-----+ +-------+
| Pot |-->| ADC |-->| AnalogIn::read |-->| Float-to-us |-->| Servo::SetPosition |-->| PWM |-->| Servo |
+-----+ +-----+ +----------------+ +-------------+ +--------------------+ +-----+ +-------+
All together these subsystems form your entire system. If one of these links isn't working correctly, the whole thing won't work correctly. Usually (or at least we like to imagine we will when we have the time), we apply tests to systems and subsystems to make sure that they produce expected output depending on their input. If you apply input to one of those boxes, and the output is what you expect, then that box is good. Give it a green check mark and move to the next one.
Testing for each of these could be something like:
Potentiometer: input: twist the knob, output: the voltage at the middle pin as near system voltage (5V or 3.3V) when turned all the way one way, close to 0 when turned to the opposite end, and has approximately linear progression between the two ends. You'll need a multimeter to measure this.
ADC (analog-to-digital converter): input: some voltage on the input pin. You can vary this by twisting the potentiometer, once you verify that's working. output: this is a little harder because the output is a register in the microcontroller. I don't know what the debugging environment looks like for your hardware, so I can't tell you how to measure this output. You can assume this works and move onto the next one if you don't know how to use the debugger (but you really should learn how to use your hardware's debugger)
AnalogIn::read: input: a register value of the ADC. output: some float between 0.0 and 1.0. We can test the ADC and the AnalogIn::read function at the same time by treating them as one subsystem, with pin voltage as the input and a float value as the output. Again for this you'll need some debugging functionality. Either print statements or a serial connection or a development environment or something.
Float to us conversion: input: a float between 0.0 and 1.0. output: an integer between 0 and 20,000, proportional (or inversely proportional, depending on desired functionality) to the float input. Again, since we're looking at variables, you'll need to use your debugging environment.
Servo::SetPosition input: an integer between 0 and 20,000 representing the duty cycle (high period) of your output pulse width modulated (PWM) signal. output: increasing this number increases the observed duty cycle. Decreasing decreases it. The length of the duty cycle in us is about equal to the set length in code. You'll need an oscilloscope to observe the duty cycle. Alternatively, if your servo is working, then you should see it move when this changes.
Servo: input: a PWM signal. output: an angular position. A 0% duty cycle should be all the way to one extreme, and a 100% duty cycle should be rotated to the other extreme.
Conclusion
Treat your system as a series of subsystems. Test each one independently. You can't expect the next subsystem to "make up for" the inadequacies of the one before it. They all need to work.

How do I get two stepper motors to rotate at the exact same time and in the same direction using only one Arduino Uno?

My current code:
#include <Stepper.h>
const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution
Stepper myStepper(stepsPerRevolution, 3, 4, 5, 6);
Stepper secondStepper(stepsPerRevolution, 8, 9, 10, 11);
void setup() {
// set the speed at 60 rpm:
myStepper.setSpeed(60);
// initialize the serial port:
Serial.begin(9600);
secondStepper.setSpeed(60);
// initialize the serial port:
Serial.begin(9600);
}
void loop() {
// step one revolution in one direction:
Serial.println("clockwise");
myStepper.step(stepsPerRevolution);
Serial.println("clockwise");
secondStepper.step(stepsPerRevolution);
delay(500);
}
I was working on a project involving the above code during a hackathon this past weekend, but I couldn't get the two motors to move simultaneously. I was wondering if anyone on here knew how to do it properly so that I may be better prepared in the future.
I'm using the Arduino IDE, if that matters.
You need a non-blocking step (or start) call that starts the motion and returns immediately. After starting the two motions, you would then wait for an asynchronous callback from each motor indicating that the motion has completed. One thread per motor would work in a straightforward manner. The main thread would wait for both motor threads to complete before proceeding.
Yes, you can wire the both motor in parallel, that how the z axis is controlled on the Ramps 1.4 board!

On and Off Button on Arduino

I'm back with another non-homework related question. I'm playing with an arduino with my brother, and we're trying to attach a button so that when its pressed, his sensor stays on and does what it has to do. When its pressed again it'll do nothing and turn off. Right now when the button is held down it stays on, but when its unpressed it stays off. We're trying to make something that'll continuously take pictures when its thrown off a building. It'll stop with the ultra-sonic sensor reads <= 5. I can't throw myself off the roof top while holding the button XD It's a 2 pin button. Here's the code of what we have right now:
// defines pins numbers
const int trigPin = 9;
const int echoPin = 10;
const int buzzer = 11;
const int ledPin = 13;
const int buttonPin = 2;
// defines variables
long duration;
int distance;
int safetyDistance;
#include <Servo.h>
Servo myservo; // create servo object to control a servo
// twelve servo objects can be created on most boards
int pos = 0; // variable to store the servo position
void setup() {
pinMode(echoPin, INPUT);// Sets the echoPin as an Input
pinMode(buttonPin, INPUT);
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(buzzer, OUTPUT);
pinMode(ledPin, OUTPUT);
Serial.begin(9600); // Starts the serial communication
myservo.attach(8); // attaches the servo on pin 9 to the servo object
}
void loop() {
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(buttonPin, HIGH);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
distance= duration*0.034/2;
safetyDistance = distance;
if (digitalRead(buttonPin) == HIGH)
{
if (safetyDistance <= 5){
digitalWrite(buzzer, HIGH);
digitalWrite(ledPin, HIGH);
}
else{
digitalWrite(buzzer, LOW);
digitalWrite(ledPin, LOW);
for(pos = 0; pos <= 180; pos += 20) // goes from 0 degrees to 180 degrees
{ // in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(10); // waits 15ms for the servo to reach the position
}
for(pos = 180; pos>=0; pos-=2) // goes from 180 degrees to 0 degrees
{
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(10); // waits 15ms for the servo to reach the position
}
}
}
// Prints the distance on the Serial Monitor
Serial.print("Distance: ");
Serial.println(distance);
}
Now, what we're having trouble with is, I understand that there has to be states for the button. But as we were scouring the internet for help we came across terms like debouncing and we just don't understand what that means. We're so close to finally finishing our mini project. The servo is moving fine, the ultrasonic sensor works well. We just need help figuring out this button. Any advice and help would be appreciated as we're both scratching our heads on this one. Thank you!!
--Zane
Normal buttons, like they are used in most project, are doing nothing else but pressing two electrical contacts together, when it is pressed. But - because it's a mechanical action with limited velocity - the level on the pin doesn't simply rise from LOW to HIGH (or vice versa). Instead it changes it's level in the moment the button gets pressed a few times, until the final level is reached. This variation is to fast for a human to see (for example with an attached LED), but slow enough for a microcontroller like the arduino taking notice. So often you have to make sure, that it's really only one button press, even if the level changes a few times in a row. Mostly it is sufficient to add a small timeout, where the button presses aren't recognized by your code (for example 50 ms), or checking a second time for the state of the button after this period. You can check the corresponding Arduino page for an official example of debouncing.
In your code you are only checking directly the state of the button, which is why it turns off, when you release the button. I would try something like this:
boolean program_state = false;
unsigned long debounce_time = 50;
unsigned long debounce_time_stamp=0;
void loop(){
// ultasound measuring code
if(digitalRead(buttonPin) && debounce_time_stamp - millis() > debounce_time){
program_state=!program_state;
debounce_time_stamp = millis();
}
if(program_state){
// distance checking and servo code
}
}
This check - when the button is pressed - if enough time has been bygone since the last recognized press (the amount of time can be adjusted with the variable debounce_time). When a valid press is recognized, the program_state variable is toggled to change the state between the two modes (On and Off).
Notice that with this the code is unresponsive for the time the servo needs to finish one sequence. If you want to have code, that is more responsive, you should consider using the button as an external interrupt (for this look at the examples on the correspondig Arduino page).

PJRC Encoder Object as Property of Another Object

I'm borrowing PJRC's Encoder library to manage a stepper-powered syringe pump I am running off a Sparkfun RedBoard and a BigEasy Driver.
I've been developing the program modularly, defining lower-level classes first and working up from there. It is my desire that higher-level classes take instances of lower classes as properties. In my current nightmare, I'm building a syringe Pump class with Stepper motor and Encoder objects as properties.
I'm organizing the library into a header file and '.cpp' file as recommended by the Arduino Tutorials. The Pump class is declared as follows in 'Pump.h':
#include "Arduino.h"
#include "Stepper.h"
#include "Encoder.h"
#define PUMP_TOP_SPEED 50 // ml/min top pump speed
#define PUMP_ERROR 10 // encoder counts acceptable error
class Pump {
private:
Stepper motor; // object stepper motor
Encoder encoder; // object attached encoder
int countPerRev; // # encoder counts per relovlution
float nominalVolume; // mL nominal syringe volume
float innerDiameter; // cm syringe inner diameter
float shaftLead; // cm driveshaft threading lead distance
float degVolume; // mL effective volume change per degree of rotation
bool state; // boolean T = ready, F = slept
public:
// constructor
Pump(const Stepper& stp, const Encoder& enc, int cpr, float vol, float diam, float lead);
float volume(); // returns nominalVolume
float position(); // returns current pump position in mL
void hold(); // high power state to resist back-pressure
void relax(); // low power state
void pump(float vol, float rate); // pumps the requested volume at requested rate
void release(); // moves the plunger all the way out so syringe can be serviced
void set(); // returns plunger to zero mL
};
The relevant code in 'Pump.cpp' file which I have been testing with is the constructor and the definition of the pump() method, which goes like so:
// constructor
Pump::Pump(const Stepper& stp, const Encoder& enc, int cpr, float vol, float diam, float lead) : motor(stp), encoder(enc), countPerRev(cpr), nominalVolume(vol), innerDiameter(diam), shaftLead(lead) {
// calculate volume per degree
// (diameter^2 / 4) * PI * (lead / 360) = mL / deg
// diam * diam * lead * PI / 360 / 4 = (diam diam lead PI) / 1440
degVolume = innerDiameter * innerDiameter * shaftLead * PI / 1440;
// construct the encoder inside here
/*encoder = new(Encoder(2,3));
// set it to 0
encoder.write(0);*/
}
// pumping function
void Pump::pump(float vol, float rate) {
/*
vol < 0 INFUSE
vol > 0 WITHDRAW
*/
if (rate > PUMP_TOP_SPEED) rate = PUMP_TOP_SPEED; // limit rate
if (!state) hold(); // wake up the motor if it's asleep
// make sure this doesn't push outside of the acceptable range
if (position() + vol <= nominalVolume && position() + vol >= 0) {
// (mL) / (mL/deg) = deg
float degrees = vol / degVolume; // find number of degrees to turn the motor
Serial.print("Looking to turn ");
Serial.print(degrees, DEC);
Serial.print(" degrees at ");
// (count) + (deg) * (count/rev) / (deg/rev) = count
long goal = encoder.read() + degrees * countPerRev / 360; // set target encoder reading
// (mL/min) / (mL/deg) / (deg/rev) = RPM
int rpm = abs(rate) / degVolume / 360; // find RPM to turn the motor
Serial.print(rpm, DEC);
Serial.println(" RPM in full-stepping mode");
Serial.print("Going from encoder count ");
Serial.print(encoder.read(), DEC);
Serial.print(" to ");
Serial.println(goal, DEC);
motor.drive(degrees, 1, rpm); // drive the pump
int err = goal - encoder.read(); // how far from the goal are we in counts?
Serial.print("Reached encoder count ");
Serial.println(encoder.read(), DEC);
Serial.print("Missed by ");
Serial.println(err, DEC);
}
}
I've been testing my pump() method and threw in a whole bunch of Serial.print() to try to debug and figure out what is happening and from what I can see, the Encoder object that is a property of the Pump object doesn't have its position updated as the shaft turns, whereas the Encoder object declared in the Arduino sketch and passed to the Pump constructor does.
As you can see above I've tried to initialize the encoder within the pump constructor but the 2 or 3 things I tried all threw a bunch of cryptic errors in the Arduino IDE when I tried to compile, left that commented out section so you can see what I was trying.
What I find exceedingly annoying is that while my own Stepper object works fine, the Pump object can turn the motor, the Encoder object won't function inside the Pump object. When I run the sketch:
#include <Stepper.h>
#include <Encoder.h>
#include <Pump.h>
// initialize stepper
Stepper motor(4, 5, 6, 7, 8, 9, 10, 11);
// initialize encoder
Encoder encoder(2, 3);
// initialize the pump
Pump pump(motor, encoder, 1440, 25, 2.328, 0.1);
void setup() {
// start the Serial connection
Serial.begin(9600);
// set up the motor
motor.enable();
motor.reset();
// pump
pump.pump(0.25,25);
Serial.print("Pump reading: ");
Serial.println(pump.position(), DEC);
Serial.print("Encoder reading: ");
Serial.println(encoder.read(), DEC);
// cool boards
pump.relax();
}
void loop() {}
I get back the following in the Serial monitor:
Looking to turn 211.4397277832 degrees at 58 RPM in full-stepping mode
Going from encoder count 0 to 845
Reached encoder count 0
Missed by 845
Pump reading: 0.0000000000
Encoder reading: 845
So, the method encoder.read() always returns zero in the Pump object but when I called it at the end of my sketch in the setup() function it turns I turned exactly as far as I wanted to.
Thank you for reading. I'd appreciate guidance on how to either properly pass an active Encoder object to Pump, or how to properly initialize an Encoder object within Pump without freaking out the compiler.
The key was, in-fact, to initialize the encoder within the Pump object, as I've been reading on the Arduino boards posted by people some variant of my issue.
I constructed the encoder within the property declarations of 'Pump.h'. Since the RedBoard I'm working with is an Arduino Uno, in essence, the only acceptable pins are 2 and 3 for interrupts. I declared the encoder with the following line under the class's list of private properties:
Encoder encoder = Encoder(2,3); // attached encoder
And it now works flawlessly. There is likely an option to pass the encoder pins to the Pump constructor and have it be flexible, but for the time being I need something that works more than I need something perfect.