Using SD Cards with...
 
Notifications
Clear all

Using SD Cards with Arduino - Record Servo Motor Movements

84 Posts
6 Users
1 Likes
7,705 Views
frogandtoad
(@frogandtoad)
Member
Joined: 5 years ago
Posts: 1458
 

@robomaster

Posted by: @robomaster

@will 

To answer your question abbout the Crypter Keeper figure it was made in 1996 at that time the Arduino Boards had not be invented yet. Had to make my own servo driver boards using MIDI which worked pretty good.

I am extermely sorry about what happen here on Servo Controler code. What can I do to compensate you for time and help on this?

There is no need to compensate anyone here for the help they provide - This is a public forum, where all and any help is provided for free.

Given that you have explained your position, please feel free to ask any questions if you need help... there are many people here willing to help.

Cheers.


   
ReplyQuote
(@robomaster)
Member
Joined: 3 years ago
Posts: 36
 

In the original code, it keeps appending to the same file over and over. How can I make it stop doing it?

Also which is the best to show my code?

Here the Record Function:

 

/****************************** Functions Record / Playback *******************************
//
// Function to Record the movements of the Servos
//
// This routine creates a file, reads sets of pot settings, sets
// the servos to match, displays the results and then saves
// them to the file "servopos.txt" for later use.
//
// It continues doing this until the user presses the blue STOP
// button. It will complete the last write before stopping.
//
// It returns the count of records were written or 0 if the file
// could not be created.
//
long Record() {
long count = 0; // Nothing written yet
Serial.println("Recording Servo File"); // Notify user of new mode
lcd.setCursor(0,1);
lcd.print("Recording Servo File");
//
// Open the file to prepare for results storage
// Note that only one file can be open at a time, so you
// have to close this one before opening another.
File dataFile = SD.open("servopos.txt", FILE_WRITE);
if (!dataFile) {
Serial.println("Can't open data file in Record()");
return 0;
}
//
// Now cycle through collecting user settings and save them
// until user pushes the blue button
//
//
while ( digitalRead(BlueBtn) == HIGH ) { // Stop Button not LOW
byte index, value;
for (index=0;index<DATA_POINTS;index++) {
value = map(analogRead(potPins[index]), 0, 1023, 0, 180);
if (value!=servoWas[index]) { // New value
moveServo(index,value); // Move servo
printDatum(index,value); // Print to terminal
writeToFile(dataFile,index,value); // Save to file
servoWas[index]=value; // Update value
count++; // Update count
delay(15); // Wait for servos
}
}
}

//
// Be polite and close data file after use
//
dataFile.close();
return (count > 0) ? count : 0; // Count of data written
}

 


   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2042
 

   
ReplyQuote
(@robomaster)
Member
Joined: 3 years ago
Posts: 36
 

I need some help with the Playback function I do not think I got it working right stops before the audio track finishes. Here is the whole program.

 

 

 

/*

SD Card Servo Record/Playback with Button Control
by Tim Lewis 9/23/2021
to store on SD Card four Channels Servo Data and Play it back.
using Push Buttons for Recod and Playback control.

9/27/2021
Got it to loop on Recording until I pressed
the Stop Button ( Blue Button )

Adding code to brake-out of Playback Mode works

9/28/2021

Adding NeoPixel LED Code
Neopixel LEDs working on Record Mode

Fixed brake-out of Playback Mode now. not working
10-01-2021
Brake-out of Playback Mode now working
Setup the other three buttons

10-7-2021
Got the Record and Playback working great.

10-9-2021
Switched to Neopixel Ring Looks Coller and I 12 LEDs to work with.

10-11-2021
Added a SPI Serial LED Display it now works the Record and
Playback Functions

10-18-2021

Adding Control of External Wave Player to Start Recording when
either record button is pushed or the play button is pushed to
starta the player playing an audio track.

10-26-2021
Got the working the start the player playing a track when Play Button and stops when the
Stop Button is pressed.

10-28-2021
Add code to erase the current file before usiing it thus clearing it out
Working on code to allow the wave player to Stop the recording when
end of the wave file.

*/

// Include libraries

