Rick's b.log - 2023/04/01 |
|
It is the 23rd of November 2024 You are 18.216.104.106, pleased to meet you! |
|
mailto:
blog -at- heyrick -dot- eu
The first is to add the option of a
The format is simple. One or more lines that consist of a lowercase letter followed by an equals followed by a number (in base 10).
For example, here is a file that sets a lower quality SVGA picture to be taken every 30 seconds:
Another issue that appeared, since my little µSD card is only 128MB, is that when the media is full, the camera will continue trying to write files to the disc, as it is capable of creating files, but not writing data to them.
Therefore, the amount of data written is now checked, and if there's a discrepancy, the camera will halt with a slow blinking red notification LED.
As this required numerous changes to the source, I'll give a brief overview of them here, but it's best if you download the archive with the sketch within.
That's it. Now you can use the presence of the file reset.txt to reset the counter, and information in the config.txt file to control the resolution, quality, and sleep interval.
This one was taken this morning. I got up at about twenty past six to feed Anna and make my morning tea, so I set LapseCam running. Similar frame count, similar duration.
Then use FFMPEG to convert the pictures to a video.
On Windows, assuming C:\LapseCam\source is where the pictures are:
On Android, with the FFMPEG app by SilentLexx UA (it's a green icon with the ffmpeg logo in a white Android robot), click on the little
Feel free to play with the framerate. My 280 pictures gives just under 19 seconds at 15fps. At 30fps it would be a smoother video, but only nine and a half seconds.
Fudging the colour space to YUV (Y'CbCr) with 4:2:0 chroma subsampling (-pix_fmt yuv420p) is necessary as a fair number of players will struggle with other subsampling methods. JPEGs normally use 4:2:0, but this isn't guaranteed. So it's best to force it for maximum compatibility.
And soon the other cherries...
These pictures were taken in the brief time the sun was out and it was neither dreary-grey and/or raining.
Saw this, saw the opportunity, liked.
I was planning on going shopping today, but I don't really need to (have enough milk) so I won't. But... it's chilly (only 10°C), grey, miserable, raining now and then...
Rick's LapseCam v0.02
Having used my camera briefly in testing, it was clear that a few changes were necessary.
config.txt
file in order to control some of the behaviour of the device without having to rebuild the firmware each time.
f=
Set frame size, range 0 - 10:
0 QQVGA (160×120) 1 2 QCIF (176x144) 3 HQVGA (240×176) 4 QVGA (320×240) 5 CIF (400×296) 6 VGA (640×480) 7 SVGA (800×600) 8 XGA (1024×768) 9 SXGA (1280×1024) 10 UXGA (1600×1200) - default q=
Set quality, range 1 - 63. Default quality is 5. i=
Set interval in seconds, range 15 - ... Default interval is 60 seconds. f=7
q=15
i=30
Initial variables
At the top of setup()...
int counter = 0;
char filename[32] = "";
int64_t ticks = esp_timer_get_time();
uint64_t interval = 60000000; // default 1 minute
uint8_t sdtype = CARD_NONE;
uint64_t sdsize = 0;
uint64_t sdfree = 0;
int quality = 5; // default
int framesize = FRAMESIZE_UXGA; // default
char confbuff[8] = "";
int confread = 0;
int confval = 0;
int byteswritten = 0;
Handling the config.txt file
After checking for the "reset.txt" file, insert this to handle the "config.txt" file.
// Is the "config.txt" file present?
if ( fs.exists("/config.txt") )
{
Serial.println("The config.txt file is present, loading settings.");
File conffile = fs.open("/config.txt", FILE_READ);
if ( !conffile )
{
Serial.println("Failed to open config.txt, using defaults.");
}
else
{
while ( conffile.available() )
{
confread = conffile.readBytesUntil('\n', confbuff, 8);
if ( confread > 0 )
{
// f=<num> to set framesize
if ( tolower(confbuff[0]) == 'f' )
{
confval = atoi(confbuff + 2);
if ( ( confval > 0 ) && ( confval < 11 ) )
{
// This relates to the ORIGINAL resolutions
// list. The use of the defines is because
// the list doesn't match what's there now.
Serial.print("-> Setting framesize to ");
switch (confval)
{
case 0 : // fall through
case 1 : Serial.println("QQVGA (160x120).");
confval = FRAMESIZE_QQVGA;
// 1 = QQVGA2 (128x160), this was
// an odd size, not present in
// current builds.
break;
case 2 : Serial.println("QCIF (176x144).");
confval = FRAMESIZE_QCIF;
break;
case 3 : Serial.println("HQVGA (240x176).");
confval = FRAMESIZE_HQVGA;
break;
case 4 : Serial.println("QVGA (320x240).");
confval = FRAMESIZE_QVGA;
break;
case 5 : Serial.println("CIF (400x296).");
confval = FRAMESIZE_CIF;
break;
case 6 : Serial.println("VGA (640x480).");
confval = FRAMESIZE_VGA;
break;
case 7 : Serial.println("SVGA (800x600).");
confval = FRAMESIZE_SVGA;
break;
case 8 : Serial.println("XGA (1024x768).");
confval = FRAMESIZE_XGA;
break;
case 9 : Serial.println("SXGA (1280x1024).");
confval = FRAMESIZE_SXGA;
break;
case 10 : Serial.println("UXGA (1600x1200).");
confval = FRAMESIZE_UXGA;
break;
// We do not support 96x96 and HD (1280x720)
// as these are newer than my SDK.
}
framesize = confval;
}
else
{
Serial.printf("Invalid framesize %d.\n", confval);
}
}
// q=<num> to set quality
if ( tolower(confbuff[0]) == 'q' )
{
confval = atoi(confbuff + 2);
if ( ( confval > 0 ) && ( confval < 64 ) )
{
Serial.printf("-> Setting quality to %d.\n", confval);
quality = confval;
}
else
{
Serial.printf("Invalid quality %d.\n", confval);
}
}
// i=<num> to set timer interval
if ( tolower(confbuff[0]) == 'i' )
{
confval = atoi(confbuff + 2);
if ( confval < 15 )
{
Serial.printf("Interval must be at least 15 seconds.\n");
confval = 15;
}
Serial.printf("-> Setting timer interval to %d seconds.\n", confval);
interval = (uint64_t)confval * (uint64_t)1000000;
}
} // if (confread > 0 )
} // while ( fs.available() )
conffile.close();
} // if config file opened
} // if config file exists
Setting the camera options
Just below the above, amend the camera setup as follows:
// Set the camera options
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, (framesize_t)framesize);
s->set_quality(s, quality);
// other options can just be the camera defaults
Checking file writes
Change the block of code for writing to the file to include testing that what was wanted to be written was in fact written:
{
byteswritten = file.write(fb->buf, fb->len);
file.close(); // buffer data, buffer length
Serial.printf("Saved %d of %d bytes, updating counter.\n",
byteswritten, fb->len);
// Trap if data couldn't be written (usually means disc full)
if ( byteswritten != fb->len )
{
Serial.println("ERROR: Unable to write all data - disc full?");
while (true)
{
// Just loop, slow LED flash, it's a show stopper
digitalWrite(LED_PIN, LED_ON);
delay(500);
digitalWrite(LED_PIN, LED_OFF);
delay(500);
}
}
// If we're here, file saved correctly, so update
// the sequential counter and commit it to EEPROM.
counter++;
EEPROM.write(0, (counter & 255));
EEPROM.write(1, ((counter >> 8) & 255));
EEPROM.commit();
}
Variable sleep interval
Finally, changethe RTC timer and final status as shown:
// Tell the RTC timer to prod us when the time has elapsed
ticks = esp_timer_get_time() - ticks; // our elapsed time
ticks = interval - ticks; // how much remains of our interval time
esp_sleep_enable_timer_wakeup(ticks);
// Final status
Serial.println("Going into deep sleep for %llu seconds, seeya!", (ticks / 1000000));
delay(500);
Serial.flush();
Two timelapse videos
This was taken yesterday afternoon to test everything works. 284 pictures (all that would fit on my 128MB µSD card) with one picture every minute, giving a recording of just under five hours.
Making a video from the pictures
Copy the pictures so they're all in the same directory (on a PC, Android phone, whatever).
ffmpeg -framerate 15 -i "c:\LapseCam\source\image%05d.jpg" -pix_fmt yuv420p "c:\LapseCam\video.mp4"
>_
icon at the bottom right to control FFMPEG directly, and then enter:
ffmpeg -framerate 15 -i "/storage/emulated/0/LapseCam/source/image%05d.jpg" -pix_fmt yuv420p "/storage/emulated/0/LapseCam/video.mp4"
This assumes, also, the pictures are in LapseCam\source in the root of your accessible storage.
Soon Sakura
Soon the Sakura cherry...
Wait for it, wait for it...
Keep waiting for it...
Nice patterns and colours.
...I guess there's no other choice except to crawl under my duvet with a mug of tea and fire up Netflix.
David Pilling, 3rd April 2023, 15:27 I used "Virtual Dub" to take a folder of jpegs and convert them to a video. (free, video edit software)
© 2023 Rick Murray |
This web page is licenced for your personal, private, non-commercial use only. No automated processing by advertising systems is permitted. RIPA notice: No consent is given for interception of page transmission. |