Skip to content

Alternative Firmware with Dipole Physics Model, Extended Kalman Filter, and 6DoF Normalization and isolation (RP2040 and RP2350) - #56

Open
maximweb wants to merge 56 commits into
sb-ocr:mainfrom
maximweb:ekf-firmware
Open

maximweb wants to merge 56 commits into
sb-ocr:mainfrom
maximweb:ekf-firmware

Conversation

@maximweb

@maximweb maximweb commented Aug 3, 2026

Copy link
Copy Markdown

This is an alternative firmware as initially discussed in #19 .

Heads up: I started from scratch and only later rebased it on the original repo. Sorry for that.

Hardware

  • Environment settings for RP2040 and RP2350
  • RP2350 is pin-compatible, but has builtin hardware-sided floating point support, making it significantly faster for complex filtering
  • Usage of secondary core to perform the filtering while primary core handles buttons, sensor readings, LEDs and HID communication

Firmware

  • Dipole physics model in combination with extended Kalmen filter (EKF)
  • On-device calibration finds each magnets magnetic moment (needed for the physics model) and correct tiny offsets in all 6DoF due to assembly tolerances
  • Normalization and axes isolation as post processing step after the EKF

Settings

There are several aspects which might demand further fine tuning: Quick Tuning Guide

Performance

  • On originally proposed RP2040 I get an average (max) filter duration of 6.6 (7.5) ms -> 150 Hz
  • On the RP2350 I measured roughly 2 ms -> 500 Hz
    • But this was before some recent performance improvements targeting the RP2040.
    • Was not able to test yet on RP2350

maximweb added 30 commits August 3, 2026 21:47
Multicore `multicore_fifo_rvalid()` did not work as expected with RP2040. Hence reverting to own `core_sync_state`.
…can be reduced to the potentially non-zero 6DoF readings instead of always computing 6 velocity guaranteed-zero columns.
…e performance and maintain numerical stability
…rmance by reducing redundant calculations and enhancing matrix operations.
…a ToDo section for firmware calibration tuning
@relikd

relikd commented Aug 30, 2026

Copy link
Copy Markdown

Sorry for the confusion. I think the step files have only the 1mm variant, while the stl folder contains the 0.8mm:

https://github.com/sb-ocr/cad-mouse-mk2/blob/main/enclosure/stl/

The multiple of 0.4mm is only releveant if you want to go below 2 perimeter walls. As soon as you go above 0.8mm, the printer has more options to fill in the gaps. In my case, the slicer rounded 0.6mm down to 0.4mm because it couldn't print two lines and achieve a thickness of 0.6mm. For your 1mm thickness, the slicer can create a sparse infill so to speak. Now I wonder if you see two lines or three lines (did the printer add a thin line inbetween or did it omit the inner line completely?).

@maximweb

Copy link
Copy Markdown
Author

Sorry for the confusion. I think the step files have only the 1mm variant, while the stl folder contains the 0.8mm:

https://github.com/sb-ocr/cad-mouse-mk2/blob/main/enclosure/stl/

The multiple of 0.4mm is only releveant if you want to go below 2 perimeter walls. As soon as you go above 0.8mm, the printer has more options to fill in the gaps. In my case, the slicer rounded 0.6mm down to 0.4mm because it couldn't print two lines and achieve a thickness of 0.6mm. For your 1mm thickness, the slicer can create a sparse infill so to speak. Now I wonder if you see two lines or three lines (did the printer add a thin line inbetween or did it omit the inner line completely?).

PrusaSlicer uses 1 perimeter at 0.6 mm and 2 perimeters between 0.7 and 1.0 mm. Printing three variants with full height now (0.5, 0.6, and 0.7 mm) and will measure them before testing.


I've merged the glow effect by @pfrazer . Check it out its pretty !

For the time being it only has effect on x, y, rx, ry.

If you have ideas how to represent z shift and rotation feel free to pitch ideas.

@pfrazer

pfrazer commented Aug 30, 2026

Copy link
Copy Markdown

Pushed a tweak just now so that sensitivity can be set asymmetrically. Already increased z-up sensitivity a little.

@maximweb This tweak alone remedies any complaints I had about the force asymmetry. My mouse is pretty heavy because of all the lead I added to the base, but in use it feels really good to me. I'm using the stock 01_spring_0_8_mm_30_deg.stl spring from the original repo 'stl' folder printed in PETG with a 0.4mm nozzle. I plan to stick with that spring because I think anything thinner will be fragile and this one feels fine to me.

I added another PR to consume less power while sleeping. Let me know what you think...

@relikd

relikd commented Aug 30, 2026

Copy link
Copy Markdown

Perfect. I finally had some time to test the new version (as of now). This feels much better, even with my spring design ("Seventeen"). I still think the X-translation is a tad to stiff, but I wouldn't mind using it as-is. Also, my previous bug-report does not seem to apply anymore / seems fixed, thank you :).

The LEDs are a very nice touch and I laughed my ass off when @pfrazer wrote:

