Our cat Elsa needs lots of entertainment. In our last attempt to make her happy, we bought her a Flippity Fish: a plush that looks like a fish, but it starts wiggling and flipping when its body gets hit.
It looks really nice and fun, but Elsa disagrees. When it starts moving, she immediately leaves it and looks at it from a distance. I think she's scared of how much and how long it moves. To prove my theory, I took it apart and looked for ways to reduce the wiggling, or even make it remote-controllable.
tl:dr; if you're doing OTA with PlatformIO and an ESP-01 module with 1MB of Flash, don't forget to add board_build.ldscript = eagle.flash.1m.ld in your platformio.ini file.
To finish the project I have to fit the ESP-01 inside the small space in the plastic inner case, just above the existing PCB.
But I can't even fit the ESP-01 as it is: the pin headers make the module too tall. I tried replacing them with 90-degree headers, but now the module would be too long and won't fit either direction.
Going wireless
So I had to remove the headers altogether and solder the pins directly to wires to the existing PCB. This will remove any possibility to reprogram the module in case I need software updates.
But WiFi-based modules like the ESP8266 can luckily be programmed over-the-air (aka OTA). With OTA I wouldn't worry about doing any physical connection to the module; as long as the module is powered, connected to WiFi and at a known IP address, I can reprogram it.
So I looked through tutorials, all basically saying that I should add some code snippets in my sketch, take care about running them as regularly as possible, and not running anything while the transfer is in progress.
Not so fast...
But every attempt I did, the OTA update always failed. Sometimes with unknown errors, but mostly with "Error[4] Not enough space" or similar.
I knew this can happen for some ESP-01 modules with 512kB of Flash memory. The rationale is that for OTA you must have at least double the space taken by the sketch. My sketch was ~300kB big so a 512kB chip wouldn't do. I used modules I bought years ago so without much thinking I ordered a few ESP-01S, guaranteed to have at least 1MB of flash.
Once the new modules arrived, and programmed them with my now OTA-powered sketch... the same error happened again :( Turns out that even my "old" modules had 1MB of flash. So why do I keep getting space-related errors?
The problem has to do SPIFFS (SPI Flash File System). See, the ESP8266 doesn't have to use the entire flash memory for code. Part of it can be used to store files, e.g. configuration or webpages, that you don't want or need to replace when uploading a new sketch.
By default, at least when building sketches with PlatformIO, a lot of flash is dedicated to SPIFFS; can't say how much, but just too much to allow OTA. But there's a way to use less or no flash memory for SPIFFS. On Arduino IDE, that's pretty simple: The Tools > Flash Size gives plenty of options. On PlatformIO that's less intuitive: you have to use a different "linker script" than the one used by default. This can be done by adding the following line to platformio.ini:
board_build.ldscript = eagle.flash.1m.ld
This will tell to make a firmware file suitable for 1MB of flash, with no space reserved for SPIFFS.
Once I added that line and uploaded the firmware via serial - for the last time -, I finally experienced a successful OTA update:
That kind of stroke in the fish's tail indicates that the flash is being written. I think that happens because one of the GPIO pins connected to the motor driver is set to input with pull-up resistor, causing the motor to fully go on one direction until the new firmware starts running.
So the USB-to-serial adapter arrived. I can now program the ESP-01 module, considerably smaller than the development boards I have: the WeMos D1 mini, for example, is a little too big to fit inside the small space available in the plastic enclosure.
With a bunch of jumper wires I kinda managed to connect it to an ESP-01 module. Did a first programming, then I unplugged the wires from the adapter, re-plugged the ones for the fish, and checked if it worked. It did work, but I needed a few adjustments. Unplug again, re-plug again. And every time, carefully check for mistakes.
Mildly fed up by this tedious process, I decided to build myself an adapter board. So I could plug the ESP-01 on one side, and the USB-to-serial adapter on the other. An evening and a morning later, here's the result:
I simply desoldered and lifted the two microcontroller pins, and connected the H-bridge driver to an ESP8266 dev board I had lying around.
I wrote a small sketch based on Blynk (GitHub repo in project page) and here's the result:
The next step is to use a smaller ESP-01 module to fit inside the inner plastic body. I couldn't do that before because I was missing an USB-to-TTL converter needed to program it.
Here's how it looks and behaves after removing the soft exterior and take apart the insides:
It wiggles following two patterns. First one is "continuous" and is shown above. The second one is "pulsed" and is shown below. In both cases the motor is moved back and forth to do the wiggling.
The next step is to get rid of the microcontroller to put our own control signals.