05. Firmware - reivaxy/kinetix GitHub Wiki
I prefer using Platformio on Visual Studio Code, rather than the Arduino IDE, because it better handles the configuration of the board, the libraries, that makes the project much easier to share, thanks to the platformio.ini file.
You can download a released .bin file from https://github.com/reivaxy/kinetix/releases and upload it to your device by several means:
Start with installing Python3 if you don't already have it https://www.python.org/downloads/
Then install esptool:
pip install esptool
Depending on your OS you will then run either 'esptool.exe' (Windows) or 'python esptool.py' (others) like this, after replacing the port parameter to the one your ESP32 is connected to and with the name of the binary file that you downloaded
On Windows you may need to add the path to esptool.exe to your PATH environment variable.
Then run:
esptool --chip esp32s3 --port "COM14" --baud 460800 --before default-reset --after hard-reset write-flash -z --flash-mode dio --flash-freq 80m --flash-size 8MB 0x10000 <Name of binary file>
If this does not work, try:
python -m esptool --chip esp32s3 --port "COM14" --baud 460800 --before default-reset --after hard-reset write-flash -z --flash-mode dio --flash-freq 80m --flash-size 8MB 0x10000 <Name of binary file>
To find the COM port, plug the ESP32-s3 to a USB socket, then:
On Windows, open a CMD: Press Win + R to open the Run dialog. Type cmd and press Enter. In the CMD command, type
wmic path Win32_SerialPort get Name,DeviceID
On Mac, open a terminal, and type
ls /dev/tty.*
Warning
This can only work if the firmware to be replaced also supports OTA update. If it does not, you will need to first upgrade to a release that supports it, using one of the other methods (esptool on command line or from IDE)
Starting with its version 0.2-OTA the Android Application allows to upload a new version of the firmware using Wifi. This app is available in release 0.12.
Warning
This feature requires the ESP32 WiFi antenna to be plugged in.
Once your KinetiX device is already running a firmware version that handles OTA, here is how to flash a new version:
Check the Browser application page: https://github.com/reivaxy/kinetix/wiki/09.-Chrome-Browser-Application#update-the-firmware-wirelessly
Check the Android application page: https://github.com/reivaxy/kinetix/wiki/06.-Android-Application#updating-the-firmware-of-the-esp32
Check the computer application page: https://github.com/reivaxy/kinetix/wiki/08.-Laptop-Application#updating-the-firmware-of-the-esp32
See next Chapter:
Install Visual Studio Code (VSC): https://code.visualstudio.com/download
Run it, open the Extension dialog, search Platformio and click Install
If you are not familiar with github, you can just download a released source code zip or tar.gz file from the latest release https://github.com/reivaxy/kinetix/releases and then unzip it to your hard drive.
If you are familiar with github, clone the repository to your hard drive.
Better yet, fork it so that you can make contributions!
Run Visual studio code and create a workspace using the subdirectory with the sources "firmware/esp32"
The platformio.ini file will make sure you have the appropriate board configuration and libraries.
Use the VSC environment selector to pick one environment from the ones in the platformio.ini file.