#include <SPI.h>
#include <SD.h>
#include <Servo.h>
#include <FastLED.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// SPI LCD Display
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display

// Neopixel Leds
// How many leds in your strip?
#define NUM_LEDS 11
#define DATA_POINTS 4 // the number of servos you'll be monitoring and controlling

// For led chips like WS2812, which have a data line, ground, and power, you just
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN
// Clock pin only needed for SPI based chipsets when not using hardware SPI
#define DATA_PIN 11

// Define the array of leds
CRGB leds[NUM_LEDS];

const int Player = 49 ; // Player Start Pin
const int TrkDone = 48; // Track Done Playing

// CS pin for SD Card Module
const int chipSelect = 53;

// String to hold one line of text
String buffer;

 

// Create a Servo object

byte dataBuffer[DATA_POINTS]; // Create a list of values
byte servoWas[DATA_POINTS] = {0}; // Previous servo settings
Servo myServos[DATA_POINTS]; // Create a set of servos
int potPins[DATA_POINTS]; // Pins

// file name to use for writing
const char filename[] = "servopos.txt";

// Buttons Constants
const int RedBtn = 22; // Red Button 1
const int GrnBtn = 23; // Green Button 2
const int BlueBtn = 24; // Blue Button 3
const int BlkBtn = 25; // Black Button 4
const int WhtBtn = 26; // White Button 5
const int YellBtn = 27; // Blue Button 6
const int led = 10;

 

void setup() {

lcd.init(); // initialize the lcd
lcd.backlight();

// Buttons

pinMode(RedBtn, INPUT); // Button 1 as Input
pinMode(GrnBtn, INPUT); // Button 2 as Input
pinMode(BlueBtn, INPUT); // Button 3 as Input
pinMode(BlkBtn, INPUT_PULLUP); // Button 4 as Input
pinMode(WhtBtn, INPUT_PULLUP); // Button 5 as Input
pinMode(YellBtn, INPUT_PULLUP); // Button 6 as Input

digitalWrite(RedBtn, HIGH); // Pullup
digitalWrite(GrnBtn, HIGH); // Pullup
digitalWrite(BlueBtn, HIGH); // Pullup

// Wave Player Pins
pinMode(Player, OUTPUT); // Player Start Pin is an Output
pinMode(TrkDone, INPUT); // Player Stop Pin is an Input

// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only .

}

Serial.print("Initializing SD card...");

// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
while (1);
}
Serial.println("card initialized.");

FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, NUM_LEDS); // GRB ordering is typical

// Attach servo pins to the servo objects
setupPots();
setupServos();

//Write the servo motors to initial position
myServos[0].write(15);
myServos[1].write(15);
myServos[2].write(15);
myServos[3].write(15);

// Now turn the LED off, then pause
All_Off() ;

// Print a Start Up message to the LCD.
lcd.setCursor(0,0);
lcd.print("Servo Controller 1.0");
digitalWrite(Player, LOW); delay (200) ; // Stop Play Track

}

void loop() {
All_Off() ;
//
//
// Test buttons and take appropriate action
//
//
if(digitalRead(RedBtn) == LOW) {
//
// Button 1 pressed - do Record() function
//
digitalWrite(Player, HIGH); delay (200) ; // Play Track
showLED( CRGB::Red,100); // Turn on red LED
displayInfo(Record()," sets recorded"); // Say how we did
Serial.println("Recording Servo File complete");
showLED(CRGB::Black,100); // Turn off LED
lcd.setCursor(0,1); // Clear line 1
lcd.print(" ");
delay (100) ;
digitalWrite(Player, LOW); delay (200) ; // Stop Play Track
}

//
//
//
if(digitalRead(GrnBtn) == LOW) { // If button 2 pressed PlayBack Mode
//
// Button 2 pressed - do Play() function
//
digitalWrite(Player, HIGH); delay (200) ; // Play Track
showLED( CRGB::Green,100); // Turn on green LED
Serial.println("Playing Back Servo File"); // Print "Playing Back Servo File" on Serial Monitor
delay (100) ;
lcd.setCursor(0,1);
lcd.print("Playing Servo File");
delay (100) ;

Play() ; // Call Playback Function
Serial.println("Playback of Servo File complete");
showLED(CRGB::Black,100);

}

// On return from PLay Function
digitalWrite(Player, LOW); delay (200) ; // Stop Play Track
lcd.setCursor(0,1);
lcd.print(" "); //Blank the Line
delay (100) ;
leds[0] = CRGB::Black; FastLED.show(); delay(100);
//leds[1] = CRGB::Blue; FastLED.show(); delay(100);

if(digitalRead( BlkBtn) ==LOW) { // If button 4 pressed
delay (100) ;
leds[1] = CRGB::Blue; FastLED.show(); delay(100);
}
if(digitalRead( WhtBtn) ==LOW) { // If button 5 pressed
delay (100) ;
leds[2] = CRGB::White; FastLED.show(); delay(100);
}
if(digitalRead(YellBtn ) ==LOW) { // If button 6 pressed
delay (100) ;
leds[3] = CRGB::Yellow; FastLED.show(); delay(100);
}
}

 

