Joyride: joystick-controlled wheelchair power attachment

Hi everyone,

I’m working on a project called Joyride, and I’d love some help, mainly around the encoder setup for a new configuration, but also general feedback on the overall design.

Project overview

Joyride is an adaptation of a wheelchair power attachment, that is normally steered using a bicycle-style handlebar. The goal is to replace that steering input with a joystick-controlled system.

This is intended for my partner, who has a neuromuscular condition that makes it difficult to operate a traditional steering handlebar. Instead, we’re using a motorized steering system driven by joystick input, with ODrive handling the motor control.

Current setup: belt drive

Our first prototype uses a belt-driven system. We mounted a laser-cut plate onto the head tube, with an ODrive D6374 motor positioned parallel to the steering shaft. The motor drives the steering through a timing belt. An ODrive S1 is mounted on the back of the motor, and we’re using its onboard encoder for both commutation and load feedback. Control is handled by an Adafruit Feather M4 CAN Express, which reads joystick input and communicates over CAN.


In testing, this setup gave mixed results. Without load, we were able to tune the system to behave reasonably well and follow joystick inputs. However, under real conditions the limitations became clear. The belt introduces noticeable compliance, which causes the steering shaft to miss its target positions. When I sit in the wheelchair and apply real load, the motor approaches its current limits without actually reaching the commanded position. So while the concept works, the mechanical transmission is clearly a weak point.

New setup: direct drive

We’re now moving toward a direct-drive approach using a geared motor (Steadywin), mounted directly on top of the steering shaft.
This seems to be a much better setup: smaller form factor, higher torque, no transmission.

This change does require some redesign. Mechanically, we’ll need a custom shaft and adapter to connect the motor to the steering column, and a custom (likely 3D-printed) mount to attach the motor to the head tube. On the sensing side, we can no longer rely on a single encoder for everything, so we’re planning to separate commutation and load sensing. The current idea is to use a magnet on the motor shaft for commutation, and a ring magnet on the steering shaft for an off-axis load encoder.

Encoder questions (main ask)

This is where I’d really appreciate some guidance.

It seems that the onboard encoder of the ODrive S1 can not be used in this configuration. The required magnet distance is around 1 mm, but with the heatsink and mounting constraints we end up closer to 4 mm, which I believe is too far for reliable operation.

So as far as I understand, this means I’ll need external encoders for both commutation and load. From reading the documentation and forum posts, I get the impression that I can’t mix SPI and RS485 encoders, and that using multiple SPI encoders is also not supported. If that’s correct, it seems like I’m effectively limited to using two RS485 (OA1) encoders.

What I’m unsure about is whether that’s the best approach, and whether an OA1 encoder would work reliably in an off-axis setup with a ring magnet on the steering shaft. I’m also wondering if there’s a simpler or more standard architecture I might be overlooking here.

Other aspects (for context)

For input, we’re currently using an industrial APEM joystick in a custom 3D-printed housing. In the future, we’d like to switch to the Xbox Adaptive Joystick, since it should be much easier for my partner to use.

Braking is currently handled by two servos pulling on brake cables. This works, but it’s not ideal. We don’t have proper force control, and it doesn’t feel particularly robust. We’re considering either switching to smart servos (like Dynamixel) or adding load sensing with a PID controller.

What I’m looking for

I’d really appreciate feedback on the direct-drive approach, and especially on the encoder setup given the constraints of the ODrive S1. If anything in the mechanical design or control strategy seems off, I’d much rather catch it early.

Thanks in advance!

Wow, this is a super cool project!

My first reaction is that you may not need direct drive – if belt compliance/flex is the issue, you could consider (1) increasing the diameter of the driven pulley (for an effective gear reduction), and (2) add a second encoder on the belt output / shaft itself – something really high res like the AMT21 would be great if you can mount it well, or you could use an OA1. Then you get the benefit of being able to directly control the output angle, sans belt compliance.

You could also drop down to a D5045 motor (+ NEMA23 faceplate), which has an 8mm output shaft – same as NEMA23 motors, which means you could use an off-the-shelf NEMA23 gearbox – here’s a 20:1. It’ll have a nonzero amount of backlash, so having a secondary encoder would be helpful – again, the OA1 or something would work.

However, the Steadywin is also a perfectly fine option! A few notes:

  • Yes, 4mm magnet distance may be a bit much. The OA1 is a good choice here
  • You can mix two OA1s, but it requires a bit of custom configuration/a small firmware tweak. Instead, you can use both an OA1 and a stock AMT212-B-V (not the AMT212-B-V-OD purchased on our shop, you’d have to get it from something like Digikey). This is because the AMT212 has a firmware flaw that causes it to rapidly lose resolution over a few hundred RPM; the one we sell comes with custom firmware that fixes this issue, but doesn’t allow it to coexist with other RS485 devices. Since this is just for a gearbox output, the stock one will be fine in terms of the speed/resolution issue, and it can coexist with the OA1.
  • That being said, I think there’s a much simpler solution here. The Steadywin’s backlash is about 0.25°-- this is likely fine for control. So you just need some way of sensing the output shaft position in order to initialize the system. You could use a simple photointerruptor sensor or a mechanical endstop at the end of the wheel’s travel range, connected to the S1’s GPIO, then use the homing procedure at each power-on to find the absolute position.
  • Alternatively, if you’re worried about the 0.25° of backlash (I wouldn’t be), you could just use an incremental encoder on the output, either something fancy/high res or cheap and easy to mount. It’s also perfectly fine to run a small belt from the driven shaft to the encoder, especially just for a load encoder.

Other notes:

The current idea is to use a magnet on the motor shaft for commutation

It looks like the Steadywin already comes with one, you’d just need to 3D print a mount for the OA1

Braking is currently handled by two servos pulling on brake cables. This works, but it’s not ideal. We don’t have proper force control, and it doesn’t feel particularly robust. We’re considering either switching to smart servos (like Dynamixel) or adding load sensing with a PID controller.

Sounds like something that could be a good use for an ODrive Micro! I have some reference/notes for mounting those on the back of a GIM4310. Do you know how much force is actually needed for pulling on the brake cables? I have some ideas there.

I think overall if I was doing this project, I’d just do something like a D5045 + NEMA faceplate + S1 + 20:1 gearbox, with a similar transmission setup to what you currently have, and an OA1 on the steering axle – it’ll have plenty of resolution, and way more torque than the Steadywin, while being a bit more compact than the current setup (just a bit longer). But there’s also no issues with the Steadywin+beambreak/endstop, my main concern would just come down to the custom shaft adapter needed.

I’d love to help out here in any way – feel free to shoot me an email at solomon.greenberg@odriverobotics.com and I’d be happy to see if I can dig up some used parts to make this build feasible!