It's unnecessary, but I like it. I paid for those LEDs; I want them doing something fun.

@pfrazer

pfrazer commented Aug 30, 2026

Copy link
Copy Markdown

If you have ideas how to represent z shift and rotation feel free to pitch ideas.

@maximweb I couldn't leave this alone... I've prototyped new LED effects:

  • for Z translation, LEDs evenly brighten and skew towards LED_INPUT_GLOW_COLOR when the knob is pulled up, and evenly dim when the knob is pressed down.
  • for Z rotation, LEDs light starting in the front, and progressing in the direction the knob is being twisted.

Overall, I like the added effects and I'll finish tuning and testing them soon. These changes introduce a minor conflict with the code in the open PR, so I'll submit the new effects after we either merge or discard the power-saving changes.

@maximweb

Copy link
Copy Markdown
Author

@maximweb I couldn't leave this alone... I've prototyped new LED effects:

  • for Z translation, LEDs evenly brighten and skew towards LED_INPUT_GLOW_COLOR when the knob is pulled up, and evenly dim when the knob is pressed down.
  • for Z rotation, LEDs light starting in the front, and progressing in the direction the knob is being twisted.

Overall, I like the added effects and I'll finish tuning and testing them soon. These changes introduce a minor conflict with the code in the open PR, so I'll submit the new effects after we either merge or discard the power-saving changes.

@pfrazer Cool, looking forward to the PR.

Just a heads-up: I'll be busy with other things the next two weeks. Maybe I find some spare time to look at your PR code and leave some comments, but definitely won't be able to test on hardware.

My suggestion:

Let's tackle the z, rz glow first so we can complete that feature. Once that is done we can focus on potential power savings. Sorry if this breaks your commit/PR order but my thought is that we should back any power savings attempts on solid numbers. If you have - by any chance - a USB power meter, it would be interesting to get some hard measurements on the power consumption first. For example comparing

  • fully running with LEDs
  • sensor readings / filtering fully running without LEDs (current no-led state)
  • your new PR power savings mode

My reasoning: If - besides switching off the LEDs on idle - your PR significantly contributes to power savings, it would be worth adding. But if the additional savings are barely measurable, I'd lean towards not increasing code complexity for little to no gain.

If you don't have a usb power meter at hand, no worries, I am always looking for reasons to buy more tools and a usb power meter has been on my wishlist for ages 😉

@pfrazer

pfrazer commented Aug 31, 2026

Copy link
Copy Markdown

@maximweb Sure, I can make that work. I have a really good power profiler I use for my day job and I'll just need to find a USB-C cable I'm willing to cut up. I'll get us some solid numbers for when you're available again.

I'll go ahead and submit a PR for the additional LED effects and you (or others) can comment as time permits. None of this is critical, we're just having fun.

I do think your fork is solid enough that I would like to see it start to get some traction among users of this mouse design. To that end, I think the platform.ini file should contain commented definitions for the VID/PID without actually including the 3dconnexion values. Even I spent more time than I should have wondering why my mouse didn't work with your firmware, remembering that those values need set, and then finding where they belonged. I can make a simple PR for that change as well.

@lshachar

lshachar commented Sep 1, 2026

Copy link
Copy Markdown

My brain is already rattling how to make this firmly connected yet tool-free easily detacheable...

image

That's my thought

I've taped mine to the table with double sided tape for now... works great but I'm on PC :)

edit: I have a suction cup on the bottom now and it works very well.

@Manuel-Br-07

Copy link
Copy Markdown

Hello!
I found your Firmware and like it a lot.
It is really responsive and precise.
But I have a problem.
While using Fusion, the plane slowly turnes left. So I have to constantly readjust.
Is that a problem in the firmware or just a fault in the calibration values.

@relikd

relikd commented Sep 4, 2026

Copy link
Copy Markdown

sounds like calibration. Hold both buttons for 5s until the LEDs start to spin (and dont touch the knob!)

@relikd relikd mentioned this pull request Sep 6, 2026
@maximweb

maximweb commented Sep 18, 2026

Copy link
Copy Markdown
Author

By courtesy of @pfrazer we now have beatiful LED effects also for z translation and rotation.

I took the liberty to alter it a little bit.

  • Original turned LEDs entirely off when pressing down hard. Default is now #define LED_INPUT_GLOW_MIN_BRIGHTNESS 10. If you prefer LEDs off, set it to 0.
  • Also it felt somewhat asymmetric that all effects use LED_INPUT_GLOW_COLOR except for z down. So I modified this to also use the glow color.

If we want to get fully crazy we could think about allowing to set a default glow color and individual overrides for certain movements with a color mixer logic. I'd probably prefer a single glow color, but, hey:

I paid for those LEDs; I want them doing something fun.

(still makes me chuckle 😀 )


@pfrazer also suggested a better sleep mode with significant power savings, which I have not merged (yet).

Preliminary measurements indicate:

