Skip to content

Conversation

@jillyfox
Copy link

@jillyfox jillyfox commented Nov 24, 2025

Important disclaimer: I'm tinkering with this to learn rust, and also have only tested this via my wasm frankenbuild. Review with skepticism.

First commit switches the manual command to SetPoint, which fixes both FSetSite moving at low speed (SetPoint appears to move at an appropriate speed for the distance, up to maximum), as well as FSetSite having some bad momentum calculation going on where issuing repeated large movements causes the device to somehow buffer movement that then plays (at high speed!) upon the next command. Fun.

Second commit rewrites the control loop to behave much better. At least in my high-latency-wasm-via-js setup, the delay on BT commands meant that sleeping 100ms per step actually stretched steps out much longer, and any variation in BT latency lead to uneven pacing.

Instead, do the math based on the current time of where in the motion we should be at each wakeup, and then sleep for 100ms-command_duration.

Combined, this means if a BT command takes 200ms, we'd just immediately start the next one, and to the right spot for 200ms of time. Fast movements correctly move at near full speed, and longer movements hit their target duration much more closely. In my simple test app, this makes a interactive slider to control the device at least as responsive as the phone app's manual UI, if not better.

Other notes:

  • I have no idea what I'm doing in rust. RwLock seemed like the right pattern for passing Instant around, which meant the other values needn't be atomic, I think. There's some crate with AtomicInstant, but, at 100ms, thread contention isn't really a concern. The tuple should probably be a struct? I avoided touching things that weren't relevant, but the resulting patterns might be dumb.
  • There's still some aliasing shenanigans for e.g. 150ms movements (will be 200ms total). Could try to do two moves with 75ms delay or similar in that case.
  • Could bake knowledge of device's actual speed in. 0% to 100% takes half a second-ish, so if our distance+duration is faster than that, breaking it up into five commands isn't productive (which could lead to the device unnecessarily pausing if BT packets drop/etc).

jillyfox added 2 commits November 23, 2025 20:27
Moves at appropriate speed, doesn't go off the rails when updated
multiple times during a movement start making random movements
indefinitely...
At least when using webbluetooth, the latency here + a static 100ms
sleep meant it frequently extended movements far past their intended
duration.

Instead, track the start/end time of a movement and calculate our
target on each wake.  Subtract the time the bluetooth command took
from our sleep interval to ensure we're attempting to start commands
at 100ms intervals (or as fast as the bt provider can handle it)
@CLAassistant
Copy link

CLAassistant commented Nov 24, 2025

CLA assistant check
All committers have signed the CLA.

@blackspherefollower
Copy link
Collaborator

@jillyfox Could you rebase onto the dev branch?

I think the use of Instant and RwLock is sane, but that needs @qdot eyes.

The only thing I think might be missing is a way to cancel the movement: if the handle_output_oscillate_cmd function is called, I'd be a good idea to prevent further SetPoint messages going out until handle_position_with_duration_cmd is called again.

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.

3 participants