Pick either a left hand or right hand configuration.
You'll need to uodate the COM port to upload and monitor in the chosen env:
To know which port your hand is connected to, open a terminal in VSC, and type the command
pio device list
Compare the results when your hand is disconnected to when your hand is connected.
The classes included allow to very easily code new positions and movements, use settings that can be modified from one of the applications (Android or Computer), use a small oled screen if available, ...
Everything is handled by 4 concepts:
A finger position is an integer between 0 (fully open) and 100 (fully closed), no matter what are the actual servo angles matching these position, which can be different from a finger to another, and from left hand and right hand.
A finger movement describes a finger position and a speed, with 1 being the fastest and fractions of 1 being slower (it's actually a step increment rather than a speed).
A hand movement is a collection of 5 finger movements, each having an optional starting delay. For instance when closing all finger, you may want the thumb to end on top, so you will make it start to close a bit later than the others, or move slower.
For instance:
HandMovement* HandMovementFactory::rock() {
HandMovement *handMovement = new HandMovement(hand, "Rock");
// Thumb
handMovement->setFM(0, new FingerMovement(100, 0));
handMovement->setFM(1, new FingerMovement(0, 0));
handMovement->setFM(2, new FingerMovement(100, 0));
handMovement->setFM(3, new FingerMovement(100, 0));
handMovement->setFM(4, new FingerMovement(0, 0));
return handMovement;
}
A sequence is a collection of hand movements, each one with a maximum duration.
It can repeat indefinitely or a specific number of times.
For instance, the "scratch" command is a sequence with two hand movements, one that half opens the hand, and one that closes the hand, and it repeats. Each hand movement describes the positions of all fingers.
void MessageProcessor::scratch() {
log_i("Starting scratch sequence");
HandMovementFactory *hmf = new HandMovementFactory(hand);
seq = new Sequence(0); // 0 is repeat forever
seq->addMovement(hmf->scratchOpen(), 600);
seq->addMovement(hmf->scratchClose(), 600);
seq->start();
}
Another example with "come"
void MessageProcessor::come() {
log_i("Starting come sequence");
HandMovementFactory *hmf = new HandMovementFactory(hand);
seq = new Sequence(5);
seq->addMovement(hmf->comeOpen(), 500);
seq->addMovement(hmf->comeClose(), 500);
seq->start();
}
The MessageProcessor handles messages sent by the App (or any other BLE client) through Bluetooth.
Messages can be settings read/write, movement requests, OTA start request, ...
When a movement requests is received, if a sequence was running it will be stopped, and all relative objects freed (minus possible bugs...) so release memory, then the movement will be executed.
The ONE thing that you must be careful to not break is the OTA feature. Because once it is broken, if you published the firmware and people updated their device, they will no longer be able to update the firmware wirelessly (which is very convenient for non tech savvy people).
Try as much as possible to make the new hardware code optional:
- by using compilation directives.
- by using mock classes.
The compilation directives such as
#ifdef WITH_OLED_DISPLAY
display = new RealDisplay();
#else
display = new MockDisplay();
#endif
allow to include or exclude some code from the compilation (not just from the execution) depending on the presence of flags on the compilation options in the platformio.ini file.
For instance
build_flags = !python gitVersion.py -std=gnu++17 -DWITH_OLED_DISPLAY
will result in having the code display = new RealDisplay(); compiled and executed, but not the
code display = new MockDisplay();
As for the mock classes, they allow to not have to use the compilation directives everywhere in the code, which is hard to read and maintain.
In the example above, the MockDisplay class has the exact same methods as the RealDisplay class, but they do nothing. This way, each time we want to display something we call the method to do so without worrying about the display availability, and if there is no physical display, it does not break, it just does nothing by calling the mock display class methods.
Here is a full example of the Optional OLED screen display
Quite often, features might need values that should be adjustable, either once for all by iterative testing, or depending on each user for instance.
Some 'Experiments settings" have been implemented to allow you to have values that can be adjusted from the control apps (running on your Android phone or your computer) without requiring you to update these apps.
There are four booleans, b_1, b_2, b_3, b_4
Four strings s_1, s_2, s_3, s_4
and four integers i_1, i_2, i_3, i_4
Which are exposed on the PC application:

And the Android app:
(screen capture soon)
These settings have generic names, since I don't know how you will use them.
In the firmware you can access them by their name through the setting object instantiated at initialization:
// Let's read offset and threshold from all-purpose "experiment" settings
int offset = settings->getInt("i_1", 380);
int threshold = settings->getInt("i_2", 2);
The second parameter is the default value, in case they have not been initialized from the App yet.
Ideally, once the new feature works fine, and if the code is to be merged into the main branch of this repository, they should be replaced with new specific settings, freeing the "experiments" settings for new experimentations. But of course this will require modifying the applications to expose these new settings.