//****************************** Functions Record / Playback *******************************
//
// Function to Record the movements of the Servos
//
// This routine creates a file, reads sets of pot settings, sets
// the servos to match, displays the results and then saves
// them to the file "servopos.txt" for later use.
//
// It continues doing this until the user presses the blue STOP
// button. It will complete the last write before stopping.
//
// It returns the count of records were written or 0 if the file
// could not be created.
//
long Record() {
long count = 0; // Nothing written yet
Serial.println("Recording Servo File"); // Notify user of new mode
lcd.setCursor(0,1);
lcd.print("Recording Servo File");
//

SD.remove(filename); // If you want to start from an empty file,

// Open the file to prepare for results storage
// Note that only one file can be open at a time, so you
// have to close this one before opening another.
File dataFile = SD.open(filename, FILE_WRITE);
if (!dataFile) {
Serial.println("Can't open data file in Record()");
return 0;
}
//
// Now cycle through collecting user settings and save them
// until user pushes the blue button
//
//
while ( digitalRead(BlueBtn) == HIGH ) { // Stop Button not LOW
byte index, value;
for (index=0;index<DATA_POINTS;index++) {
value = map(analogRead(potPins[index]), 0, 1023, 0, 180);
if (value!=servoWas[index]) { // New value
moveServo(index,value); // Move servo
printDatum(index,value); // Print to terminal
writeToFile(dataFile,index,value); // Save to file
servoWas[index]=value; // Update value
count++; // Update count
delay(15); // Wait for servos
}
}
}

//
// Be polite and close data file after use
//
dataFile.close();
return (count > 0) ? count : 0; // Count of data written
}

long Play() //Function to PlayBack the movements of the Servos
{
long count = 0; // Nothing read yet

// Put Playback Code Here to Play

 

// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File dataFile = SD.open(filename);

// If the file is available, read it
if (dataFile) {
while (dataFile.available()) {

// when the STOP button is pressed, stop Playingback
// while (digitalRead(BlueBtn) == LOW )) { // Stop Button is pressed

//************ Read Data Back off SD Card Move Servos *****************
while ( digitalRead(BlueBtn) == HIGH ) { // Stop Button is not pressed
byte index, value;
for (index=0;index<DATA_POINTS;index++) {
value = 0 ;
// if (value!=servoWas[index]) { // New value

readFromFile(dataFile,index,value); // Read from file
printDatum(index,value); // Print to terminal
moveServo(index,value); // Move servo
servoWas[index]=value; // Update value
// count++; // Update count
delay(15); // Wait for servos
}
}

//
// Be polite and close data file after use
//
dataFile.close();
return (count > 0) ? count : 0;

}
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening servopos.txt");

}
}

//***************** Functions ***********************************

