Skip to content

Commit a8c8cd4

Browse files
committed
add loop mode
1 parent a597fc6 commit a8c8cd4

File tree

8 files changed

+232
-90
lines changed

8 files changed

+232
-90
lines changed

src/BlenderServoAnimation.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ void Animation::changeMode(byte mode) {
4141
void Animation::run(unsigned long currentMicros) {
4242
switch (mode) {
4343
case MODE_PLAY:
44+
case MODE_LOOP:
4445
this->handlePlayMode(currentMicros);
4546
break;
4647
case MODE_STOP:
@@ -74,7 +75,15 @@ void Animation::handlePlayMode(unsigned long currentMicros) {
7475
Servo *servo = this->servos[i];
7576

7677
if (servo && servo->hasPositions()) {
77-
servo->moveByStep(this->frame);
78+
servo->moveByFrame(this->frame);
79+
}
80+
}
81+
82+
if (this->frame == 0) {
83+
if (this->mode == Animation::MODE_LOOP) {
84+
this->changeMode(Animation::MODE_LOOP);
85+
} else {
86+
this->changeMode(Animation::MODE_DEFAULT);
7887
}
7988
}
8089
}
@@ -132,6 +141,11 @@ void Animation::pause() {
132141
this->changeMode(Animation::MODE_PAUSE);
133142
}
134143

144+
void Animation::loop() {
145+
this->lastMicros = micros();
146+
this->changeMode(Animation::MODE_LOOP);
147+
}
148+
135149
void Animation::stop(byte stepDelay) {
136150
this->stopStepDelay = stepDelay;
137151
this->frame = 0;

src/BlenderServoAnimation.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ class Animation {
3737

3838
public:
3939
static const byte MODE_DEFAULT = 0;
40-
static const byte MODE_PAUSE = 1;
41-
static const byte MODE_PLAY = 2;
42-
static const byte MODE_STOP = 3;
43-
static const byte MODE_LIVE = 4;
40+
static const byte MODE_PLAY = 1;
41+
static const byte MODE_PAUSE = 2;
42+
static const byte MODE_LOOP = 3;
43+
static const byte MODE_STOP = 4;
44+
static const byte MODE_LIVE = 5;
4445

4546
Animation();
4647
Animation(byte fps, int frames);
@@ -50,6 +51,7 @@ class Animation {
5051
void run(unsigned long currentMicros = micros());
5152
void play();
5253
void pause();
54+
void loop();
5355
void stop(byte stepDelay = 20);
5456
void live(Stream &serial);
5557
byte getMode();

src/servo/Servo.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ void Servo::move(int position, bool force) {
3838
this->currentPosition = position;
3939
}
4040

41-
void Servo::moveByStep(int step) {
42-
int newPosition = pgm_read_word_near(this->positions + step);
41+
void Servo::moveByFrame(int frame) {
42+
int newPosition = pgm_read_word_near(this->positions + frame);
4343
this->move(newPosition);
4444
}
4545

src/servo/Servo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class Servo {
2222
Servo(byte id, const int positions[], cb moveCallback, byte threshold = 20);
2323
Servo(byte id, cb moveCallback, byte threshold = 20);
2424
void move(int position, bool force = false);
25-
void moveByStep(int step);
25+
void moveByFrame(int frame);
2626
void moveTowardsNeutral(bool inSteps = true);
2727
bool isNeutral();
2828
bool hasPositions();

test/test_animation/test_animation.cpp

Lines changed: 63 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,6 @@ struct positionLog {
1515

1616
positionLog lastPositions[16];
1717

18-
struct modeLog {
19-
byte prevMode;
20-
byte newMode;
21-
};
22-
23-
byte modeIndex = 0;
24-
modeLog lastModes[10];
25-
2618
void setUp(void) {
2719
for (int id = 0; id < 16; id++) {
2820
lastPositions[id].index = 0;
@@ -31,13 +23,6 @@ void setUp(void) {
3123
lastPositions[id].positions[i] = 0;
3224
}
3325
}
34-
35-
for (int i = 0; i < 10; i++) {
36-
lastModes[i].prevMode = 0;
37-
lastModes[i].newMode = 0;
38-
}
39-
40-
modeIndex = 0;
4126
}
4227

4328
void move(byte servoID, int position) {
@@ -46,12 +31,6 @@ void move(byte servoID, int position) {
4631
lastPositions[servoID].index++;
4732
}
4833

49-
void onModeChange(byte prevMode, byte newMode) {
50-
lastModes[modeIndex].prevMode = prevMode;
51-
lastModes[modeIndex].newMode = newMode;
52-
modeIndex++;
53-
}
54-
5534
const int positionsA[5] PROGMEM = {350, 340, 330, 340, 330};
5635
const int positionsB[5] PROGMEM = {250, 240, 230, 240, 230};
5736

@@ -67,48 +46,56 @@ void test_play(void) {
6746
animation.play();
6847
TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode());
6948

70-
int expA[9] = {340, 330, 340, 330, 350, 340, 330, 340, 330};
71-
int expB[9] = {240, 230, 240, 230, 250, 240, 230, 240, 230};
49+
int expA[5] = {340, 330, 340, 330, 350};
50+
int expB[5] = {240, 230, 240, 230, 250};
7251

7352
for (long i = 0; i < FRAME_MICROS * (long)9; i++) {
7453
animation.run(i);
7554
}
7655

77-
for (int i = 0; i < 9; i++) {
56+
for (int i = 0; i < 5; i++) {
7857
TEST_ASSERT_EQUAL(expA[i], lastPositions[1].positions[i]);
7958
TEST_ASSERT_EQUAL(expB[i], lastPositions[2].positions[i]);
8059
TEST_ASSERT_EQUAL(0, lastPositions[3].positions[i]);
8160
}
61+
62+
for (int i = 5; i < 9; i++) {
63+
TEST_ASSERT_EQUAL(0, lastPositions[1].positions[i]);
64+
TEST_ASSERT_EQUAL(0, lastPositions[2].positions[i]);
65+
TEST_ASSERT_EQUAL(0, lastPositions[3].positions[i]);
66+
}
67+
68+
TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode());
8269
}
8370

84-
void test_pause(void) {
71+
void test_pause_play(void) {
8572
Animation animation(FPS, FRAMES);
8673
Servo servo(2, positionsA, move);
8774
animation.addServo(servo);
8875
animation.play();
8976
TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode());
9077

91-
int exp[9] = {340, 330, 340, 330, 350, 340, 330, 340, 330};
78+
int exp[5] = {340, 330, 340, 330, 350};
9279

93-
for (int i = 0; i < 4; i++) {
80+
for (int i = 0; i < 2; i++) {
9481
animation.run(FRAME_MICROS * (long)(i + 1));
9582
TEST_ASSERT_EQUAL(exp[i], lastPositions[2].positions[i]);
9683
}
9784

9885
animation.pause();
9986
TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode());
10087

101-
for (int i = 4; i < 8; i++) {
88+
for (int i = 2; i < 5; i++) {
10289
animation.run(FRAME_MICROS * (long)(i + 1));
10390
TEST_ASSERT_EQUAL(0, lastPositions[2].positions[i]);
10491
}
10592

10693
animation.play();
10794
TEST_ASSERT_EQUAL(Animation::MODE_PLAY, animation.getMode());
10895

109-
for (int i = 8; i < 14; i++) {
96+
for (int i = 5; i < 8; i++) {
11097
animation.run(FRAME_MICROS * (long)(i + 1));
111-
TEST_ASSERT_EQUAL(exp[i - 5], lastPositions[2].positions[i - 5]);
98+
TEST_ASSERT_EQUAL(exp[i - 3], lastPositions[2].positions[i - 3]);
11299
}
113100
}
114101

@@ -143,68 +130,71 @@ void test_stop(void) {
143130
TEST_ASSERT_EQUAL(0, animation.getFrame());
144131
}
145132

146-
void test_live(void) {
147-
Animation animation;
148-
SerialMock mock;
133+
void test_loop(void) {
134+
Animation animation(FPS, FRAMES);
149135
Servo servos[] = {
150-
Servo(0, positionsA, move),
151-
Servo(1, move),
136+
Servo(1, positionsA, move),
137+
Servo(2, positionsB, move),
138+
Servo(3, move),
152139
};
153-
animation.addServos(servos, 2);
154-
animation.live(mock);
155-
TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode());
140+
animation.addServos(servos, 3);
141+
TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, animation.getMode());
142+
animation.loop();
143+
TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode());
156144

157-
byte values[20] = {60, 0, 1, 94, 62, 60, 1, 1, 94, 62,
158-
60, 0, 1, 99, 62, 60, 1, 1, 99, 62};
145+
int expA[9] = {340, 330, 340, 330, 350, 340, 330, 340, 330};
146+
int expB[9] = {240, 230, 240, 230, 250, 240, 230, 240, 230};
159147

160-
for (int i = 0; i < 10; i++) {
161-
mock.write(values[i]);
148+
for (long i = 0; i < FRAME_MICROS * (long)9; i++) {
149+
animation.run(i);
162150
}
163151

164-
animation.run();
165-
166-
TEST_ASSERT_EQUAL(0, lastPositions[0].positions[0]);
167-
TEST_ASSERT_EQUAL(350, lastPositions[1].positions[0]);
168-
169-
for (int i = 10; i < 20; i++) {
170-
mock.write(values[i]);
152+
for (int i = 0; i < 9; i++) {
153+
TEST_ASSERT_EQUAL(expA[i], lastPositions[1].positions[i]);
154+
TEST_ASSERT_EQUAL(expB[i], lastPositions[2].positions[i]);
155+
TEST_ASSERT_EQUAL(0, lastPositions[3].positions[i]);
171156
}
172157

173-
animation.run();
174-
175-
TEST_ASSERT_EQUAL(355, lastPositions[0].positions[0]);
176-
TEST_ASSERT_EQUAL(355, lastPositions[1].positions[1]);
158+
TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode());
177159
}
178160

179-
void test_mode_change(void) {
180-
SerialMock mock;
161+
void test_pause_loop(void) {
181162
Animation animation(FPS, FRAMES);
163+
Servo servo(2, positionsA, move);
164+
animation.addServo(servo);
165+
animation.loop();
166+
TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode());
182167

183-
animation.onModeChange(onModeChange);
168+
int exp[9] = {340, 330, 340, 330, 350, 340, 330, 340, 330};
169+
170+
for (int i = 0; i < 4; i++) {
171+
animation.run(FRAME_MICROS * (long)(i + 1));
172+
TEST_ASSERT_EQUAL(exp[i], lastPositions[2].positions[i]);
173+
}
184174

185-
animation.play();
186-
TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, lastModes[0].prevMode);
187-
TEST_ASSERT_EQUAL(Animation::MODE_PLAY, lastModes[0].newMode);
188175
animation.pause();
189-
TEST_ASSERT_EQUAL(Animation::MODE_PLAY, lastModes[1].prevMode);
190-
TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, lastModes[1].newMode);
191-
animation.stop();
192-
TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, lastModes[2].prevMode);
193-
TEST_ASSERT_EQUAL(Animation::MODE_STOP, lastModes[2].newMode);
194-
animation.run();
195-
TEST_ASSERT_EQUAL(Animation::MODE_STOP, lastModes[3].prevMode);
196-
TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, lastModes[3].newMode);
197-
animation.live(mock);
198-
TEST_ASSERT_EQUAL(Animation::MODE_DEFAULT, lastModes[4].prevMode);
199-
TEST_ASSERT_EQUAL(Animation::MODE_LIVE, lastModes[4].newMode);
176+
TEST_ASSERT_EQUAL(Animation::MODE_PAUSE, animation.getMode());
177+
178+
for (int i = 4; i < 8; i++) {
179+
animation.run(FRAME_MICROS * (long)(i + 1));
180+
TEST_ASSERT_EQUAL(0, lastPositions[2].positions[i]);
181+
}
182+
183+
animation.loop();
184+
TEST_ASSERT_EQUAL(Animation::MODE_LOOP, animation.getMode());
185+
186+
for (int i = 8; i < 14; i++) {
187+
animation.run(FRAME_MICROS * (long)(i + 1));
188+
TEST_ASSERT_EQUAL(exp[i - 5], lastPositions[2].positions[i - 5]);
189+
}
200190
}
201191

202192
int main(int argc, char **argv) {
203193
UNITY_BEGIN();
204194
RUN_TEST(test_play);
205-
RUN_TEST(test_pause);
195+
RUN_TEST(test_pause_play);
206196
RUN_TEST(test_stop);
207-
RUN_TEST(test_live);
208-
RUN_TEST(test_mode_change);
197+
RUN_TEST(test_loop);
198+
RUN_TEST(test_pause_loop);
209199
UNITY_END();
210200
}

test/test_live/test_live.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#include "../SerialMock.h"
2+
#include "BlenderServoAnimation.h"
3+
#include <unity.h>
4+
5+
using namespace BlenderServoAnimation;
6+
7+
#define FPS 60
8+
#define FRAMES 5
9+
10+
struct positionLog {
11+
int index;
12+
int positions[20];
13+
};
14+
15+
positionLog lastPositions[16];
16+
17+
void setUp(void) {
18+
for (int id = 0; id < 16; id++) {
19+
lastPositions[id].index = 0;
20+
21+
for (int i = 0; i < 20; i++) {
22+
lastPositions[id].positions[i] = 0;
23+
}
24+
}
25+
}
26+
27+
void move(byte servoID, int position) {
28+
int index = lastPositions[servoID].index;
29+
lastPositions[servoID].positions[index] = position;
30+
lastPositions[servoID].index++;
31+
}
32+
33+
const int positionsA[5] PROGMEM = {350, 340, 330, 340, 330};
34+
const int positionsB[5] PROGMEM = {250, 240, 230, 240, 230};
35+
36+
void test_live(void) {
37+
Animation animation;
38+
SerialMock mock;
39+
Servo servos[] = {
40+
Servo(0, positionsA, move),
41+
Servo(1, move),
42+
};
43+
animation.addServos(servos, 2);
44+
animation.live(mock);
45+
TEST_ASSERT_EQUAL(Animation::MODE_LIVE, animation.getMode());
46+
47+
byte values[20] = {60, 0, 1, 94, 62, 60, 1, 1, 94, 62,
48+
60, 0, 1, 99, 62, 60, 1, 1, 99, 62};
49+
50+
for (int i = 0; i < 10; i++) {
51+
mock.write(values[i]);
52+
}
53+
54+
animation.run();
55+
56+
TEST_ASSERT_EQUAL(0, lastPositions[0].positions[0]);
57+
TEST_ASSERT_EQUAL(350, lastPositions[1].positions[0]);
58+
59+
for (int i = 10; i < 20; i++) {
60+
mock.write(values[i]);
61+
}
62+
63+
animation.run();
64+
65+
TEST_ASSERT_EQUAL(355, lastPositions[0].positions[0]);
66+
TEST_ASSERT_EQUAL(355, lastPositions[1].positions[1]);
67+
}
68+
69+
int main(int argc, char **argv) {
70+
UNITY_BEGIN();
71+
RUN_TEST(test_live);
72+
UNITY_END();
73+
}

0 commit comments

Comments
 (0)