RP2040

  • Idle with LED (probably brightness 40): 92 mA
  • Deflected knob (at probably max glow brightness 255): 125 to 170 mA
  • Current idle (filter fully running but LEDs off): 44 mA
  • Proposed sleep state (LEDs off): 12 mA

PR2350

  • Idle with LED at brightness 40: 77 mA
  • Deflected knob at max glow brightness 255: 110 to 130 mA
  • Current idle (filter fully running but LEDs off): 27 mA
  • Proposed sleep state (LEDs off): 8 mA

-> Proposed sleep state reduces idle/sleep power consumption by ~ 25 to 30 %
-> but LEDs (at brightness 40) contributes ~50 to 65 % of running energy consumption, glow effect with increased brightness even more

Should we add some magic button combination to disable normal-use LEDs entirely? E.g. long press of a single button toggles LEDs off/on (in normal operation) when we depend on laptop battery in our favorite workcation environment?

Status LED effects should stay active, though.

@pfrazer

pfrazer commented Sep 20, 2026

Copy link
Copy Markdown

RP2040

Idle with LED (probably brightness 40): 92 mA
Deflected knob (at probably max glow brightness 255): 125 to 170 mA
Current idle (filter fully running but LEDs off): 44 mA
Proposed sleep state (LEDs off): 12 mA

Minor correction: the RP2040 sleep current draw in the PR's current state is 9.4 mA.

Should we add some magic button combination to disable normal-use LEDs entirely? E.g. long press of a single button toggles LEDs off/on (in normal operation) when we depend on laptop battery in our favorite workcation environment?

I had some free time, so I went ahead and prototyped this. It's simple enough, and at this point there's no sense in not making the firmware flexible. I made it so long-pressing the right button disables the feedback effects and sets the LEDs to #000000, leaving the ring powered so all the other effects are unchanged. Of course, long-pressing the button sends press/release events via HID and the user might pop a context menu in whatever application they're using. I don't think we'd want to change that behavior because we'd have to delay the delivery of button press events for the long-press duration, which would make button presses laggy. I'm also intentionally not planning to save the state across power cycles so a user doesn't forget they turned the LEDs off and think they're not working. I suppose we could make the default state configurable in config.h. Thoughts?

@relikd

relikd commented Sep 20, 2026

Copy link
Copy Markdown

#42 did implement an LED color configurator via pressing both buttons for 6s (you keep holding both buttons after calibration starts). The firmware would then ignore the calibration request and enter color selection mode. Color selection worked as follows: you turn the knob to select a color in HUE mode (color circle which loops). press right button to confirm, left to cancel. Once you confirmed the color, you'd select the brightness, again, by turning the knob. Same buttons for confirm / abort.

I liked the idea but dont know how applicable it is to this use-case. I could imagine using the LED ring like a mode selector, but without context, I doubt users will remember what each LED mean. I also think, having the long-press as it is now, isnt very useful. I would rather see the buttons utilized for useful features not for aesthetic ones. I think options such as these, should go into a serial communication protocoll or something. But thats just my opinion.

@relikd

relikd commented Sep 20, 2026

Copy link
Copy Markdown

another option (also by the mentioned PR), would be to holda button combination before plugging the device in. This would be useful (and understandable) if this mode would trigger a collection of features, e.g. battery safe mode. As I user, if I know I am low on battery, I'd (hopefully) remember to plug in the mouse accordingly.

@pfrazer

pfrazer commented Sep 21, 2026

Copy link
Copy Markdown

I like the idea of holding buttons at powerup to turn off the unnecessary LEDs. It's straightforward, doesn't send random HID updates, and isn't permanent. I think any additional attempts at power-savings while in full operation mode risks degrading the accuracy or introducing latency, and I don't think it's worth making those compromises. However, we could have an alternate "LEDs off" sleep timeout that could enable power savings after just a few seconds. With the LEDs off, you wouldn't even notice that it was waking up every time you deflect the knob.

I don't think it would be worthwhile to add a complex color selection via knob input. Anyone who will be building one of these units should be able to edit an RGB triplet in the config header, and I can't imagine anyone would frequently change the idle color. When I'm actually using the mouse, I barely pay attention to it.

@relikd

relikd commented Sep 21, 2026

Copy link
Copy Markdown

I didn't intend to suggest adding a color chooser. I just wanted to describe the whole process to have a better feel for how it works (and whether we could apply this interaction to any/other feature). :-)

While I agree that this is probably a one-time config, I still liked the idea that I could change it anytime. At one point, I'd like to flash a firmware onto my mouse and throw away VSCode / platformio bloatware. So I have to commit to a color.

As for the LED animations, in a previous comment you mentioned "leaving the ring powered so all the other effects are unchanged". Maybe this new mode could be night-mode instead of an energy-saving mode. Imagining a night-time situation where you dont want to disturb people nearby with flashy LEDs. But I guess thats a preference which depends on the people using it.

Another idea: is it possible to boot into a USB-stick like mode? E.g., hold both button when you plug-in and you get a config file which you can edit and which will be loaded the next time you plug-in the device. That way it would be super easy to change multiple settings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants