├── README.md ├── code ├── simple │ └── simple.ino ├── puppet │ └── puppet.ino └── sequencer │ └── sequencer.ino └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # ServoSmoothing 2 | 3 | CAD and Code for my simple servo/motion smoothing demo: https://youtu.be/jsXolwJskKM 4 | -------------------------------------------------------------------------------- /code/simple/simple.ino: -------------------------------------------------------------------------------- 1 | int switch1; 2 | float switch1Smoothed; 3 | float switch1Prev; 4 | 5 | void setup() { 6 | 7 | Serial.begin(115200); 8 | 9 | pinMode(12, INPUT_PULLUP); 10 | 11 | } 12 | 13 | void loop() { 14 | 15 | switch1 = digitalRead(12); // read switch 16 | switch1 = switch1 * 100; // multiply by 100 17 | 18 | // *** smoothing *** 19 | 20 | switch1Smoothed = (switch1 * 0.05) + (switch1Prev * 0.95); 21 | 22 | switch1Prev = switch1Smoothed; 23 | 24 | // *** end of smoothing *** 25 | 26 | Serial.print(switch1); // print to serial terminal/plotter 27 | Serial.print(" , "); 28 | Serial.println(switch1Smoothed); 29 | 30 | delay(10); // run loop 100 times/second 31 | 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 James Bruton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/puppet/puppet.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int pot1; 4 | int pot2; 5 | int pot3; 6 | int pot4; 7 | int pot5; 8 | int pot6; 9 | 10 | float pot1Scaled; 11 | float pot2Scaled; 12 | float pot3Scaled; 13 | float pot4Scaled; 14 | float pot4aScaled; 15 | float pot5Scaled; 16 | float pot6Scaled; 17 | 18 | float pot1Smoothed; 19 | float pot2Smoothed; 20 | float pot3Smoothed; 21 | float pot4Smoothed; 22 | float pot4aSmoothed; 23 | float pot5Smoothed; 24 | float pot6Smoothed; 25 | 26 | float pot1SmoothedPrev; 27 | float pot2SmoothedPrev; 28 | float pot3SmoothedPrev; 29 | float pot4SmoothedPrev; 30 | float pot4aSmoothedPrev; 31 | float pot5SmoothedPrev; 32 | float pot6SmoothedPrev; 33 | 34 | Servo servo1; 35 | Servo servo2; 36 | Servo servo3; 37 | 38 | Servo servo4; 39 | Servo servo5; 40 | Servo servo6; 41 | Servo servo7; 42 | 43 | void setup() { 44 | 45 | pinMode(A0, INPUT); 46 | pinMode(A1, INPUT); 47 | pinMode(A2, INPUT); 48 | pinMode(A3, INPUT); 49 | pinMode(A4, INPUT); 50 | pinMode(A5, INPUT); 51 | 52 | Serial.begin(115200); 53 | 54 | servo1.attach(4); 55 | servo2.attach(5); 56 | servo3.attach(6); 57 | 58 | servo4.attach(7); 59 | servo5.attach(8); 60 | servo6.attach(9); 61 | servo7.attach(10); 62 | 63 | servo1.writeMicroseconds(1200); 64 | servo2.writeMicroseconds(1650); 65 | servo3.writeMicroseconds(1650); 66 | 67 | servo4.writeMicroseconds(1500); 68 | servo5.writeMicroseconds(1550); 69 | servo6.writeMicroseconds(1500); 70 | servo7.writeMicroseconds(1450); 71 | 72 | } 73 | 74 | void loop() { 75 | 76 | pot1 = analogRead(A0); 77 | pot2 = analogRead(A1); 78 | pot3 = analogRead(A2); 79 | pot4 = analogRead(A3); 80 | pot5 = analogRead(A4); 81 | pot6 = analogRead(A5); 82 | 83 | // scale all pots for the servo microseconds range 84 | 85 | pot1Scaled = ((pot1 - 512) * -1.6) + 1200; 86 | pot2Scaled = (pot2 - 512) + 1500; 87 | pot3Scaled = (pot3 - 512) + 1500; 88 | pot4Scaled = ((pot4 - 512) * 1.2) + 1500; 89 | pot4aScaled = ((pot4 - 512) * -1.2) + 1500; 90 | pot5Scaled = (pot5 - 512) * 1.5; 91 | pot6Scaled = (pot6 - 512) + 1650; 92 | 93 | pot4Scaled = constrain(pot4Scaled,900,1500); 94 | pot4aScaled = constrain(pot4aScaled,1500,2100); 95 | 96 | // smooth pots 97 | 98 | pot1Smoothed = (pot1Scaled * 0.02) + (pot1SmoothedPrev * 0.98); 99 | pot2Smoothed = (pot2Scaled * 0.02) + (pot2SmoothedPrev * 0.98); 100 | pot3Smoothed = (pot3Scaled * 0.02) + (pot3SmoothedPrev * 0.98); 101 | pot4Smoothed = (pot4Scaled * 0.05) + (pot4SmoothedPrev * 0.95); 102 | pot4aSmoothed = (pot4aScaled * 0.05) + (pot4aSmoothedPrev * 0.95); 103 | pot5Smoothed = (pot5Scaled * 0.02) + (pot5SmoothedPrev * 0.98); 104 | pot6Smoothed = (pot6Scaled * 0.02) + (pot6SmoothedPrev * 0.98); 105 | 106 | // bookmark previous values 107 | 108 | pot1SmoothedPrev = pot1Smoothed; 109 | pot2SmoothedPrev = pot2Smoothed; 110 | pot3SmoothedPrev = pot3Smoothed; 111 | pot4SmoothedPrev = pot4Smoothed; 112 | pot4aSmoothedPrev = pot4aSmoothed; 113 | pot5SmoothedPrev = pot5Smoothed; 114 | pot6SmoothedPrev = pot6Smoothed; 115 | 116 | Serial.print(pot1Smoothed); 117 | Serial.print(" , "); 118 | Serial.print(pot2Smoothed); 119 | Serial.print(" , "); 120 | Serial.print(pot3Smoothed); 121 | Serial.print(" , "); 122 | Serial.print(pot4Smoothed); 123 | Serial.print(" , "); 124 | Serial.print(pot5Smoothed); 125 | Serial.print(" , "); 126 | Serial.println(pot6Smoothed); 127 | 128 | // write servos 129 | 130 | servo1.writeMicroseconds(pot1Smoothed); 131 | servo2.writeMicroseconds(pot6Smoothed - pot5Smoothed); 132 | servo3.writeMicroseconds(pot6Smoothed + pot5Smoothed); 133 | 134 | servo5.writeMicroseconds(pot2Smoothed); 135 | servo7.writeMicroseconds(pot2Smoothed); 136 | 137 | servo4.writeMicroseconds(pot4Smoothed); 138 | servo6.writeMicroseconds(pot4aSmoothed); 139 | 140 | 141 | 142 | delay(5); // run loop 200 times/second 143 | 144 | } 145 | -------------------------------------------------------------------------------- /code/sequencer/sequencer.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int pot1 = 512; 4 | int pot2 = 512; 5 | int pot3 = 512; 6 | int pot4 = 512; 7 | int pot5 = 512; 8 | int pot6 = 512; 9 | 10 | float pot1Scaled; 11 | float pot2Scaled; 12 | float pot3Scaled; 13 | float pot4Scaled; 14 | float pot4aScaled; 15 | float pot5Scaled; 16 | float pot6Scaled; 17 | 18 | float pot1Smoothed = 512; 19 | float pot2Smoothed = 512; 20 | float pot3Smoothed = 512; 21 | float pot4Smoothed = 512; 22 | float pot4aSmoothed = 512; 23 | float pot5Smoothed = 512; 24 | float pot6Smoothed = 512; 25 | 26 | float pot1SmoothedPrev = 512; 27 | float pot2SmoothedPrev = 512; 28 | float pot3SmoothedPrev = 512; 29 | float pot4SmoothedPrev = 512; 30 | float pot4aSmoothedPrev = 512; 31 | float pot5SmoothedPrev = 512; 32 | float pot6SmoothedPrev = 512; 33 | 34 | unsigned long currentMillis; 35 | long previousMillis = 0; // set up timers 36 | long interval = 5; // time constant for timer 37 | 38 | int stepFlag = 0; 39 | long previousStepMillis = 0; 40 | 41 | Servo servo1; 42 | Servo servo2; 43 | Servo servo3; 44 | 45 | Servo servo4; 46 | Servo servo5; 47 | Servo servo6; 48 | Servo servo7; 49 | 50 | void setup() { 51 | 52 | pinMode(A0, INPUT); 53 | pinMode(A1, INPUT); 54 | pinMode(A2, INPUT); 55 | pinMode(A3, INPUT); 56 | pinMode(A4, INPUT); 57 | pinMode(A5, INPUT); 58 | 59 | Serial.begin(115200); 60 | 61 | servo1.attach(4); 62 | servo2.attach(5); 63 | servo3.attach(6); 64 | 65 | servo4.attach(7); 66 | servo5.attach(8); 67 | servo6.attach(9); 68 | servo7.attach(10); 69 | 70 | servo1.writeMicroseconds(1200); 71 | servo2.writeMicroseconds(1650); 72 | servo3.writeMicroseconds(1650); 73 | 74 | servo4.writeMicroseconds(1500); 75 | servo5.writeMicroseconds(1550); 76 | servo6.writeMicroseconds(1500); 77 | servo7.writeMicroseconds(1450); 78 | 79 | } 80 | 81 | void loop() { 82 | 83 | currentMillis = millis(); 84 | if (currentMillis - previousMillis >= interval) { // start 5ms timed loop 85 | previousMillis = currentMillis; 86 | 87 | // step sequencer 88 | 89 | if (stepFlag == 0 && currentMillis - previousStepMillis > 500) { 90 | pot1 = 512; 91 | pot6 = 512; 92 | stepFlag = 1; 93 | previousStepMillis = currentMillis; 94 | } 95 | 96 | else if (stepFlag == 1 && currentMillis - previousStepMillis > 1000) { 97 | pot1 = 1024; 98 | pot2 = 1024; 99 | pot6 = 0; 100 | stepFlag = 2; 101 | previousStepMillis = currentMillis; 102 | } 103 | 104 | else if (stepFlag == 2 && currentMillis - previousStepMillis > 1500) { 105 | pot1 = 0; 106 | pot6 = 1024; 107 | pot2 = 0; 108 | stepFlag = 3; 109 | previousStepMillis = currentMillis; 110 | } 111 | 112 | if (stepFlag == 3 && currentMillis - previousStepMillis > 1500) { 113 | pot5 = 512; 114 | pot6 = 0; 115 | pot2 = 512; 116 | stepFlag = 4; 117 | previousStepMillis = currentMillis; 118 | } 119 | 120 | if (stepFlag == 4 && currentMillis - previousStepMillis > 1500) { 121 | pot4 = 0; 122 | stepFlag = 5; 123 | previousStepMillis = currentMillis; 124 | } 125 | if (stepFlag == 5 && currentMillis - previousStepMillis > 1500) { 126 | pot4 = 512; 127 | stepFlag = 1; 128 | previousStepMillis = currentMillis; 129 | } 130 | 131 | // end of step sequencer 132 | 133 | 134 | 135 | // scale all pots for the servo microseconds range 136 | 137 | pot1Scaled = ((pot1 - 512) * -1.6) + 1200; 138 | pot2Scaled = (pot2 - 512) + 1500; 139 | pot3Scaled = (pot3 - 512) + 1500; 140 | pot4Scaled = ((pot4 - 512) * 1.2) + 1500; 141 | pot4aScaled = ((pot4 - 512) * -1.2) + 1500; 142 | pot5Scaled = (pot5 - 512) * 1.5; 143 | pot6Scaled = (pot6 - 512) + 1650; 144 | 145 | pot4Scaled = constrain(pot4Scaled,900,1500); 146 | pot4aScaled = constrain(pot4aScaled,1500,2100); 147 | 148 | // smooth pots 149 | 150 | pot1Smoothed = (pot1Scaled * 0.01) + (pot1SmoothedPrev * 0.99); 151 | pot2Smoothed = (pot2Scaled * 0.01) + (pot2SmoothedPrev * 0.99); 152 | pot3Smoothed = (pot3Scaled * 0.01) + (pot3SmoothedPrev * 0.99); 153 | pot4Smoothed = (pot4Scaled * 0.05) + (pot4SmoothedPrev * 0.95); 154 | pot4aSmoothed = (pot4aScaled * 0.05) + (pot4aSmoothedPrev * 0.95); 155 | pot5Smoothed = (pot5Scaled * 0.01) + (pot5SmoothedPrev * 0.99); 156 | pot6Smoothed = (pot6Scaled * 0.01) + (pot6SmoothedPrev * 0.99); 157 | 158 | // bookmark previous values 159 | 160 | pot1SmoothedPrev = pot1Smoothed; 161 | pot2SmoothedPrev = pot2Smoothed; 162 | pot3SmoothedPrev = pot3Smoothed; 163 | pot4SmoothedPrev = pot4Smoothed; 164 | pot4aSmoothedPrev = pot4aSmoothed; 165 | pot5SmoothedPrev = pot5Smoothed; 166 | pot6SmoothedPrev = pot6Smoothed; 167 | 168 | Serial.print(pot1Smoothed); 169 | Serial.print(" , "); 170 | Serial.print(pot2Smoothed); 171 | Serial.print(" , "); 172 | Serial.print(pot3Smoothed); 173 | Serial.print(" , "); 174 | Serial.print(pot4Smoothed); 175 | Serial.print(" , "); 176 | Serial.print(pot5Smoothed); 177 | Serial.print(" , "); 178 | Serial.println(pot6Smoothed); 179 | 180 | // write servos 181 | 182 | servo1.writeMicroseconds(pot1Smoothed); // neck rotate 183 | servo2.writeMicroseconds(pot6Smoothed - pot5Smoothed); // neck side-side 184 | servo3.writeMicroseconds(pot6Smoothed + pot5Smoothed); // neck front-back 185 | 186 | servo5.writeMicroseconds(pot2Smoothed); // eyeballs side-side 187 | servo7.writeMicroseconds(pot2Smoothed); 188 | 189 | servo4.writeMicroseconds(pot4Smoothed); // eyelids 190 | servo6.writeMicroseconds(pot4aSmoothed); 191 | 192 | } // end of timed loop 193 | 194 | 195 | } // end if main loop 196 | --------------------------------------------------------------------------------