Recording servo movements

hello, I'm new here and in Arduino, i had just gotten a elegoo Uno r3 starter kit, as it was cheaper compared to the Arduino starter kit, i would like to record servo movements with what is in the kit, i got no SD card module as that is something i have seen other people use, i only have the servo sweep example and have not gone into coding my own code yet, i still need to learn the code, but i have the "pluging wires into things" part down, i would like some help with learning the coding part aswell as figuring out how i could record a servo movement, thanks to anyone who can help

I can appreciate where you’re starting from, but you really need to look into your paragraph structure, and the logic of your post. I’m sure we can help you move in, but the existing word salad isn’t inviting enough.

idk what that even means, i need help recording a string of movments from a pot and replay that on the servos later, i want to record a pot thats moving a servo, and play it later, if that makes it more clear

That’s a good start…so there’s a pot involved.
It might be a little more complicated than it appears, but here’s a plan to start from…

In loop(), read the pot value, then each change you want to record, store the value in an array, along with a millis() timestamp.

Later to replay the sequence, assume a ‘zero’ point, then scan the recorded time stamp array, and when you find a match (a ‘keyframe’j, seek the servo to the new corresponding saved value.
Repeat until you’ve used up all the stored ‘keyframes’

There’s a lot more that can be done, but that might get you going,

1 Like

thanks, i would have no idea where to start tbh, now i got to learn all the code, is there a good example i can follow that you can make or give me? or a good YouTube video i can learn the coding from? the pdf that came with the kit did not explain it very well

I’d suggest simply getting the pot to move the servo.
Next save the keyframes…
then recall the keyframes.

Finally a organise the time sequencing.

how would i go about saving the keyframes, what would the code be and where would i put the code?

You’d save the keyframes times and positions in an array.

The code will come from your mind, probably created in pieces so it doesn’t overwhelm you.

You create the code in a text editor or the IDE, then use the IDE to compile and upload the binary to the processor.

how will the code come from my mind if i still dont know how to code......

You persistently try to skip the initial training. It will not work this way. If you want a ready-made program, you can try the section for paid consultations. If you want to learn and write your own program, for the moment forget your project and start from the basic lessons in the Arduino IDE.

i went through all of them and didnt get the solution to my problems, THEN, i came here to ask for help, i had already joined python discord servers and went through every thing that was free, i have found all these courses that say there free, and 2 steps in it says to go further i need to pay like $100 and i dont wanna spend 100 dollars on somthing that might help me

You will hardly ever find a custom solution. You will have to learn the basics and based on what you learned write the code; if you don't manage, read / learn more :wink:

The below code examples hopefully guide you a little. It does not provide a full solution for what you want to do, I'll leave that to your creativity.

Be aware of the limitations of the amount of memory of an Uno; you only have 2k RAM so you can not store a long recording in RAM.

You will first need to read up on arrays (array - Arduino Reference). The below declares an array of 50 elements; it limited to 50 entries to keep the memory usage low.

// number of frames to record
const uint16_t MAXFRAMES = 50;
// array to store recorded potentiometer values
int values[MAXFRAMES];

You don't want to store constantly but only when the potentiometer value changes. Naturally there can be small variations in the readings and you don't want to record those either; therefore you can use a hysteresis.

The below code does that.

// the pin for the potentiometer
const uint8_t potPin = A0;
// the pin for the LED
const uint8_t ledPin = LED_BUILTIN;
// hysteresis; only record of change is greater than 20
const int hysteresis = 20;

// number of frames to record
const uint16_t MAXFRAMES = 50;
// array to store recorded potentiometer values
int values[MAXFRAMES];


void setup()
{
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  Serial.println(F("Turn the pot"));
}

void loop()
{
  // remember the last potentiometer value
  static int prevPotValue;
  // counter to keep track where to store the recorded potentiometer value
  static uint16_t frameCounter;

  // read the potentiometer
  int potValue = analogRead(potPin);

  // if it differs enough from the previous value
  if (potValue < prevPotValue - hysteresis || potValue > prevPotValue + hysteresis)
  {
    // remember the previous value
    prevPotValue = potValue;
    // record the value
    values[frameCounter] = potValue;
    // next time, store in next location
    frameCounter++;
    // check if the array with potentiometer values is full
    if (frameCounter == MAXFRAMES)
    {
      // indicate to user that array is full
      digitalWrite(ledPin, HIGH);
      
      // display the results
      for(uint16_t cnt = 0; cnt < MAXFRAMES; cnt++)
      {
        Serial.println(values[cnt]);
      }
      
      // hang forever
      for (;;) {}
    }
  }
}

This code records 50 potentiometer values in the array and after that displays the recorded values and stops. When the array is full, the built-in LED will light up as a visual indication.

If you want to save some memory, you can store the servo positions instead of the potentiometer values.

Now you can add the timing. To keep it simple, I used a second array (an array of structs would be better).

// number of frames to record
const uint16_t MAXFRAMES = 50;
// array to store recorded potentiometer values
int values[MAXFRAMES];
// array to store the times when a value was recorded
int32_t times[MAXFRAMES];

The below code uses this approach and stores a delta time when a potentiometer value was recorded.

// the pin for the potentiometer
const uint8_t potPin = A0;
// the pin for the LED
const uint8_t ledPin = LED_BUILTIN;
// hysteresis; only record of change is greater than 20
const int hysteresis = 20;

// number of frames to record
const uint16_t MAXFRAMES = 50;
// array to store recorded potentiometer values
int values[MAXFRAMES];
// array to store the times when a value was recorded
int32_t times[MAXFRAMES];

void setup()
{
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  Serial.println(F("Turn the pot"));
}

void loop()
{
  // remember the last potentiometer value
  static int prevPotValue;
  // counter to keep track where to store the recorded potentiometer value
  static uint16_t frameCounter;
  // remember when you last added a value to the array(s)
  static uint32_t lastRecordingTime;

  // read the potentiometer
  int potValue = analogRead(potPin);

  // if it differs enough from the previous value
  if (potValue < prevPotValue - hysteresis || potValue > prevPotValue + hysteresis)
  {
    // remember the previous value
    prevPotValue = potValue;
    // record the potentiometer value
    values[frameCounter] = potValue;
    // record the time
    times[frameCounter] = millis() - lastRecordingTime;
    // update the time that we did the last recording
    lastRecordingTime = millis();
    // next time, store in next location
    frameCounter++;
    // check if the array with potentiometer values is full
    if (frameCounter == MAXFRAMES)
    {
      // indicate to user that array is full
      digitalWrite(ledPin, HIGH);
      
      // display the results
      for(uint16_t cnt = 0; cnt < MAXFRAMES; cnt++)
      {
        Serial.print(times[cnt]);
        Serial.print(F("\t"));
        Serial.println(values[cnt]);
      }
      
      // hang forever
      for (;;) {}
    }
  }
}

In the next step you can use a struct to combine a value and a delta time.

// number of frames to record
const uint16_t MAXFRAMES = 50;
// struct holding potentiometer value and delta time
struct FRAME
{
  int16_t value;
  uint32_t time;
};
FRAME frames[MAXFRAMES];

A struct (see e.g. C++ Data Structures) is like an entry in a phone book where you combine e.g. a name and a phone number (and possibly other information like address). You access the elements of a struct using the dot as show in below code.

The below code makes use of this

// the pin for the potentiometer
const uint8_t potPin = A0;
// the pin for the LED
const uint8_t ledPin = LED_BUILTIN;
// hysteresis; only record of change is greater than 20
const int16_t hysteresis = 20;

// number of frames to record
const uint16_t MAXFRAMES = 50;
// struct holding potentiometer value and delta time
struct FRAME
{
  int16_t value;
  uint32_t time;
};
FRAME frames[MAXFRAMES];


void setup()
{
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  Serial.println(F("Turn the pot"));
}

void loop()
{
  // remember the last potentiometer value
  static int prevPotValue;
  // counter to keep track where to store the recorded potentiometer value
  static uint16_t frameCounter;
  // remember when you last added a value to the array(s)
  static uint32_t lastRecordingTime;

  // read the potentiometer
  int potValue = analogRead(potPin);

  // if it differs enough from the previous value
  if (potValue < prevPotValue - hysteresis || potValue > prevPotValue + hysteresis)
  {
    // remember the previous value
    prevPotValue = potValue;
    // record the potentiometer value
    frames[frameCounter].value = potValue;
    // record the time
    frames[frameCounter].time = millis() - lastRecordingTime;
    // update the time that we did the last recording
    lastRecordingTime = millis();
    // next time, store in next location
    frameCounter++;
    // check if the array with potentiometer values is full
    if (frameCounter == MAXFRAMES)
    {
      // indicate to user that array is full
      digitalWrite(ledPin, HIGH);
      
      // display the results
      for(uint16_t cnt = 0; cnt < MAXFRAMES; cnt++)
      {
        Serial.print(frames[cnt].time);
        Serial.print(F("\t"));
        Serial.println(frames[cnt].value);
      }
      
      // hang forever
      for (;;) {}
    }
  }
}

This behaves exactly the same as the previous code but is a little neater.

I'll leave the rest of the puzzle up to you. You can use e.g. simple serial commands to start recording ('r') and playback ('p')and so on.

4 Likes

thank you that will help significantly, i will leave the post open just incase i need more help, will let you know if i end up getting it to work, thanks again

ok i added a thing telling the code there is a servo

#include <Servo.h>
Servo headLR;  // create servo object to control a servo

// the pin for the potentiometer
const uint8_t potPin = A0;
// the pin for the LED
const uint8_t ledPin = LED_BUILTIN;
// hysteresis; only record of change is greater than 20
const int16_t hysteresis = 20;

// number of frames to record
const uint16_t MAXFRAMES = 50;
// struct holding potentiometer value and delta time
struct FRAME
{
  int16_t value;
  uint32_t time;
};
FRAME frames[MAXFRAMES];


void setup()
{
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  Serial.println(F("Turn the pot"));
  headLR.attach(9);  // attaches the servo on pin 9 to the servo object
}


void loop()
{
  // remember the last potentiometer value
  static int prevPotValue;
  // counter to keep track where to store the recorded potentiometer value
  static uint16_t frameCounter;
  // remember when you last added a value to the array(s)
  static uint32_t lastRecordingTime;

  // read the potentiometer
  int potValue = analogRead(potPin);

  // if it differs enough from the previous value
  if (potValue < prevPotValue - hysteresis || potValue > prevPotValue + hysteresis)
  {
    // remember the previous value
    prevPotValue = potValue;
    // record the potentiometer value
    frames[frameCounter].value = potValue;
    // record the time
    frames[frameCounter].time = millis() - lastRecordingTime;
    // update the time that we did the last recording
    lastRecordingTime = millis();
    // next time, store in next location
    frameCounter++;
    // check if the array with potentiometer values is full
    if (frameCounter == MAXFRAMES)
    {
      // indicate to user that array is full
      digitalWrite(ledPin, HIGH);
      
      // display the results
      for(uint16_t cnt = 0; cnt < MAXFRAMES; cnt++)
      {
        Serial.print(frames[cnt].time);
        Serial.print(F("\t"));
        Serial.println(frames[cnt].value);
      }
      
      // hang forever
      for (;;) {}
    }
  }
}
1 Like

but all it does is twitches the servo for a second, idk what to add, i thought about looking through the examples in the ide for soloutions but i wanted to post it here so someone could have a look at it while i do that, it may seem stupid of me to not see obvios issues but i am still a beginner

Here is a similar example but for a robotic arm with 5 servo motors. That should be enough for you.

do you know of one that uses arduino uno? this one uses nano and i cant seem to get the same effect out of it, i also am so confused on how you press r and p

Why not? Arduino Nano and Arduino Uno use ATmega328, the difference is that Nano has 2 additional analog inputs. Everything else is equal. The Uno is not convenient for a prototyping board because it is larger in size. I only use Nano. Buttons R and P are commands sent over the serial connection through the serial monitor from the Arduino IDE. Did you watch the clip? It looks good there. If you want independent work without a computer, you can do it through 2 buttons to Arduino. Looks like you still have a lot to learn. The important thing is not to give up and to be persistent.

Have you tried youtube?

search term - arduino record servo movement

Waiting for the result of your searching; that result should be an updated version of the code that you provided in post #14 (or any other code that kind-of resembles what you need) where you show how you (attempt to) control the servo.

Take it one step at a time. Once you have the servo moving and the movements stored in an array you can concentrate on on the serial commands.
Things that you will probably use: