From 35817c221915cd86e26a31462f4735bbb382ca38 Mon Sep 17 00:00:00 2001 From: marble Date: Tue, 2 Dec 2025 22:00:01 +0100 Subject: [PATCH] minor changes --- LICENSE | 21 ++++++++++ README.md | 29 ++++++++++++++ button.py | 47 ++++++++++++++++++++++ main.py | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ shell.nix | 12 ++++++ 5 files changed, 226 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 button.py create mode 100644 main.py create mode 100644 shell.nix diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c038d63 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Geheimorganisation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2168c9e --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Geheimbadge Firmware +This is the Geheimbadge firmware. +It wares the Geheimbadge firm. + +## Deployment +Run `nix-shell` in this repo to enter an environment with all necessary tools. +Replace `/dev/ttyACM0` with the correct port for your system. + +### Micropython +Download the latest [Firmware Release](https://micropython.org/download/esp32c6/) .bin file. +Flash the firmware using [esptool](https://github.com/espressif/esptool). + +```shell +esptool.py --chip esp32c6 --port /dev/ttyACM0 erase_flash +esptool.py --chip esp32c6 --port /dev/ttyACM0 write_flash -z 0x0 esp32c6-20241129-v1.24.1.bin +``` + +### Scripts +Deployment via [rshell](https://github.com/dhylands/rshell) is recommendet. + +```shell +rshell --port /dev/ttyACM0 "cp ./*.py /pyboard" +``` + +### WiFi Config +Copy `sta-template.json` to `sta.json` and edit. +```shell +rshell --port /dev/ttyACM0 "cp ./sta.json /pyboard" +``` diff --git a/button.py b/button.py new file mode 100644 index 0000000..ce65a81 --- /dev/null +++ b/button.py @@ -0,0 +1,47 @@ +from machine import Pin, Timer +from time import ticks_ms + + +class Button: + def __init__(self, pin_num, pull=Pin.PULL_UP, thresholds_ms=[1000, 3000]): + self.pin = Pin(pin_num, Pin.IN, pull) + self.pin_state = 1 if Pin.PULL_UP else 0 + self.thresholds_ms = thresholds_ms + self.threshold_idx = 0 + self.timer = Timer() + + self.pin.irq(self._isr) + + def _timer_cb(self, timer): + self.threshold_idx += 1 + if self.threshold_idx < len(self.thresholds_ms): + timer.init( + period=self.thresholds_ms[self.threshold_idx] + - self.thresholds_ms[self.threshold_idx - 1], + mode=Timer.ONE_SHOT, + callback=self._timer_cb, + ) + + if self.callback_fn: + self.callback_fn(self.pin_state, self.threshold_idx) + + def _isr(self, pin): + pin_state = pin() + if pin_state != self.pin_state: + self.pin_state = pin_state + + if pin_state == 0: + self.threshold_idx = 0 + self.timer.init( + period=self.thresholds_ms[self.threshold_idx], + mode=Timer.ONE_SHOT, + callback=self._timer_cb, + ) + else: + self.timer.deinit() + + if self.callback_fn: + self.callback_fn(pin_state, self.threshold_idx) + + def callback(self, fn): + self.callback_fn = fn diff --git a/main.py b/main.py new file mode 100644 index 0000000..c645c7f --- /dev/null +++ b/main.py @@ -0,0 +1,117 @@ +from machine import Pin, ADC +from button import Button +from time import sleep, time, sleep_us + +DEAD_ZONE = 0.125 +TIMEOUT = 10 +GAMMA = 1 +DELAY_MIN_US = 500 +DELAY_MAX_US = 100000 + +class Motor: + _LUT = [ + (1, 0, 0, 0), + (1, 1, 0, 0), + (0, 1, 0, 0), + (0, 1, 1, 0), + (0, 0, 1, 0), + (0, 0, 1, 1), + (0, 0, 0, 1), + (1, 0, 0, 1), + ] + + def __init__(self, pins, phase=0): + self._pins = pins + self._phase = phase + + def update_pins(self): + pattern = self._LUT[self._phase] + for pin, value in zip(self._pins, pattern): + pin(value) + + def step(self, dir): + dir = 1 if dir > 0 else -1 if dir < 0 else 0 + self._phase = (self._phase + dir) % len(self._LUT) + self.update_pins() + + def inc(self): + self.step(1) + + def dec(self): + self.step(-1) + + @property + def phase(self): + return self._phase + + def off(self): + for pin in self._pins: + pin(0) + + +class Joystick: + _OFFSET = 30000 + _RANGE = 2**16 + + def __init__(self, adcs): + self._adcs = adcs + + def pos(self): + return [2 * adc.read_u16() / self._RANGE - 1 for adc in self._adcs] + + +# motor = Motor([Pin(i, Pin.OUT) for i in range (4)]) +motors = [Motor([Pin(2 + i + 4 * j, Pin.OUT) for i in range(4)]) for j in range(3)] +motor_idx = 3 +joystick = Joystick([ADC(i) for i in range(2)]) +rgb_led = [Pin(20 - i, Pin.OUT) for i in range(3)] +for led in rgb_led: + led(0) + +button = Button(22, thresholds_ms=[1000]) + + +def button_cb(pin_state, threshold): + global motor_idx + if pin_state == 0 and threshold > 0: + motor_idx = (motor_idx + 1) % 4 + for i in range(len(rgb_led)): + rgb_led[i](1 if i == motor_idx or motor_idx == 3 else 0) + + +button.callback(button_cb) + +for i in range(len(rgb_led)): + rgb_led[i](1 if i == motor_idx or motor_idx == 3 else 0) + +for motor in motors: + motor.update_pins() + +now = time() + +while True: + joystick_pos = joystick.pos()[1] + abs_pos = abs(joystick_pos) + step_dir =1 if joystick_pos < 0 else -1 + dir = joystick_pos < 0 + + if abs_pos > DEAD_ZONE: + print(joystick_pos, abs_pos) + now = time() + if motor_idx != 3: + motors[motor_idx].step(step_dir) + else: + for motor in motors: + motor.step(step_dir) + + normalized = (abs_pos - DEAD_ZONE) / (1-DEAD_ZONE) + delay_us = DELAY_MIN_US + (DELAY_MAX_US- DELAY_MIN_US) * (1-normalized**GAMMA) + sleep_us(int(delay_us)) + else: + sleep(0.01) + + if time() - now > TIMEOUT: + for motor in motors: + motor.off() + + # sleep(0.0025) diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..fae972e --- /dev/null +++ b/shell.nix @@ -0,0 +1,12 @@ +with import {} ; + +mkShell { + buildInputs = [ + rshell + esptool + (python3.withPackages (p: with p;[ + pyserial + black + ])) + ]; +}