diff options
Diffstat (limited to 'docs/projects')
-rw-r--r-- | docs/projects/byseekel.md | 4 | ||||
-rw-r--r-- | docs/projects/byseekel_scrapped.md | 441 |
2 files changed, 445 insertions, 0 deletions
diff --git a/docs/projects/byseekel.md b/docs/projects/byseekel.md index a0e96c9..ff1f73f 100644 --- a/docs/projects/byseekel.md +++ b/docs/projects/byseekel.md @@ -205,6 +205,10 @@ In the end, they grew so complicated I had to throw them away. ![braking lights, reed, ctrl, LCD, brake and the control panel are crossed out](img/byseekel/feature_creep_removal.png) +2024-02-14 update: There was [another version of this blogpost that +I scrapped and rewrote](byseekel_scrapped.md), where you may find some of +these dead ideas and bad puns. + ### Speedometer & odometer My uni has a required 80km of jogging per semester, tracked by GPS to diff --git a/docs/projects/byseekel_scrapped.md b/docs/projects/byseekel_scrapped.md new file mode 100644 index 0000000..1c0dbbf --- /dev/null +++ b/docs/projects/byseekel_scrapped.md @@ -0,0 +1,441 @@ +# Byseekel (scrapped version) + +> Note: This is the scrapped version of [Byseekel](byseekel.md). I began +> writing this article in early 2022, until I abandoned it 2022-05-02. The +> next year I revived and finished the project, but killed many features. +> That was when I decided to rewrite this blogpost from scratch, with less +> groundless optimism you'd find in this scrapped version. + +> Nevertheless, for archival reasons, I am publishing the scrapped version +> on 2024-02-14. This article is not finished and will not be updated. +> Please disregard any sentence that suggests otherwise. + +> I deleted the images a long time ago, so I put in the alt text instead. + +> Article begins here. + +Freddie Mercury famously sang: + +> I want to ride my bicycle I want to ride my bike +> I want to ride my bicycle I want to ride it where I like + +I, too, own a bicycle, but in terms of performance and condition it is +like crap. I certainly wouldn't take riding my bicycle as much of +a pleasure as Mercury did. This makes me ask myself a question: What do +I need to make a bike trip more enjoyable, or just less painful? + +A [cyclocomputer](https://en.wikipedia.org/wiki/Cyclocomputer). + +Image: Cateye cyclocomputer mounted to a bicycle handlebar. + +Image credit: Wikipedia user +[Mnisawlpsa](https://commons.wikimedia.org/wiki/User:Mnisawlpsa). + +Despite its stupid name (cyclo? computer? smh) it's kinda useful. It keeps +track of the speed and mileage of your bike, and displays them on +a screen. I do know one application where it definitely fits, and that is +cheating the 80-kilometers-of-jogging-per-semester mandate from my school +office. + +Every (able) undergrad in my uni has to accumulate a certain jogging +mileage by the end of each semester. For boys, the number is 80 +kilometers. To track your movement you turn on your phone's GPS and start +jogging. But the loophole is, it can't actually tell if you're jogging, as +long as you keep your speed within 3-9 minutes/km. Experiments show I am +able to maintain a steady 3-5 min/km on a bike and trick the system into +believing I'm legitimately jogging. But even so, I have to pull out my +phone mid-journey — a quite dangerous act, even when no one was around +— to make sure I'm not going too fast. It would be helpful if I had +a device to check that for me and warn me if it exceeds that range. + +Guess what, it'd be extra helpful if it could tell me how far I've cycled. +It'd also be cool if I could integrate this with my previous +semi-successful project, [Bikeblinkers](../bikeblinkers). What if besides +blinkers, it also had a braking light. Hey, since looking for my bike +among 200 others in front of the gate is such a pain, how about something +that would tell me where it is? + +I should totally make a bucket list of features to implement: + +- speedometer +- odometer +- blinkers +- hazard light +- braking indicator +- remote-activated buzzer + +And no, this is so much more than a cyclocomputer. As a tribute to Freddie +Mercury, I'm going to name my project after how he enunciates the word +"bicycle". + +Note: this blogpost is continuously being updated. + +## Hardware + +### MCU (spoiler: it's AVR) + +The project at hand really seems to dwarf [Bikeblinkers](../bikeblinkers) +in terms of complexity, and apparently a single 555 IC simply won't do, +and an MCU is necessary. + +Which MCU? That is one of the most consequential decisions to make. Up to +this point I had a really limited tech stack, because before this one all +I knew was Arduino (in this blogpost I treat the Arduino as a distinct +"MCU", despite its real MCU being ATmega328P), and I hadn't really done +any project that (a) has an MCU, and (b) runs more than one meter away +from a computer and a power source that draws power from the mains. + +"How about Arduino," I thought. However, upon close inspection, the +Arduino isn't all cake. + +- Many Arduino libraries are bloat and inefficient (I'm not judging + though) +- Arduino IDE v1 is a huge pain to use (Yes I am judging here) +- The Arduino has a 3.3V regulator which isn't useful for this project but + consumes quite a substantial chunk of power + +That said, I am really hoping there was some alternative. What I want is +a bare-bones version of Arduino, where I get the freedom to do whatever +I want, but still somehow match the Arduino's capabilities. + +I have a few ATmega328P's lying around, so let's try them. + +🛒 BOM += ATmega328P + +Admittedly, you _can_ embed AVR C/C++ snippets in your `.ino` or +completely write your sketch with it, and if done right it's possible to +compile and download an Arduino sketch onto your average ATmega328P, but +what's the fun? I'm going to ditch Arduino completely here. + +I'm going with avr-gcc and avr-libc, so that I won't touch assembly and as +a bonus practice C which I had been learning for 2/3 of a semester. + +I fetched a copy of datasheet for the ATmega328P and began reading. The +most important information as of now is + +- Pinout (GPIO and SPI) +- IO registers (`PORTB`, `DDRB`, etc.) + +I bought a [USBASP](https://www.fischl.de/usbasp/) to download my code +onto the chip. Well, in fact it's not the code I'm downloading, it's the +hex file obtained by compiling the code, linking the libraries, generating +an elf, then summoning Satan. + +There are three limitations on the specs one ought to care about when +designing software for an AVR chip: + +- Flash size +- SRAM size +- Clock frequency + +The 328P has 32KB flash, 2KB SRAM and a maximum frequency of 20MHz, but of +course we're not using all that much. Of the three what worries me most is +RAM, because after 2/3 of a semester of C I know how hard keeping track of +memory can be, and for some reason my programs easily ate up megabytes on +the OJ. Although 2KB sounds extremely limited, fortunately we don't need +fancy algorithms here. + +So far, all I needed was the I/O functionality, and the most basic +conditionals and loops C has to offer. By lumping up stuff like + +```c +#include <avr/io.h> +#include <util/delay.h> +int main(void) { + DDRB |= _BV(PB5); // set pin direction of PB5 to output + while (1) { + PORTB ^= _BV(PB5); // toggle PB5 + _delay_ms(500); + } +} +``` + +I was able to blink an LED. + +Image: An illuminating LED driven by a DIP-28 ATmega328P on a breadboard + +This was all very basic, equivalent to what you would do with `pinMode` +and `digitalWrite` on an Arduino. Although I was eager to write some +_real_ code, I should figure out how my MCU would sense and react to the +physical world. + +### Input Peripherals + +#### Learn to reed + +To calculate the speed the bicycle is traveling at, we need to count the +number of revolutions. I initially had two ideas: + +- Optical: reflective material on the spokes, IR LED and phototransistor + on the fork; +- Magnetic: reed switch on the fork and a permanent magnet on the spokes. + +The optical solution in theory works like this: + +Image: Diagram showing the location and schematics of the optical sensor + +However, the weaknesses are pretty obvious. + +- Requires power source +- Requires directional alignment +- Requires a minimum of three wires (VCC, GND, output) +- Aluminum foil on a bicycle wheel looks silly +- Electrical noise + +Moreover, the industrial standard for cyclocomputers is reed switches. + +Image: Wired reed switch sensor with spoke mounted magnet. + +Image credit: Wikipedia user +[AndrewDressel](https://en.wikipedia.org/wiki/User:AndrewDressel). + +They should be installed on the rear wheel, because rotations of the rear +wheel are more representative of the real mileage. + +🛒 BOM += reed switch, permanent magnet + +#### Turning big + +In Bikeblinkers my control for the blinker circuit was a tiny SP3T toggle +switch. It's a bit too small, and it was the source of two design errors +in my rev. 1 PCB (look I gotta find someone else to blame okay?) + +Image: A SP3T toggle switch mounted on a PCB + +🛒 BOM += bigger SP3T switch + +I spent a fortune buying one, but it was worth it. Cue the industrial +switch! + +Image: Industrial SP3T switch in metal and plastic casing. It is thrown to the right. + +(ruler in centimeters) + +This is all good and such, but one problem is it's pretty likely you'll go +all the way to the opposite direction when your intention is to throw it +back to neutral. No countermeasure so far. + +In February 2022, I came up with an alternative. This is one of those +blinker switches they use on e-bikes. It has three terminals: left, right, +and common. Flick it to the left, and left connects to common. Flick it to +the right, and right does so. Push the stalk down to disconnect all +terminals. Two models are sold: one that allows three terminals to be +simultaneously connected, and one that doesn't. I picked the former, as +hazard lights are just left and right blinkers on at the same time. + +🛒 BOM += e-bike blinker switches + +Image: A pair of e-bike blinker switches. One of them has its three copper +terminals exposed. +#### Brake it apart + +The brake is a little trickier and as of the time of writing I have one +idea but have absolutely no idea how it would work out in the physical +world. + +Image: Diagram of the location and schematics of the brake switches + +This design taps into movements of the brake handle but not anywhere +further in the braking mechanism, e.g. brake pads. This is because brakes +are a key part to bike safety, and it's stupid to tamper it just for +a braking indicator. + +It comprises of four metal contacts: two on the left, two on the right. Of +each two, one is on the hinge and remains stationary relative to the +bicycle, but the other is somewhere on the moving part, the handle. They +are normally closed, forming an electrical connection. When you pull back +the handle to engage the brake though, they are forced apart, breaking the +continuity. The two pairs are wired in series and act like a single +switch. When it is open, it means at least one brake is engaged, which is +good enough since we don't care which. + +Sure, ugly hack, but having read Arduino forum threads like +[this](https://forum.arduino.cc/t/interfacing-with-a-bicycle-sensing-braking-solved/72661) +it actually isn't _the_ ugliest one, while in my reach in terms of +afforability. + +Problems: + +- I can't think of a way to install them other than superglue +- Rainwater can interfere with the connection, for example shorting a pair + of contacts that are supposed to be open +- The location of contacts have to be super precise +- Exposed wires are a potential cosmetic imperfection (shut up your bike + isn't beautiful anyway) + +🛒 BOM += tiny metal contact plates? is that a thing? + +📋 TODO: install this to prove I'm not an idiot + +#### WhereTheFuck™ + +WhereTheFuck™ (WTF) is a bleeding-edge, innovative and disruptive +technology which augments and accelerates your vehicle retrieving +experience with audiovisual cues. + +OK, it's just a regular bike finder. The components are an RF receiver and +a transmitter at 433MHz, and a LED-beeper combo, which I will show later. + +🛒 BOM += RF TX/RX kit + +I am not a radio expert, so what I bought is this kit. It's a cute +[OOK](https://en.wikipedia.org/wiki/On%E2%80%93off_keying) RF receiver +module capable of detecting four programmable signals, which happens to be +the number of keys the transmitter has. The transmitter is just your +average garage door opener. + +Image: Left to right: four-key RF transmitter with antenna extended, RF +receiver as a small yellow PCB with 7 bent pin headers. + +Looks like I can attach an antenna to the RX module too, so here's a bunch +of them I ordered a few weeks later. + +Image: 10 RF antennae in plastic packaging. They look like coils with tails and +are made of copper. + +📋 TODO: install, find out how effective it is + +### Output Peripherals + +#### Crystal clear + +Sure, we're able to calculate our speed and mileage now, but of course we +will need to display it somehow. For this purpose we will use an LCD. +I have one lying around but it's one of those expensive 12864 models, +which is best for complex graphics and a complete overkill for showing +a bunch of numbers. So I opted for a downgrade, i.e. 1602, which can only +draw characters only (of course, there are hacks which let you draw custom +pixmaps. we won't touch them here) + +🛒 BOM += 1602 LCD + +Image: An LCD with soldered pins + +#### Blinkers, again (also stop lamp) + +On one hand, I could reuse the blinkers for my previous project, +Bikeblinkers. They are working perfectly fine; they're just four sets of +yellow LEDs. I even spent hours designing a 3D printed case, which in the +end was never gestated into the physical world, but I feel it would be +a pity if no one saw it, so here's a picture. + +Image: FreeCAD model of an enclosure for blinkers and a stop lamp + +However I want something big. No, not physically, but it's going to amaze +everyone. + +🛒 BOM += LED strips + +Look at these bright boys! + +Image: 1 meter long red LED strip resting on my lap. It's drawing 654mA at +12.0V from my DC power supply and hella bright + +I bought a red strip for the stop lamp and a yellow one for blinkers, one +meter each which is a plenty amount. Given I cut them in appropriate +lengths, they don't draw much more power than the discrete LEDs do. + +#### WhereTheFuck™ + +My idea for WhereTheFuck™ is, I press a button on my transmitter, and +something on my bicycle flashes and/or makes a loud noise. That is +basically my patent claim. How novel. + +I bought this thingie, which is basically two LEDs and a (really loud) +buzzer, and it fits in a 22mm hole designed for industrial pushbuttons. +When fed 12V it happily beeps on and off thanks to its internal RC +circuitry (it's visible from the holes). + +Image: Buzzer. It's a black plastic cylinder with a transluscent red cap. + +Image: The red lid is removed to reveal two LEDs and a buzzer. + +## Software + +### Oh boy, avr-gcc + +That's right y'all, it's official: I wrote C for AVR. Embedded +programming. One more line on my resume I guess? + +Oh, you're asking me if it's enjoyable? You better ask yourself: is it +really possible to enjoy C? Is it in all plausibility an attainable +outcome that I, a mere mortal of flesh and soul, would have the `__asm__ +__volatile__` in my command, or possess enough power to conquer the army +of CMOS logic gates? No. To write C one must suffer. To control the +silicon, one must first wrestle it, then tame it. + +#### State and global variables + +Global variables are gross, but atop 2,048 bytes of memory there are no +rules. I am representing global state in a pile of global variables. One +of them is called `state`. At the time of writing it holds 5 boolean +states in bits [6..2] (imagine the memory saved compared to 5 ints) and +the two least significant bits represent a finite state of four. + +```c +uint8_t state = 0; +``` + +As you might have expected, reading and writing on `state` is a pain. But +AVR C is full of bitwise stuff anyways, so it doesn't really matter if you +define macros wisely. + +In my `main.h` I defined the following: + +```c +#define BRAKE_BIT _BV(6) +#define BLINKER_L_BIT _BV(5) +#define BLINKER_R_BIT _BV(4) +// ... +``` + +(`_BV(x)` is macro for `1 << x` which is used to create a bitmask, with BV +standing for Bit Value) + +To test a bit, say `BRAKE_BIT`, I need to do: + +```c +if (state & BRAKE_BIT) { /*...*/ } +``` + +And to alter it: + +```c +state |= BRAKE_BIT; // set to one +state &= ~BRAKE_BIT; // set to zero +``` + +#### LCD + +#### Stop lamp + +Despite the hardware implementation being unproven, this is one of the +easiest features in software. There are only two possibilities: + +- braking, and +- not braking + +If it is the former, we turn on the red stop lamp. Otherwise, turn it off. +Here's the code: + +```c +void braking(void) { + if (PIND & BRAKES && !(state & BRAKE_BIT)) { + state |= BRAKE_BIT; + PORTC |= STOPLAMP; + lcd_print("[BR]", 0x19); + } else if (!(PIND & BRAKES) && state & BRAKE_BIT) { + state &= ~BRAKE_BIT; + PORTC &= ~STOPLAMP; + lcd_clear(0x19, 4); + } +} +``` + +...where `STOPLAMP` is a macro for `_BV(PC1)`, the assigned pin. + +#### Blinker + +#### Sleep mode + +#### WhereTheFuck™ |