From eba49d17e7edd0efde6844d8dac6b630c0e87f4c Mon Sep 17 00:00:00 2001 From: Tim Hendriks Date: Thu, 1 Feb 2024 21:03:13 +0100 Subject: [PATCH] add scene reset logic --- examples/MultiplePCA9685/MultiplePCA9685.ino | 22 ++++++++++--------- examples/MultipleScenes/MultipleScenes.ino | 4 ++-- examples/MultipleScenes/README.md | 6 ++--- examples/SerialLiveMode/SerialLiveMode.ino | 1 + .../SwitchModeButton/SwitchModeButton.ino | 17 +++++++------- src/internal/Animation.cpp | 1 + src/internal/AnimationData.cpp | 9 ++++++++ src/internal/AnimationData.h | 1 + src/internal/Scene.cpp | 16 +++++++------- src/internal/Scene.h | 1 + src/internal/ServoManager.cpp | 14 +++++------- src/internal/ServoManager.h | 4 +++- 12 files changed, 55 insertions(+), 41 deletions(-) diff --git a/examples/MultiplePCA9685/MultiplePCA9685.ino b/examples/MultiplePCA9685/MultiplePCA9685.ino index 4b03691..fc53f11 100644 --- a/examples/MultiplePCA9685/MultiplePCA9685.ino +++ b/examples/MultiplePCA9685/MultiplePCA9685.ino @@ -43,18 +43,20 @@ const byte servoAmount = sizeof(servoMappings) / sizeof(servoMappings[0]); void setPWM(byte servoID, int position) { // Iterate through the available servos for (int i = 0; i < servoAmount; i++) { - // Check if the current servo ID matches the target servo ID - if (servoMappings[i].id == servoID) { - // Get the PWM driver instance and channel from the mapping - Adafruit_PWMServoDriver pwm = servoMappings[i].pwm; - byte channel = servoMappings[i].channel; + // Continue if the current servo ID doesn't match the target servo ID + if (servoMappings[i].id != servoID) { + continue; + } - // Set the current position as PWM output - pwm.setPWM(channel, 0, position); + // Get the PWM driver instance and channel from the mapping + Adafruit_PWMServoDriver pwm = servoMappings[i].pwm; + byte channel = servoMappings[i].channel; - // Break the for loop as we already handled the servo movement - break; - } + // Set the current position as PWM output + pwm.setPWM(channel, 0, position); + + // Break the for loop as we finsihed handling the servo movement + break; } } diff --git a/examples/MultipleScenes/MultipleScenes.ino b/examples/MultipleScenes/MultipleScenes.ino index c6c6782..d378d55 100644 --- a/examples/MultipleScenes/MultipleScenes.ino +++ b/examples/MultipleScenes/MultipleScenes.ino @@ -1,5 +1,5 @@ /* - Setting up a show consisting of 2 animations. + Setting up an animation consisting of 2 scenes. Note the namespaces which are used to distinguish the positions of one scene / animation from another. It's even possible to @@ -41,7 +41,7 @@ void setup() { animation.addScene(SceneB::ANIMATION_DATA, SceneB::LENGTH, SceneB::FPS, SceneB::FRAMES); - // Trigger the show loop mode + // Trigger the animation loop mode animation.loop(); // There are also other playback options diff --git a/examples/MultipleScenes/README.md b/examples/MultipleScenes/README.md index 2619f9f..882585d 100644 --- a/examples/MultipleScenes/README.md +++ b/examples/MultipleScenes/README.md @@ -1,7 +1,7 @@ -# Show +# Multiple scenes -Setting up a show consisting of 2 animations. +Setting up an animation consisting of 2 scenes. -By default, the 2 animations will be played synchronously in a loop. +By default, the 2 scenes will be played synchronously in a loop. ![Arduino Nano with servo](../../images/arduino-nano-with-servo.png) diff --git a/examples/SerialLiveMode/SerialLiveMode.ino b/examples/SerialLiveMode/SerialLiveMode.ino index a7a56c6..e128845 100644 --- a/examples/SerialLiveMode/SerialLiveMode.ino +++ b/examples/SerialLiveMode/SerialLiveMode.ino @@ -27,6 +27,7 @@ void move(byte servoID, int position) { BlenderServoAnimation::Animation animation; void setup() { + // Initialize serial communication Serial.begin(115200); // Attach the servo to pin 12 diff --git a/examples/SwitchModeButton/SwitchModeButton.ino b/examples/SwitchModeButton/SwitchModeButton.ino index 3d7de7a..1e77914 100644 --- a/examples/SwitchModeButton/SwitchModeButton.ino +++ b/examples/SwitchModeButton/SwitchModeButton.ino @@ -12,7 +12,7 @@ based on the current mode. Starting the animation will only play it once, so another button press is - required to play it again. Alternatively, you can also use MODE_LOOP instead + required to play it again. Alternatively, you can use MODE_LOOP instead of MODE_PLAY and loop() instead of play(). This will keep the animation running until the button is short or long pressed again, thus pausing or stopping the animation. @@ -53,6 +53,9 @@ void modeChanged(byte prevMode, byte newMode) { case BlenderServoAnimation::Animation::MODE_PAUSE: // E.g. pause audio break; + case BlenderServoAnimation::Animation::MODE_STOP: + // E.g. stop audio + break; } } @@ -80,15 +83,8 @@ void onPressed() { void onLongPressed() { // Get the current mode, act accordingly and trigger another mode switch (animation.getMode()) { - // On long press in default mode, we want to trigger the live mode - case BlenderServoAnimation::Animation::MODE_DEFAULT: - animation.live(Serial); - break; - // On long press in any other mode, we want to stop the animation + // On long press in play, pause or live mode, we want to stop the animation case BlenderServoAnimation::Animation::MODE_PLAY: - case BlenderServoAnimation::Animation::MODE_PLAY_SINGLE: - case BlenderServoAnimation::Animation::MODE_PLAY_RANDOM: - case BlenderServoAnimation::Animation::MODE_LOOP: case BlenderServoAnimation::Animation::MODE_PAUSE: animation.stop(); break; @@ -103,6 +99,9 @@ void setup() { modeButton.attachClick(onPressed); modeButton.attachLongPressStart(onLongPressed); + // Set the position callback + animation.onPositionChange(move); + // Add a scene based on PROGMEM data animation.addScene(ANIMATION_DATA, LENGTH, FPS, FRAMES); diff --git a/src/internal/Animation.cpp b/src/internal/Animation.cpp index 2b2aaf2..00c452a 100644 --- a/src/internal/Animation.cpp +++ b/src/internal/Animation.cpp @@ -68,6 +68,7 @@ void Animation::setScene(byte index) { this->playIndex = index; this->scene = scene; + this->scene->reset(); if (this->sceneCallback) { this->sceneCallback(prevIndex, index); diff --git a/src/internal/AnimationData.cpp b/src/internal/AnimationData.cpp index f9422b9..0836dc1 100644 --- a/src/internal/AnimationData.cpp +++ b/src/internal/AnimationData.cpp @@ -60,3 +60,12 @@ void AnimationData::writeByte(byte value) { this->writeIndex = 0; } } + +void AnimationData::reset() { + if (this->data) { + this->dataPosition = 0; + } else { + this->readIndex = 0; + this->writeIndex = 0; + } +} diff --git a/src/internal/AnimationData.h b/src/internal/AnimationData.h index 2ce81e7..0758c9e 100644 --- a/src/internal/AnimationData.h +++ b/src/internal/AnimationData.h @@ -19,6 +19,7 @@ class AnimationData { byte getNextByte(); void writeByte(byte value); + void reset(); private: static const byte BUFFER_SIZE = 64; diff --git a/src/internal/Scene.cpp b/src/internal/Scene.cpp index 9e4ee34..957029e 100644 --- a/src/internal/Scene.cpp +++ b/src/internal/Scene.cpp @@ -32,12 +32,7 @@ void Scene::play(unsigned long currentMicros) { } this->lastMicros = currentMicros; - - if (this->frame >= this->frames) { - this->frame = 0; - } else { - this->frame++; - } + this->frame++; if (this->frame % this->fps == 0) { this->lastMicros += this->diffPerSecond; @@ -55,10 +50,15 @@ void Scene::stop(unsigned long currentMicros) { this->servoManager->moveAllTowardsNeutral(); if (this->servoManager->servosAreAllNeutral()) { - this->frame = 0; + this->reset(); } } +void Scene::reset() { + this->frame = 0; + this->data->reset(); +} + unsigned int Scene::getMicrosDiff(unsigned long currentMicros) { if (currentMicros >= this->lastMicros) { return currentMicros - this->lastMicros; @@ -73,7 +73,7 @@ bool Scene::isNewFrame(unsigned long currentMicros) { } bool Scene::hasFinished() { - return this->frame == this->frames; + return this->frame + 1 == this->frames; } byte Scene::getFPS() { diff --git a/src/internal/Scene.h b/src/internal/Scene.h index 73d5c2c..4559073 100644 --- a/src/internal/Scene.h +++ b/src/internal/Scene.h @@ -15,6 +15,7 @@ class Scene { void play(unsigned long currentMicros); void stop(unsigned long currentMicros); + void reset(); bool hasFinished(); diff --git a/src/internal/ServoManager.cpp b/src/internal/ServoManager.cpp index 874f75a..e84e8c7 100644 --- a/src/internal/ServoManager.cpp +++ b/src/internal/ServoManager.cpp @@ -39,8 +39,6 @@ void ServoManager::parseData(AnimationData *data, bool considerLineBreaks) { return; } - Command command; - while (data->isAvailable()) { byte value = data->getNextByte(); @@ -48,19 +46,19 @@ void ServoManager::parseData(AnimationData *data, bool considerLineBreaks) { break; } - command.write(value); + this->command.write(value); - this->handleCommand(command); + this->handleCommand(); } } -void ServoManager::handleCommand(Command command) { - if (!command.isValid()) { +void ServoManager::handleCommand() { + if (!this->command.isValid()) { return; } - byte id = command.getServoID(); - int position = command.getServoPosition(); + byte id = this->command.getServoID(); + int position = this->command.getServoPosition(); if (!this->servos[id]) { this->addServo(id); diff --git a/src/internal/ServoManager.h b/src/internal/ServoManager.h index bb35fcc..1c4ee36 100644 --- a/src/internal/ServoManager.h +++ b/src/internal/ServoManager.h @@ -28,13 +28,15 @@ class ServoManager { Servo *servos[MAX_SERVO_COUNT] = {nullptr}; + Command command; + pcb positionCallback = nullptr; byte defaultThreshold = 0; byte thresholds[MAX_SERVO_COUNT] = {0}; void addServo(byte id); - void handleCommand(Command command); + void handleCommand(); }; } // namespace BlenderServoAnimation