//
// Assign pins connected to the pots
//
void setupPots() {
potPins[0] = A0;
potPins[1] = A1;
potPins[2] = A2;
potPins[3] = A3;
}
//
// Assign the servos to their pins
//
void setupServos() {
myServos[0].attach(14);
myServos[1].attach(15);
myServos[2].attach(16);
myServos[3].attach(17);
}
//
// Light indicated LED for indicated time
//
void showLED( CRGB colour, int duration)
{
leds[0] = colour;
FastLED.show();
delay (duration) ;
}
//
// Display an info message
//
void displayInfo( long num, String desc )
{
Serial.print(num);
Serial.println(desc);
}
//
// Print datum to serial monitor
//
void printDatum( byte index, byte value ) {
Serial.print("Servo ");
Serial.print(index); // Display servo number
Serial.print(" = ");
Serial.println(value); // Display value
}
//
// Move servo as per datum
//
void moveServo( byte index, byte value ) {
myServos[index].write(value);
}
//
// Write data to file
//
void writeToFile(File dataFile, byte index, byte value ) {
byte it[2]={index,value};
dataFile.write(it,2); // Write to file
}
//
// Read data from file
//
void readFromFile(File dataFile, byte &index, byte &value) {
byte it[2];
dataFile.read(it,2); // Read from file
index = it[0];
value = it[1];
}

void All_Off () { // All Neopixel Leds Off
leds[0] = CRGB::Black; FastLED.show(); delay(100);
leds[1] = CRGB::Black; FastLED.show(); delay(100);
leds[2] = CRGB::Black; FastLED.show(); delay(100);
leds[3] = CRGB::Black; FastLED.show(); delay(100);
leds[4] = CRGB::Black; FastLED.show(); delay(100);
leds[5] = CRGB::Black; FastLED.show(); delay(100);
leds[6] = CRGB::Black; FastLED.show(); delay(100);
leds[7] = CRGB::Black; FastLED.show(); delay(100);
leds[8] = CRGB::Black; FastLED.show(); delay(100);
leds[9] = CRGB::Black; FastLED.show(); delay(100);
leds[10] = CRGB::Black; FastLED.show(); delay(100);
leds[11] = CRGB::Black; FastLED.show(); delay(100);
}


   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2042
 

   
ReplyQuote
(@robomaster)
Member
Joined: 3 years ago
Posts: 36
 

Thank You for reformating it for me. I tried to do it according to the instructions but was unable to get to work. I am having a problem with Playback Code it stops playing back all the way through that has been recorded. I do not see the problem. I thought I got it set up ok it should be doing the reverse of the record code. Thank You for your help.


   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2042
 

@robomaster 

I am having a problem with Playback Code it stops playing back all the way through that has been recorded.

Maybe the memory filled up before the record finished? Your code doesn't seem to test that the memory isn't full?

if (count<maxMemory){
  count++;
}else{
  println("MEMORY FULL");
}

 

You can put the SD card into your computer and view the text.

One way to record more natural looking movements might be to have two "skeletons" one with POTS to record the movements as you manually move the joints and another with stepper motors to play the movements. There are examples of this for recording and playing the movements of Arduino based robotic arms on the internet.  You might control the head like a hand sock puppet to sync with any audio.

 


   
ReplyQuote
(@robomaster)
Member
Joined: 3 years ago
Posts: 36
 

Why would the memory be full?  I am writing to the SD Card it has a 1 gig storage capacity. I have been looking at how I break out the record and playback functions when the stop button is pressed I am not sure if I am doing it the best way. I am also removing the file before I write to so to have a clean file. The idea behind this is so I don't keep appending to the file each time I do the record function. Do I need to put some type of end of file character in there so I know it at the end when the stop button is pressed?


   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 5 years ago
Posts: 2042
 

@robomaster 

Ok. Working with limited information here.

Yes I suggested the use of SD.remove(filename);

It would have made it easier if I had an SD card and could use dummy data to test the program.

If it drops out while reading then the dataFile.available() must have run out of data to read. There would be no end character required.

So the question is: Was the amount of data actually saved as you assumed?  I would have a dummy set of data of known size to save and then see if it was saved as you expected.  This is why I suggested loading the text file into a text editor like NotePad on MSWindows so you can actually look at it and see.  Or slow the Play down and step through it using the Arduino Monitor program using Serial.print.  Maybe print the count variable in front of the four values.

I notice an if (value!=servoWas[index]) { // New value perhaps that is stopping it from saving every one of the four servo values but the play back assumes it did? This is just intuitive speculation I would have to spend more time then I have to work it out in my head,  much better to play with the code itself.

 


   
ReplyQuote
Page 6 / 6