├── tcr_dimensions.png ├── README.md ├── tiny_code_reader_back.svg ├── qwiic_connector.svg └── tiny_code_reader_front.svg /tcr_dimensions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonshine-ai/tiny_code_reader_docs/HEAD/tcr_dimensions.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tiny Code Reader Developer Guide 2 | *Author [pete@usefulsensors.com](mailto:pete@usefulsensors.com), permanent link is [usfl.ink/tcr_dev](https://usfl.ink/tcr_dev)* 3 | 4 | ## Introduction 5 | 6 | The [Tiny Code Reader](https://usfl.ink/tcr) from [Useful Sensors](https://usefulsensors.com) 7 | is a small, low-cost hardware module that reads QR codes. It's designed to be 8 | a simple way to provision a system, for example by providing the wifi network 9 | name and password, or to provide input when there's no keyboard. 10 | 11 | This guide will explain what information the module can return, how to interpret 12 | that information, and how to integrate with a microcontroller like an Arduino or 13 | Raspberry Pi. You will need a basic understanding of electronics, enough to 14 | integrate a temperature sensor for example, but very little coding is required. 15 | 16 | * [Getting it Working](#getting-it-working) 17 | + [Connecting](#connecting) 18 | + [Mounting](#mounting) 19 | + [Powering Up](#powering-up) 20 | + [Reading Data](#reading-data) 21 | * [Configuration](#configuration) 22 | * [Sensor Characteristics](#sensor-characteristics) 23 | * [Example Code](#example-code) 24 | + [Useful Sensors Examples](#useful-sensors-examples) 25 | - [CircuitPython](#circuitpython) 26 | - [MicroPython](#micropython) 27 | - [Arduino](#arduino) 28 | - [Raspberry Pi Pico](#raspberry-pi-pico) 29 | - [Raspberry Pi](#raspberry-pi) 30 | - [Micro:bit](#microbit) 31 | - [Badger 2040](#badger-2040) 32 | + [Community Examples](#community-examples) 33 | * [Privacy](#privacy) 34 | * [Acknowledgements](#acknowledgements) 35 | * [Appendix](#appendix) 36 | + [Data Format](#data-format) 37 | + [C Struct Format](#c-struct-format) 38 | + [Python Data Format Strings](#python-data-format-strings) 39 | + [CAD File](#cad-file) 40 | + [Datasheet](#datasheet) 41 | + [Pre-production Modules](#pre-production-modules) 42 | 43 | ## Getting it Working 44 | 45 | Internally the Tiny Code Reader bundles an image sensor and a small 46 | microcontroller into a single board, but to make it as easy as possible to 47 | build into products we’ve tried to hide those implementation details. It 48 | returns information about any QR codes it sees over an I2C connection. 49 | 50 | ### Connecting 51 | The board uses a standard Qwiic connector for the I2C interface. This is 52 | designed so you can only plug it in one way, but the individual lines are shown 53 | in the diagram below for reference. You can find more information about this 54 | form factor at [SparkFun’s Qwiic page](https://www.sparkfun.com/qwiic), but it’s 55 | now widely supported by a lot of vendors, including with [Adafruit’s Stemma QT connector](https://learn.adafruit.com/introducing-adafruit-stemma-qt/what-is-stemma-qt). 56 | SparkFun also have a [guide for connecting to a Raspberry Pi](https://learn.sparkfun.com/tutorials/qwiic-hat-for-raspberry-pi-hookup-guide), 57 | and [another for Arduino Nanos](https://learn.sparkfun.com/tutorials/sparkfun-qwiic-shield-for-arduino-nano-hookup-guide). If you're using a standard 58 | connector, the wire colors are yellow for SCL, blue for SDA, red for 3.3V, and 59 | black for GND. 60 | 61 | The sensor supports I2C bus speeds of up to 400k baud. We expect 62 | 3.3V power, other voltage levels are not supported. 63 | 64 | ![Qwiic Connector Diagram](qwiic_connector.svg) 65 | 66 | ### Mounting 67 | 68 | The sensor uses an image sensor internally, so you need to make sure that the 69 | lens has a clear field of view. It can be mounted in any orientation, that 70 | shouldn't affect the code recognition quality. There's a mounting hole for a 71 | screw in the top left, and some alternative pads in case you don't want to use 72 | a QWIIC connector but want to wire in directly. The edge with these pads is 73 | designed to snap off, in case you need to reduce the size of the board further. 74 | 75 | ![Front of sensor](tiny_code_reader_front.svg)![Back of sensor](tiny_code_reader_back.svg) 76 | 77 | ![Module dimensions](tcr_dimensions.png) 78 | 79 | ### Powering Up 80 | 81 | Before you start trying to read information from the sensor, a good first step 82 | is to power it up and make sure it seems to be working correctly. To do this 83 | connect the GND and 3.3V lines from your microcontroller to the sensor. If 84 | you’re using a Qwiic socket on the MCU you’ll also be connecting the SDA and SDC 85 | automatically, but if you’re breaking out to individual pins don’t worry about 86 | them yet. With the sensor powered, bring up [a simple QR code](https://en.wikipedia.org/wiki/QR_code#/media/File:QR_code_for_mobile_English_Wikipedia.svg) 87 | on your phone and place it about fifteen centimeters or six inches in front of 88 | the module, facing the camera. You should see the LED on the front of the board 89 | rapidly flashing blue, and then turn green when the QR code is detected. It may 90 | take a bit of wiggling and moving back and forth to get a detection. 91 | 92 | ### Reading Data 93 | 94 | Once you have the sensor connected and mounted, you’ll want to start reading 95 | information from it. The code you use to do this will depend on the platform 96 | you’re using for the main controller device, but [here’s some C example code for 97 | a Raspberry Pi Pico](https://github.com/usefulsensors/tiny_code_reader_pico_c). 98 | The 7-bit peripheral address for the sensor is 0x0C, or 12 in decimal. Please 99 | note that some systems include the read/write bit in the address, making the 100 | 8-bit peripheral address 0x18 or 0x19. 101 | 102 | ```C 103 | if (!tiny_code_reader_read(&results)) { 104 | printf("No code results found on the i2c bus\n"); 105 | sleep_ms(SAMPLE_DELAY_MS); 106 | continue; 107 | } 108 | 109 | if (results.content_length == 0) { 110 | printf("No code found\n"); 111 | } else { 112 | printf("Found '%s'\n", results.content_bytes); 113 | } 114 | ``` 115 | 116 | This shows how you read data from the peripheral. That data is a 16-bit 117 | unsigned integer containing the length of the read QR code content, followed by 118 | the content itself in a 254 byte array. If no QR code has been seen in the last 119 | scan period, the length will be zero, and so will the content array. If the 120 | length is greater than zero, any bytes after the end of the content will be set 121 | to zero, guaranteeing a zero-terminated string. 122 | 123 | The content will typically be a UTF-8-encoded Unicode string, but it's not 124 | guaranteed to be. As with all user inputs, you should sanitize and escape it 125 | before using it for anything sensitive. You can think of the reader like an 126 | input box on a website - users can enter whatever they want so it's important 127 | to check if you're using it to control system behavior. 128 | 129 | ## Configuration 130 | 131 | The only behavior that's configurable is the module's LED. By default it 132 | flashes blue while scanning, green when a valid QR code has been detected, and 133 | red when there was an error decoding the QR code. By writing 0x00 to register 134 | address 0x01 you can turn the LED off entirely. 135 | 136 | | Address | Name | Default | Description | 137 | | ------- | ---- | ------- | ----------- | 138 | | 0x01 | LED | 0x01 (On) | Set to zero to turn off LED | 139 | 140 | ## Reader Characteristics 141 | 142 | The module relies on an image sensor and computer vision to read QR codes, so 143 | it does require some illumination to work. The image sensor doesn’t include an 144 | IR filter, so using near-IR illumination from an LED should be possible in 145 | situations where visible light is not available, but we haven’t characterized 146 | the accuracy of the sensor in those conditions. 147 | 148 | The reader works best with comparatively simple QR codes (20 characters or 149 | less) but the only hard limit on the size is the 254 byte content array. The 150 | module is designed to be small and low cost, and so will not have the same 151 | accuracy and range of larger, more expensive commercial readers. 152 | 153 | The sensor has approximately a 110 degree field of view. 154 | 155 | The model runs about five times a second. The latency is approximately the time 156 | to perform one model iteration, so roughly 200 milliseconds. There's no 157 | pin raised raised when a QR code is found, so you will need to keep polling to 158 | catch recognitions. 159 | 160 | This version of the board requires 3.3V input, and consumes about 100 milliwatts 161 | of power (with about 5mW going to the LED when active). 162 | 163 | ## Example Code 164 | 165 | ### Useful Sensors Examples 166 | 167 | We have written samples for some of the most popular development platforms. 168 | 169 | #### CircuitPython 170 | 171 | [github.com/usefulsensors/tiny_code_reader_circuit_python](https://github.com/usefulsensors/tiny_code_reader_circuit_python) 172 | 173 | [github.com/usefulsensors/tiny_code_reader_trinkey_keyboard](https://github.com/usefulsensors/tiny_code_reader_trinkey_keyboard) 174 | 175 | #### MicroPython 176 | 177 | [github.com/usefulsensors/tiny_code_reader_wifi_micropython](https://github.com/usefulsensors/tiny_code_reader_wifi_micropython) 178 | 179 | #### Arduino 180 | 181 | [github.com/usefulsensors/tiny_code_reader_arduino](https://github.com/usefulsensors/tiny_code_reader_arduino) 182 | 183 | #### Raspberry Pi Pico 184 | 185 | [github.com/usefulsensors/tiny_code_reader_pico_c](https://github.com/usefulsensors/tiny_code_reader_pico_c) 186 | 187 | #### Raspberry Pi 188 | 189 | #### Micro:bit 190 | 191 | [github.com/usefulsensors/tiny_code_reader_micro_bit](https://github.com/usefulsensors/tiny_code_reader_micro_bit) 192 | 193 | #### Badger 2040 194 | 195 | [github.com/usefulsensors/tiny_code_reader_badger](https://github.com/usefulsensors/tiny_code_reader_badger) 196 | 197 | 198 | ### Community Examples 199 | 200 | We also love to feature projects created by makers, so if you'd like to see your 201 | guide, tutorial, or GitHub repo featured here, please send us a pull request 202 | adding it to this section of the documentation. We also collect maker guides at 203 | [our Hackster project hub](https://www.hackster.io/useful-sensors/projects). 204 | 205 | ## Privacy 206 | 207 | This module includes an image sensor, and we want to make sure that this doesn’t 208 | pose a threat to any of our users’ privacy. We’ve designed the module so that it 209 | is as resistant as possible to anyone accessing the raw image data, and only the 210 | metadata derived from each frame is available. We’ve also built it to have as 211 | slim an interface as possible, to reduce the possibility of malicious 212 | interference and make it simpler for third parties to audit our privacy claims. 213 | 214 | This approach does constrain what developers can do with the device. One obvious 215 | restriction is that we don’t allow you to access the image data, but we also 216 | don’t support flashing the firmware or model updating, because doing so could 217 | allow unchecked changes to the sensor’s behavior. Even though there’s a 218 | microcontroller on the board, we’re hoping that you’ll be able to get enough 219 | value out of its pre-programmed behavior to compensate for the inconvenience of 220 | this user protection approach. 221 | 222 | If you’re interested in learning more about this approach to system design, we 223 | have a [research paper describing what we call Machine Learning Sensors](https://arxiv.org/pdf/2206.03266.pdf). 224 | 225 | ## Acknowledgements 226 | 227 | This module uses an RP2040 MCU from Raspberry Pi to run the QR code recognition. It's been a great piece of hardware to work with, with more RAM and 228 | compute than anything else in its class. 229 | 230 | We have found the [zxing-cpp](https://github.com/zxing-cpp/zxing-cpp) a very 231 | well-written and maintained source of information on barcode decoding in general 232 | and QR codes in particular. Useful Sensors is proud to be a sponsor of the 233 | project and we encourage anyone who finds these sensors useful to [do so too](https://github.com/sponsors/axxel). 234 | 235 | Lee Jackson at [Arducam](https://arducam.com) has been a fantastic help 236 | sourcing high-quality, low-cost camera modules. If you need imaging solutions 237 | for your microcontroller projects I highly recommend [talking to him](mailto:admin@arducam.com). 238 | 239 | ## Appendix 240 | 241 | ### Data Format 242 | 243 | The inference result is stored as an array of bytes in the following format. 244 | Information about each member is described in detail above. 245 | 246 | | Byte Offset | Meaning | 247 | | ----------- | ------- | 248 | | 0 | Content Length (first byte) | 249 | | 1 | Content Length (second byte) | 250 | | 2 | Content Byte #0 | 251 | | 3 | Content Byte #1 | 252 | | ... | ... | 253 | | 256 | Content Byte #254 | 254 | 255 | ### C Struct Format 256 | 257 | The most up to date versions of these data structures can be found at [github.com/usefulsensors/tiny_code_reader_pico_c/blob/main/person_sensor.h](github.com/usefulsensors/tiny_code_reader_pico_c/blob/main/tiny_code_reader.h), 258 | but for reference here is a C struct version of the data format. The 259 | non-standard but commonly supported `packed` attribute is used to ensure no 260 | extra padding is introduced. 261 | 262 | ```C 263 | typedef struct __attribute__ ((__packed__)) { 264 | uint16_t content_length; 265 | uint8_t content_bytes[254] 266 | } tiny_code_reader_results_t; 267 | ``` 268 | 269 | ### Python Data Format Strings 270 | 271 | A complete CircuitPython example of decoding the sensor data can be found at [github.com/usefulsensors/tiny_code_reader_circuit_python/blob/main/code.py](github.com/usefulsensors/tiny_code_reader_circuit_python/blob/main/code.py), 272 | but the format strings for struct decoding can be summarized as: 273 | 274 | ```Python 275 | TINY_CODE_READER_LENGTH_FORMAT = "H" 276 | TINY_CODE_READER_MESSAGE_SIZE = 254 277 | TINY_CODE_READER_MESSAGE_FORMAT = "B" * TINY_CODE_READER_MESSAGE_SIZE 278 | TINY_CODE_READER_I2C_FORMAT = TINY_CODE_READER_LENGTH_FORMAT + TINY_CODE_READER_MESSAGE_FORMAT 279 | ``` 280 | 281 | ### CAD File 282 | 283 | [Here is a STEP file containing a model of the sensor](TCR_STEP.step). 284 | 285 | ### Datasheet 286 | 287 | [Here is a datasheet containing technical specifications for the module](https://usfl.ink/tcr_ds). 288 | 289 | ### Pre-production Modules 290 | 291 | Ahead of the full release we have given away a limited number of prototype 292 | modules with slightly older firmware versions. If you have bought a module, 293 | then it will be the final release version, but if you have received one of the 294 | pre-production versions through a contest of giveaway, it should function in a 295 | very similar way. Here are the differences: 296 | 297 | - The LED will be brighter, flashes green instead of blue, and there's no option to disable it. 298 | - The 256 byte result structure doesn't contain zeroes after the main message content. The contents are undefined, so you'll need to be careful to take the valid substring rather than decoding and relying on a zero terminator. All of the example code should handle this. -------------------------------------------------------------------------------- /tiny_code_reader_back.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /qwiic_connector.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tiny_code_reader_front.svg: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------