For contrast, here is a version for 4 pots/servos that uses 2 buttons. One button is used for indicating that the servos are all set and their position should be recorded on a single line in the file on the SD card. The other button indicates that the entire range of motion has been captured and the recording is complete.
It may not fit your perceived needs, but may offer some alternatives for program design and operation. Note that this is for the record side only.
Note that the sketch will compile clean, but I don't have the parts to test it; no guarantees.
Anything seems possible when you don't know what you're talking about.
@will - Since you're going with a Claymation / Industrial robot mentality, how do you key in the time you want for each "step"?
3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, WiFi Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide
@inq I would think that would have to be a constant determined by the length of time it takes for playback to complete the longest "line" of data, so it would be set at playback and be a constant value.
I kept the recording process in a text file format so that it can be manually edited and corrected if/as/when required. This would also allow it to be modified by adding the estimated "step" time in ms at the beginning of the file.
Then the file could be played again and again with different times and the inter-line timing could be adjusted to make the best possible playback sequence. The playback sketch would first read the line delay, then a line of positions, move the servos and, if required, pause until the interline delay time had elapsed.
This would become more useful as more and more pots and servos are added.
Anything seems possible when you don't know what you're talking about.
I should also mention that the process can be ramped up by eliding values which didn't change. That is, a typical line might contain moves for all servos and look like
20,35,160,45
whereas if the servo hadn't moved during that time slice you might see something like
,15,24,
where servo 1 and servo 4 did not move. You might also see something like
,,,
because none of the servos moved in that time slice.
Anything seems possible when you don't know what you're talking about.
I found one of my SD cards has a relatively tiny partition (60 MB) that the SD.h library recognized, so I was able to test the code changes to support SD cards. While I was at it I tried taking the recording at 15 Hz (vs 60 Hz) and it seemed to transition just as smoothly. I can't tell any difference in the motion of the playback as compared to when it was being recorded. Using 15 Hz and 4 servos... even the 60 MB partition could hold 36 hours of recording.
Recording - RalfRec.ino
#include <Servo.h> #include <SPI.h> #include <SD.h> // To change the number of servos, change at the // places marked with "SERVOS". These must be consistent // with those written in Ralf.ino struct Position { u32 timestamp; u8 servo; u8 angle; }; // GLOBAL VARIABLES // For SD Card const int chipSelect = D4; // File object to access data in recorded file. File _file; // Start Time for playing the recording. u32 _start = 0; // How fast you want to sample const u32 INTERVAL = 67; // 17 milliseconds is ~59 Hz. // Last interval occurred. u32 _last; // Stop recording pin const u8 pinStop = D2; // Your servos... doesn't matter if it's one or a hundred. Totally dependent // on what your MPU can handle hardware wise. const u8 CNT = 2; // SERVOS Servo servos[CNT]; u8 pots[CNT]; // This is number of positions that can be stored and is calculated at // runtime. If that number is then divided by 60 positions per sec and // divide by the number of servo will give you the duration of a recording. // e.g. 1 GB SD card, 4 servos => gives you 6.5 days. u32 maxPos; u32 wrotePos = 0; void setup() { // So we can debug stuff. Serial.begin(115200); Serial.flush(); Serial.printf("\nRalph Recorder is recording!\n"); // SERVOS // Attach as many pins to your servos as you have. // Make sure the number you attach is consistent with CNT. servos[0].attach(D3); servos[1].attach(D1); // SERVOS // Set the corresponding analog pins for each servo. // Make sure the number you configure is consistent with CNT. // ESP8266 only has one analog pin, have to use the same one. pots[0] = A0; pots[1] = A0; // Open the file system. if (!SD.begin(chipSelect)) { Serial.println("Card failed, or not present"); return; } maxPos = SD.size() / sizeof(Position); Serial.printf("Can store %u samples\n", maxPos); // Open up file to record. Overwrites old file. _file = SD.open("/EyeMovement.rec", FILE_WRITE); if (!_file) { Serial.printf("Unable to open file for writing, aborting\n"); return; } // Setup switch to stop the recording. pinMode(pinStop, INPUT_PULLUP); // We're just going to start recording on boot-up. You'll want to trigger // the start variable with some button press??? _start = millis(); // The last variable is the time that we took a snapshot of all the servos. _last = _start; } void loop() { u32 now = millis(); if ((wrotePos < maxPos) && (now - _last > INTERVAL)) { // We only get here on the period we've set. // First check to see if the stop button is pressed. if (!digitalRead(pinStop)) { // Stop the recording. Serial.println("Recording stopped."); Serial.printf("Stored %u data points\nApproximately %.1f seconds\n", wrotePos, (float)wrotePos / CNT * INTERVAL / 1000); maxPos = 0; // This keeps it from recording any more. _file.close(); // Close the file... ready for Playing. return; } // Read every pot, write the postion and move the servo. for(u8 i=0; i<CNT; i++) { // Read each pot. int analog = analogRead(pots[i]); // ESP8266 analog pin A0, ranges 0 to 1024. // We want to convert this to 0 to 180 degrees. analog = map(analog, 0, 1024, 0, 180); // Create our position object and write it to the file Position pos = { millis(), i, analog }; _file.write((u8*) &pos, sizeof(pos)); // Decrement how many we can store. wrotePos++; // Write to the servo servos[i].write(analog); } // update our last interval variable. _last = now; } }
Playback - Ralf.ino
#include <Servo.h> #include <SPI.h> #include <SD.h> // To change the number of servos, change at the // places marked with "SERVOS". These must be consistent // with those written in RalfRec.ino struct Position { u32 timestamp; u8 servo; u8 angle; }; // GLOBAL VARIABLES // For SD const int chipSelect = D4; // Do we want to repeat the file. bool _repeat = true; // File object to access data in recorded file. File _file; // Current position waiting for time to move. Position _current; // Start Time for playing the recording. u32 _start = 0; // Your servos... doesn't matter if it's one or a hundred. Totally dependent // on what your MPU can handle hardware wise. const u8 CNT = 2; // SERVOS Servo servos[CNT]; void setup() { // So we can debug stuff. Serial.begin(115200); Serial.flush(); Serial.printf("\nRalph is here!\n"); // SERVOS // Attach as many pins to your servos as you have. // Make sure the number you attach is consistent with CNT. servos[0].attach(D3); servos[1].attach(D1); // Open the file system. if (!SD.begin(chipSelect)) { Serial.println("Card failed, or not present"); return; } // Open up file to playback. _file = SD.open("/EyeMovement.rec"); if (!_file) { Serial.printf("Unable to open file for reading, aborting\n"); return; } u32 pos = _file.size() / sizeof(Position); Serial.printf("File has %u data points\nApproximately %.1f seconds\n", pos, (float)pos / CNT * 17 / 1000); // Read the first position in the file. readNext(); // We're just going to start playing on boot-up. You'll want to trigger // the start variable with some button press??? _start = millis(); } void loop() { if (!_file) return; // We have no data to process. u32 timeSinceStart = millis() - _start; if (timeSinceStart >= _current.timestamp) { servos[_current.servo].write(_current.angle); readNext(); } } void readNext() { // Read next position data into the "_current" position. // Check to see if the returned amount of data agrees with // the required amount. If it does not agree, its because // the end of the _file has been reached. if (_file.read((u8*)&_current, sizeof(_current)) != sizeof(_current)) { // We've finished reading the file. if (_repeat) { // Rewind the file. _file.seek(0, SeekSet); // Use recursion to read the first entry. readNext(); // Set the start time to the current time. _start = millis(); } else // Close the file. _file.close(); } }
3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, WiFi Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide
@hinobot - I was wondering if you've made any progress on your project. I host a user's group at our local library and thought this would be a great project for us to do as a group. The library has a 3D printer and I've looked on Thingiverse and found several animatronics eyeballs that seem do-able. Wondering what you were using and if you'd gotten anything motivating to report...
Also, I know you are using this to learn and teach your daughters hardware, software, 3D printing... I tried to comment the code to be self explanatory, but if you have any troubles understanding or explaining it to your daughters, I'd really appreciate the opportunity to elaborate. It helps me become a better teacher to my own students... pre-teen through senior citizens.
Thanks.
VBR,
Inq
3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, WiFi Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide
@will That is almost identical to how video frames are compressed (MPEG), MOST of the scene is identical so the data need not be stored again.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
@inq One thing I didn't see discussed is using a micro SD card for file storage. The average card is very well known for developing errors, the high endurance cards are more resilient but now we can use USB sticks and other USB based storage like SSD and even boot from them. I would highly recommend a small SSD for much better longevity.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
@inq One thing I didn't see discussed is using a micro SD card for file storage. The average card is very well known for developing errors, the high endurance cards are more resilient but now we can use USB sticks and other USB based storage like SSD and even boot from them. I would highly recommend a small SSD for much better longevity.
... and I assume you are volunteering to show us how you connect a USB stick to a MPU like a ESP8266 or ESP32???
I've never needed the SD card even though I had the hardware in drawers. The 3MB on the typical ESP8266 or 15MB on the pro version has always been far more than I've ever needed for a project. I think our local users group may go for doing a set of these recording eyes and as I described above, I can record nearly 2 hours of movement on four servos on 3MB. If I need to "compress" it, I can get 2.5 hours. Considering, we may do 30 seconds and have it repeat, we won't be needing an SD.
Here's a quick demo of both the recorder and playback Ralf.
VBR,
Inq
3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, WiFi Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide
@inq Oops, I thought a Pi was in play. If there is enough memory on the esp's then that would be the way to go obviously.
Just as an exercise, are there enough free pins (4) on the 8266 to connect an SD? Not 100% sure CS is needed, could just tie it to G or 5V as needed.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
@inq Looking good. I assume each 'eye' could be moved independently without much/any increase in complexity and playback time.
How feasible to add 2 more servos so each 'eye' has 2 degrees of freedom.
And if I am really 'going for it', what does it take for the 'eyes' to pop out and dangle on springs? Getting them back may be the issue however.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
@inq Oops, I thought a Pi was in play. If there is enough memory on the esp's then that would be the way to go obviously.
Just as an exercise, are there enough free pins (4) on the 8266 to connect an SD? Not 100% sure CS is needed, could just tie it to G or 5V as needed.
Hmmm... I plead the 5th. I'm cheating...
"https://www.amazon.com/ACEIRMC-Shield-ESP8266-Compatible-Module/dp/B09S3HFFHZ"
https://www.amazon.com/ACEIRMC-Shield-ESP8266-Compatible-Module/dp/B09S3HFFHZ
I don't know what pins are active under there. 🤣
I think there are still as least 4 pins available to drive servos. For this animatronics project, I think 3MB will be more than enough for anything... even 16 servos.
But... I'm glad @hinobot brought up the thread. It gave me a quick way to explore the capability. I can see using the SD card memory for the mapping on the Inqling Jr. project.
3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, WiFi Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide
@inq Looking good. I assume each 'eye' could be moved independently without much/any increase in complexity and playback time.
How feasible to add 2 more servos so each 'eye' has 2 degrees of freedom.
And if I am really 'going for it', what does it take for the 'eyes' to pop out and dangle on springs? Getting them back may be the issue however.
The limitation was purely on the recording hardware side. There's only one Analog input. I just chose to read the same input and applied it to each servo and recording. Using an ESP32 and using a pot for each DOF desired would be easy. On the code side, the only thing needed is two lines of configuration code per added servo/pot. There was no appreciable performance hit that I could see. One of those 16 channel servo boards hooked up to I2C could be used and record 16 channels for something with eyes and a neck and whatever. Also remember, the ESP8266 can be bumped up to 160MHz and cover even more.
I think my user group here may "Go for it". We probably will load it up with sensors so the eyes will follow people here in the library. Hopefully, we'll have it ready to put up by Halloween!
Have to give the eyes popping out thing a thought or two. 🤣
3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, WiFi Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide