From 9a0e265a648ca1b80a52e2b98869bd3299963f8b Mon Sep 17 00:00:00 2001 From: Elizabeth Moore Date: Tue, 21 Aug 2018 10:33:15 -0700 Subject: [PATCH] Add installation, remove old file --- PrecisionServo/ServoManagerold.cpp.txt | 162 ------------------------- README.md | 4 + 2 files changed, 4 insertions(+), 162 deletions(-) delete mode 100644 PrecisionServo/ServoManagerold.cpp.txt diff --git a/PrecisionServo/ServoManagerold.cpp.txt b/PrecisionServo/ServoManagerold.cpp.txt deleted file mode 100644 index 74b5558..0000000 --- a/PrecisionServo/ServoManagerold.cpp.txt +++ /dev/null @@ -1,162 +0,0 @@ -#include - -#define MICROSECONDS_PER_TCNT0_CYCLE 256 -#define MICROSECONDS_PER_DELAY_1 3 -#define MICROSECONDS_PER_DELAY_2 4 - -#define MICROSECONDS_PER_SERVO_UPDATE 20000 - -// The maximum number of degrees that we ask the servo to move at once -// higher values -> faster, less accurate movement -#define MAX_MOVEMENT 2 - -// The number of times we send our orders to the servo when we change its -// angle by max movement. Each iteration is roughly 20ms -#define MOVEMENT_ITERATIONS 2 - -// The extra iterations we do when changing directions (each is roughly 20ms) -#define NEW_DIRECTION_ADDITIONAL_ITERATIONS 2 - -// The number of microseconds of ON per 20ms to get the servo to go to 180 -#define MICROSECONDS_FOR_180 2040 - -// The number of microseconds of ON per 20ms to get the servo to go to 0 -#define MICROSECONDS_FOR_0 200 - -int8_t sign(int16_t num) { - if(num < 0) { - return -1; - }else if(num == 0) { - return 0; - }else { - return 1; - } -} - -/** - * Stores how many microseconds before we should send information - * to the servos - */ -static uint32_t microsecondsUntilNextCycle = 0; -static bool currentlyUpdatingServos = false; -static PrecisionServo* servos = NULL; -static uint8_t numServos = 0; -static uint8_t totalServos = 0; - -// TODO REMOVE -static int8_t blueLed = 1; -static int8_t greenLed = 2; -static int8_t redLed = 3; -// END TODO - -void ServoManager::setup(uint8_t totServos) { - // TIMSK - Timer/Counter Interrupt Mask Register - // OCIE0A - Timer/Counter0 Output Compare Match A Interrupt Enable - // TOIE0 - Timer/Counter0 Overflow Interrupt Enable - TIMSK |= _BV(TOIE1); - - if(totServos <= 0) { - // ideally we'd raise an error - totalServos = -1; - return; - } - - servos = (PrecisionServo*)malloc(sizeof(PrecisionServo) * totServos); - numServos = 0; - totalServos = totServos; - - pinMode(blueLed, OUTPUT); - pinMode(greenLed, OUTPUT); - pinMode(redLed, OUTPUT); - // enable global interrupts - sei(); -} - -PrecisionServo* ServoManager::createServo(uint8_t pin) { - if(numServos >= totalServos) - return NULL; // ideally we'd raise an error - - PrecisionServo* newServo = (servos + sizeof(PrecisionServo) * numServos); - numServos++; - - pinMode(pin, OUTPUT); - newServo->pin = pin; - newServo->angleDegrees = 0; - newServo->targetAngleDegrees = 0; - newServo->iterationsLeftOnCurrentIncrement = 10; - newServo->lastDirection = 0; - return newServo; -} - -void ServoManager::waitUntilFinished() { - // todo -} - -void updateServos() { - // first we busywait until we use up the remaining microseconds - delayMicroseconds(microsecondsUntilNextCycle); - - uint32_t usedMicroseconds = 0; - // now we update the servos one at a time - for(int8_t servoIndex = 0; servoIndex < numServos; servoIndex++) { - PrecisionServo* servo = (servos + sizeof(PrecisionServo) * servoIndex); - if(servo->iterationsLeftOnCurrentIncrement == 0) { - if(servo->angleDegrees != servo->targetAngleDegrees) { - int8_t directionRaw = (int8_t)((int16_t)servo->targetAngleDegrees - (int16_t)servo->angleDegrees); - int8_t direction = sign(directionRaw); - uint8_t newAngle; - if(directionRaw > -MAX_MOVEMENT && directionRaw < MAX_MOVEMENT) { - newAngle = servo->targetAngleDegrees; - }else { - newAngle = servo->angleDegrees + direction * MAX_MOVEMENT; - } - - uint8_t iters = MOVEMENT_ITERATIONS; - if(direction != servo->lastDirection) { - iters += NEW_DIRECTION_ADDITIONAL_ITERATIONS; - servo->lastDirection = direction; - } - - servo->angleDegrees = newAngle; - servo->iterationsLeftOnCurrentIncrement = iters; - } - } - - if(servo->iterationsLeftOnCurrentIncrement > 0) { - // this servo needs to set its position but we might not have - // reached the start of our cycle yet - int32_t targetMicroseconds = servoIndex * MICROSECONDS_FOR_180; - int32_t busyWaitMicroseconds = targetMicroseconds - usedMicroseconds; - delayMicroseconds(busyWaitMicroseconds); - usedMicroseconds += busyWaitMicroseconds; - - // now we're definitely at the start of our cycle - double percentOf180 = servo->angleDegrees / 180.0; - - busyWaitMicroseconds = (int32_t)(MICROSECONDS_FOR_0 + percentOf180 * (MICROSECONDS_FOR_180 - MICROSECONDS_FOR_0)); - digitalWrite(servo->pin, HIGH); - digitalWrite(greenLed, HIGH); - delayMicroseconds(busyWaitMicroseconds); - usedMicroseconds += busyWaitMicroseconds; - digitalWrite(servo->pin, LOW); - digitalWrite(greenLed, LOW); - servo->iterationsLeftOnCurrentIncrement--; - } - } - - microsecondsUntilNextCycle = MICROSECONDS_PER_SERVO_UPDATE - usedMicroseconds; -} - -ISR(TIM1_OVF_vect) { - if(microsecondsUntilNextCycle > MICROSECONDS_PER_TCNT0_CYCLE) { - digitalWrite(blueLed, LOW); - microsecondsUntilNextCycle -= MICROSECONDS_PER_TCNT0_CYCLE; - } - - if(microsecondsUntilNextCycle <= MICROSECONDS_PER_TCNT0_CYCLE && !currentlyUpdatingServos) { - digitalWrite(blueLed, HIGH); - currentlyUpdatingServos = true; - updateServos(); - currentlyUpdatingServos = false; - } -} diff --git a/README.md b/README.md index 89a2ab6..ebf5b29 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,10 @@ void loop() { } ``` +## Installation + +Download the source (clone/download button or go to releases). Extract the zip anywhere, copy the "PrecisionServo" folder into "Documents/Arduino/libraries" such that "Documents/Arduino/libraries/PrecisionServo/PrecisionServo.h" is a file. + ## Usage explained The servo manager should be setup with the number of unique servos on the circuit first, with `ServoManager::setup`. Then, create each servo one at a time by calling `ServoManager::createServo` with the corresponding pin. The returned servo is ready to go, however you might want to change the setting (see Settings below) using `PrecisionServo->setSetting`. Every servo may have its own setting.