diff --git a/README.md b/README.md index 46c3b264..ba585f91 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Note: the ordering and assembly guides have not yet been updated for the beta v2 - [Classic controller](#classic-controller-electronics-deprecated) + [Miscellaneous Tools](#miscellaneous-tools) - [Flaps and Fonts](#flaps-and-fonts) + - [Combined Front Panel Generator](#combined-front-panel-generator) - [3D Printed Tools](#3d-printed-tools) - [Chainlink Driver Tester](#chainlink-driver-tester) * [Code](#code) @@ -109,7 +110,7 @@ The mechanical/structural components are made from laser-cut 3mm MDF or acrylic, You can view an interactive 3d model of the design [here](https://scottbez1.github.io/splitflap/embed.html?branch=master). -The beta v2 mechanical design officially supports variants with 52 flaps (perfect for use with the new ["Epilogue" printed flaps](https://www.etsy.com/listing/1685633114/)) and 40 flaps. But you can always modify the design to customize it further. +The beta v2 mechanical design officially supports variants with 52 flaps (perfect for use with the new ["Epilogue" printed flaps](https://bezeklabs.etsy.com/listing/1685633114/)) and 40 flaps. But you can always modify the design to customize it further. ### Stable v0.7 (40-flap modules) ![2d laser cut rendering](https://s3.amazonaws.com/splitflap-artifacts/refs/tags/v0.7/3d/3d_laser_raster.png) @@ -170,19 +171,18 @@ power management/distribution and fault monitoring, UART and RS-485 connections, Each module needs a hall-effect sensor for start-up calibration and fault monitoring. #### Sensors for stable v0.7 hardware -Older sensors for the v0.7 and older laser-cut hardware can be found in the [tagged sensor release](https://github.com/scottbez1/splitflap/releases/tag/releases%2Fsensor%2Fv1.1) +Older sensors for the v0.7 and older laser-cut hardware can be found in the [tagged sensor release](https://github.com/scottbez1/splitflap/releases/tag/releases%2Fsensor%2Fv1.1). + +These older sensors are not compatible with v2 laser-cut hardware. -#### Sensors for v0.7 legacy laser-cut hardware -Older sensors for the v0.7 and older laser-cut hardware can be found in the [tagged sensor release](https://github.com/scottbez1/splitflap/releases/tag/releases%2Fsensor%2Fv1.1) - - - - +#### Beta Sensors v2 + + @@ -190,9 +190,14 @@ Older sensors for the v0.7 and older laser-cut hardware can be found in the [tag - + +New sensors for the v2 laser-cut hardware - these use surface mount components and are optimized for PCB assembly at JLCPCB. These new sensors are not compatible with v0.7 and older laser-cut hardware. + +Packs of 6 sensors are [available mostly-assembled in the Bezek Labs store](https://bezeklabs.etsy.com/listing/1696745674), +and come with the right-angle pin headers and magnets you'll need. Purchases support continued development of this project. + Latest auto-generated (untested!) artifacts:warning:: * Schematic [pdf](https://s3.amazonaws.com/splitflap-artifacts/master/electronics-v2/sensor_smd-schematic.pdf) @@ -207,6 +212,7 @@ Latest auto-generated (untested!) artifacts:warning:: * PCB gerbers [zip](https://s3.amazonaws.com/splitflap-artifacts/master/electronics-v2/sensor_smd-panelized-jlc/gerbers.zip) * PCB BOM (for JLCPCB assembly) [csv](https://s3.amazonaws.com/splitflap-artifacts/master/electronics-v2/sensor_smd-panelized-jlc/bom.csv) * PCB CPL (for JLCPCB assembly) [csv](https://s3.amazonaws.com/splitflap-artifacts/master/electronics-v2/sensor_smd-panelized-jlc/pos.csv) +* Purchase sensor kits in the US: [Bezek Labs](https://bezeklabs.etsy.com/listing/1696745674) :warning:For tested/stable/recommended artifacts, use the [latest release](https://github.com/scottbez1/splitflap/releases) instead @@ -224,7 +230,7 @@ for easy SMD/THT assembly to validate data integrity up and down the whole chain * Module order goes from right-to-left since this is intended to be installed and accessed from *behind* the modules -Chainlink Driver boards are [available mostly-assembled in the Bezek Labs store](https://www.etsy.com/listing/1123280069/splitflap-chainlink-driver-v11), +Chainlink Driver boards are [available mostly-assembled in the Bezek Labs store](https://bezeklabs.etsy.com/listing/1123280069/splitflap-chainlink-driver-v11), and come with the additional connectors and ribbon cables you'll need. Purchases support continued development of this project. More information on building and using Chainlink Drivers is available in the [Chainlink Driver User Guide](https://paper.dropbox.com/doc/Chainlink-Driver-v1.1-Electronics-User-Guide--BW2lxdjVkAxva68kYw2doWQEAg-U0DAXrSxEoOhgSoRU39hq). @@ -272,7 +278,7 @@ and then run a wire from the onboard screw terminals to the Chainlink Driver's m * Optional 5V regulator allows for powering the ESP32 without a USB connection, using the 12V motor power supply -Chainlink Buddy \[T-Display\] boards are [available in the Bezek Labs store](https://www.etsy.com/listing/1109357786/splitflap-chainlink-buddy-t-display), +Chainlink Buddy \[T-Display\] boards are [available in the Bezek Labs store](https://bezeklabs.etsy.com/listing/1109357786/splitflap-chainlink-buddy-t-display), and come with the additional connectors you'll need. Purchases support continued development of this project. @@ -302,7 +308,7 @@ Latest auto-generated (untested!) artifacts:warning:: The Chainlink Buddy \[Breadboard\] makes it easy to connect a Chainlink Driver to a breadboard for prototyping. You could use 5 dupont wires and have a messy rats nest, or you could use a single ribbon cable and this slick breakout board. -Chainlink Buddy \[Breadboard\] boards are [available in the Bezek Labs store](https://www.etsy.com/listing/1123863267/splitflap-chainlink-buddy-breadboard), +Chainlink Buddy \[Breadboard\] boards are [available in the Bezek Labs store](https://bezeklabs.etsy.com/listing/1123863267/splitflap-chainlink-buddy-breadboard), and come with the additional connectors you'll need. Purchases support continued development of this project. @@ -392,6 +398,20 @@ that is extremely configurable: * Front/back - for batch duplex printing, generate separate front-side and back-side files (e.g. sign shop printing on a flat sheet of PVC) * Side-by-side - for individual flap printing, each flap's front design is laid out side-by-side with its back design +TODO: finish documenting this and render some example images... + +#### Combined Front Panel Generator +If you'd like to share a single front face across multiple modules (rather than each module having its own front face), the repo +includes a script to generate a combined front panel for laser-cutting or CNC milling/routing. + +You can modify: +* Number of rows and columns +* Horizontal and vertical spacing/separation of modules +* Overall outer width and height of the panel + +For CNC cutting, the script supports rendering a vector file optimized for thicker material (e.g. 6mm MDF) where only the bolt-holes will be through-cut. In this mode, the slots for the top/bottom enclosure pieces can be cut as ~4mm pockets so they aren't visible from the front face. The script automatically generates dog-bone shapes for these pocket cuts. + + TODO: finish documenting this and render some example images... #### 3D Printed Tools @@ -454,53 +474,56 @@ The driver firmware is written using PlatformIO with the Arduino framework and i The firmware implements a closed-loop controller that accepts letters as input over USB serial and drives the stepper motors using a precomputed acceleration ramp for smooth control. The firmware automatically calibrates the spool position at startup, using the hall-effect magnetic sensor, and will automatically recalibrate itself if it ever detects that the spool position has gotten out of sync. If a commanded rotation is expected to bring the spool past the "home" position, it will confirm that the sensor is triggered neither too early nor too late; otherwise it will search for the "home" position to get in sync before continuing to the desired letter. -### Computer Control Software -The display can be controlled by a computer connected to the Arduino over USB serial. A basic python library for interfacing with the Arduino and a demo application that displays random words can be found in the [software](software) directory. +### Serial protocol +In order for a computer to communicate with the splitflap, it appears as a USB serial device. -Commands to the display are sent in a basic plain-text format, and messages _from_ the display are single-line JSON objects, always with a `type` entry describing which type of message it is. +However, usage of Arduino’s `Serial` is strictly forbidden, and instead a `logger` abstraction is provided for sending basic text debug logs. Other data is transferred in a structured way, described below. -When the Arduino starts up, it sends an initialization message that looks like: -``` -{"type":"init", "num_modules":4} -``` +This allows flexibility in the format of data transferred over serial, and in fact the splitflap provides 2 different serial modes that serve different purposes. -The display will automatically calibrate all modules, and when complete it will send a status update message: -``` -{ - "type":"status", - "modules":[ - {"state":"normal", "flap":" ", "count_missed_home":0, "count_unexpected_home":0}, - {"state":"sensor_error", "flap":"e", "count_missed_home":0, "count_unexpected_home":0}, - {"state":"sensor_error", "flap":"e", "count_missed_home":0, "count_unexpected_home":0}, - {"state":"sensor_error", "flap":"e", "count_missed_home":0, "count_unexpected_home":0} - ] -} -``` -(Note: this is sent as a single line, but has been reformatted for readability above) -In this case the Arduino was programmed to support 4 modules, but only 1 module is connected, so the other 3 end up in `"sensor_error"` state. More on status updates below. +#### Plaintext mode -At this point you can command the display to show some letters. To do this, send a message to the Arduino that looks like this: +By default, it starts in “plaintext” mode, which is developer-friendly and you’re probably familiar with if you’ve opened a serial monitor with the splitflap connected: ``` -=hiya\n +{"type":"init", "num_modules":6} ``` -The `=` indicates a movement command, followed by any number of letters, followed by a newline. You don't have to send the exact number of modules - if you send fewer letters than modules, only the first N modules will be updated and the remainder won't move. For instance, you could send `=a\n` as shorthand to only set the first module (even if there are 12 modules connected). Any letters that can't be displayed are considered a no-op for that module. -Whenever ALL modules come to a stop, the Arduino will send a status update message (just like the one following initialization, shown above). Here's what the fields mean in each module's status entry: -- **state** - `normal` indicates it's working as intended, `sensor_error` indicates the module can't find the home position and has given up trying (it will no longer respond to movement commands until told to recalibrate - see below). `panic` indicates the firmware detected a programming bug and has gone into failsafe mode (it will no longer respond to movement commands and requires a full reset of the Arduino to recover - should never happen). -- **flap** - which letter is shown by this module -- **count\_missed\_home** - number of times the module expected to pass the home position but failed to detect it. If this is non-zero, it indicates either a flaky sensor or that the motor may have jammed up. The module automatically attempts to recalibrate whenever it misses the home position, so if this number is non-zero and the module is still in the `normal` state, it means the module successfully recovered from the issue(s). However, if this number keeps going up over continued use, it may indicate a recurrent transient issue that warrants investigation. -- **count\_unexpected\_home** - number of times the module detected the home position when it wasn't supposed to. This is rare, but would indicate a flaky/broken sensor that is tripping at the wrong time. Just like with missed home errors, unexpected home errors will cause the module to attempt to recalibrate itself. +However, this isn’t great for programmatically configuring or receiving updates from the splitflap, so instead the firmware offers a programmatic interface using a binary protocol based on Google’s Protobuf standard. -If you want to make all modules recalibrate their home position, send a single @ symbol (no newline follows): -``` -@ -``` -This recalibrates all modules, including any that were in the `sensor_error` state; if recalibration succeeds they will return to the `normal` state and start responding to movement commands again. +#### Protobuf (binary/programmatic) mode + +The protobuf-based binary serial mode is a compact and flexible way to transfer structured data from the host computer to the splitflap and vice-versa. + + +##### Benefits of protobuf +protobuf provides several benefits over other encoding mechanisms like JSON: + +1. Well-defined schema. If you’re curious about the format of data to expect or send, you just need to check the protobuf file +2. Code generation. Instead of hand-writing JSON parsers every time the data changes, protobuf provides code generation of the encoding and decoding logic, and data-structures. Splitflap uses nanopb to generate C structs based off the schema, and all the code for encoding/decoding that data from the binary format. +3. Relatively compact/efficient wire encoding. It’s not a primary goal in this project, but the binary wire encoding is generally fairly compact, due to omitting default/unspecified fields, using variable length encodings, etc. It’s certainly much more compact than JSON which uses strings to describe every field in every message. +4. Backwards/forwards compatibility. Not super relevant to this project, but many common schema changes are backwards and forwards compatible, meaning an older client or a newer client will be able to handle them gracefully. +##### Disadvantages of protobuf + +1. Not human-readable. This makes it much harder to debug, as you need something that can interpret messages. Since they’re binary, viewing anything in a terminal directly will be fruitless. +2. Not self-describing. If you come across a JSON document, you can generally tell what it means because fields have string names/labels describing their contents. Protobuf has no such thing (it uses integer field numbers, which does make renaming fields easier) so you need to have a copy of the schema (.proto file - and you’d better hope it matches the data!) in order to understand an encoded message. + +This is why the splitflap defaults to plaintext mode to make basic validation/debugging easier. + +##### How it works +Protobuf messages are encoded to their binary wire format and a CRC32 checksum appended. Then that entire binary string is COBS encoded into a packet, and delimited/framed by 0 (NULL) bytes when sent over serial. This provides a basic packet-based interface with integrity checks (rather than the raw, stream-based interface of a serial connection). + +The splitflap automatically switches to binary protobuf mode when it receives a 0 byte. + + +### Computer Control Software +The display can be controlled by a computer connected to the ESP32 over USB serial. If you've built a display and want to test it out, check out the web-based demo [here](https://scottbez1.github.io/splitflap) which will connect to your display using USB - no applications/installation necessary! +The firmware supports a plaintext serial mode (enabled by default) for ease of testing, and a protobuf-based binary mode used by the software libraries for enhanced programmatic control and feedback. +You can find example Typescript and Python libraries in the [`software/chainlink`](software/chainlink) folder. # Contributing/Modifying @@ -562,7 +585,7 @@ I'd love to hear your thoughts and questions about this project, and happy to in This project is licensed under Apache v2 (see [LICENSE.txt](LICENSE.txt)). - Copyright 2015-2021 Scott Bezek and the splitflap contributors + Copyright 2015-2024 Scott Bezek and the splitflap contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.