FortiusANT icon indicating copy to clipboard operation
FortiusANT copied to clipboard

Steering

Open marcoveeneman opened this issue 3 years ago • 65 comments

Steering interface on BLE

This pull request adds initial support for steering in Zwift as described in #152.

Start FortiusANT with the --steering option on the command line. FortiusANT will advertise a steering characteristic which Zwift can connect to. When calibrating the rolling resistance, the steering interface is also calibrated, you get hints from the GUI. After you started pedalling, the GUI tells you to steer right, then middle.

Please review my changes and comment where needed.

marcoveeneman avatar Jan 15 '21 21:01 marcoveeneman

Hi - nice to see that it is now possible to send steering data to zwift. Am I correct that extracting steering information from e.g. the blacktrack still needs to be implemented? Or is that already in the code somewhere?

trygvelu avatar Jan 19 '21 17:01 trygvelu

Hi @trygvelu, yes you are correct. Currently the steering data is only fetched from the Tacx head unit itself. I see the blacktrack communicates over ANT+, so i think that can be added as a next step. I don't own a blacktrack personally, but i'm sure we can get this working as a community.

marcoveeneman avatar Jan 19 '21 18:01 marcoveeneman

I have a Blacktrack (came with my Genius). The ANT protocol for that is really simple, so I don't think it will take me long to implement. We will need to re-think calibration a bit though. The resistance calibration is only done for the Fortius while the Blacktrack can be used with any trainer. Actually the wired steering frame can be used with the Flow, too, and that doesn't have calibration (yet) either.

switchabl avatar Jan 19 '21 18:01 switchabl

I have a blacktrack myself (also with Genius), but I'm not that familiar with the ANT profiles/protocol. I can assist with testing, if needed. Ideally I would think that steering could be implemented independent of the type of trainer hardware being used.

trygvelu avatar Jan 19 '21 23:01 trygvelu

@switchabl

I don't think it will take me long to implement

I suppose implementation would be in line how head-units buttons from the Vortex are integrated. We will have to mind the maximum number of ANT-channels, unfortunately they are not dynamically assigned (now)

WouterJD avatar Jan 20 '21 14:01 WouterJD

@WouterJD Yes, pretty much the same. There is a single page with the steering angle and we need to send a keep-alive every few seconds so it doesn't turn off.

As far as I know you can have channel numbers up to 255 as long as you don't enable more than 8 at the same time. I have never used that many before though.

switchabl avatar Jan 20 '21 14:01 switchabl

Simply test to modify the channel numbers and see what happens

WouterJD avatar Jan 20 '21 14:01 WouterJD

@marcoveeneman Great work there! Thanks a lot for implementing the steering for Zwift. I did test the steering implementation today with my steering frame (not the Blacktrack obviously) on the Raspberry and it seems to work really well. I will keep testing an send you feedback in case I run into some bugs. One thing I am thinking about is how to implement this in the headless Raspberry setups that some - including me - are using. I need to figure out how to read the stdout and use the information there to trigger a visual signal for the steering calibration. Would it be possible to store the information and calibrate the steering only if required? Looking at the source code it seems like this would require 2 variables to be stored somewhere. However not sure if the steering frame does send similar values every time.

wtal710174 avatar Jan 24 '21 21:01 wtal710174

@marcoveeneman sorry for the intermediate upgrade to 5.1 causing conflicts. Could you please look into that?

WouterJD avatar Jan 24 '21 21:01 WouterJD

Is it a correct understanding that this PR will enable Zwift steering for my T1901/T1932/T1905 (steering frame) setup, i.e. Flow Multiplayer T2220 bundle? And it will communicate via the already established USB/FortiusANT interface?

kjoglum avatar Mar 24 '21 08:03 kjoglum

Yes that is correct; it can be used with Zwift only - other CTP's do not support steering. A final version has to be made and can then be integrated

WouterJD avatar Mar 25 '21 09:03 WouterJD

As a follow up: Having a RPi 3b+ not being used, with some java/git experience (although totally unfamiliar with python), I have done an attempt to achieve my goal for testing the steering functionality for my T1901/T1932/T1905 setup against Zwift.

Making a fork of the latest @WouterJD branch, implementing and modifying the @marcoveeneman code for steering (both the "as is" code for CalibratedSupported trainers as well as trying to implement code for my trainer not CalibratedSupported). Comparing with @WouterJD branch, there are no merge conflicts.

So, following the raspberry installation from manual, using my customised branch, I apparently have something going on, but not quite:

  • I get both the trainer and steering functionality connected to Zwift, although shown as "No signal" (see picture below), and no cadence connection. Then running BLE setup RPi 3b+ FortiusANT / macOS Zwift (without BLE dongle), having the RPi < 50 cm from the mac. When starting training, no response from the avatar. Also tried via Zwift Companion app, but no response.
image
  • I also struggle with the calibration part within FortiusANT, which I do not seem to manage to trigger in a good way. Try to allow the start-up phase finish, and then initiating Steering Calibration, followed by actual calibration when starting pedaling, i.e Resistance > 0 / Speed > 0. Although Resistance & Speed > 0, the calibration remains at the calibration initialisation step.

For anyone interested, willing to comment/help, please have a look at my modified FortiusANT repository: https://github.com/kjoglum/FortiusANT

EDIT Continued fiddling around, turning off potential bluetooth interference, rebooting RPi several times, and finally got connected with signal in Zwift (both trainer, power, cadence and steering) when having Zwift active during RPi reboot (although, back to no signal after restarting Zwift, so something is quite unstable).

Calibrated/setup steering successfully in Zwift. However, even if steering is shown as ON in Zwift, there is no steering response while riding.

EDIT2 Allowing RPi/FortiusANT to "settle" some time before starting Zwift seems to fix the signal issue. Although, still have active steering with no actual response.

EDIT3 So, managed to adjust python code to enable steering calibration (both triggering and performing the actual calibration) in FortiusANT for my non-CalibratedSupported trainer, followed by the regular FortiusANT initialisation (latest code on my github branch linked above). And, I manage to get everything connected in Zwift (both trainer, power, cadence and steering). However, when riding in Zwift, even though steering is shown as ON, I do not get any actual steering response.

See from log file that initial calibration works as intended, providing actual values for calibrating right/middle (e.g. 788/949). Then the Tacx2Dongle function calls calibration once again, and as the criterias for steering calibration are not met the second time, default values (i.e. 0/0) are set and steering angle remains at 0.

Solved by making the calibration variables global, enabling storing calibration values - now Zwifting with steering (although challenging to maintain smooth steering while riding...).

kjoglum avatar Mar 26 '21 22:03 kjoglum

Yet another update on my behalf, having played around with the steering functionality of my T1901/T1932/T1905 setup. Now believe I have something working satisfactory, based on @marcoveeneman initial steering code, rebasing to latest @WouterJD branch, implementing steering calibration/functionality for non-calibration trainers. Please have a look and see if valid to implement: https://github.com/kjoglum/FortiusANT

As a note: The potmeter readings (at least for T1905) proves to be non-linear, so the updated code is introducing an additional calibration value for steering left (in addition to steering right and middle) to set steering angle in the range -45/45 degrees based on potmeter reading.

kjoglum avatar Apr 04 '21 21:04 kjoglum

@switchabl What is the status on the Blacktrack VR implementation?

Would be awesome!

Maybe I can help or test?

How did you reverse engineer the Blacktrack VR protocol?

frankhommers avatar Aug 30 '21 18:08 frankhommers

@marcoveeneman it seems that @switchabl has disappeared from github since March. Can we/I do something to get the Blacktrack VR steering working...?

frankhommers avatar Sep 12 '21 19:09 frankhommers

@frankhommers Sorry, life got in the way and this hasn't been much of a priority for me since I've been riding outdoors anyway. The protocol for the Blacktrack is here: https://gist.github.com/switchabl/75b2619e2e3381f49425479d59523ead (all the way at the bottom).

But I'm afraid Zwift has changed the steering protocol in order to lock out third-party implementations (https://www.dcrainmaker.com/2021/06/zwift-hardware-tidbits-breaking-steering-apple-tv-2021-updates-new-non-supported-trainers-list.html). So @marcoveeneman 's branch is probably broken right now. I think I've more or less managed to crack their new authentication mechanism. So I am cautiously optimistic that it can be done but more work needed.

There's also the chance that they will just break it again in a few months time. I'm not sure how keen I am on playing cat-and-mouse with them.

switchabl avatar Oct 30 '21 19:10 switchabl

@switchabl ah yes, life is more important than a few lines of code ;-)

I have read DCRainmakers' blog post. And I understand your opinion about cat and mouse.

So I guess I am out of luck here... Maybe I'll just buy an Elite Sterzo Smart in order to be able to steer in a supported way.

frankhommers avatar Oct 31 '21 13:10 frankhommers

@frankhommers Maybe don't rush out to buy a Sterzo quite yet if you are not in a hurry. The good news is, it doesn't look like they have done a terribly good job locking us out. I think if all goes well I should have something working next weekend.

switchabl avatar Oct 31 '21 15:10 switchabl

@switchabl Ah that would be awesome!! Can't wait to try!

frankhommers avatar Oct 31 '21 15:10 frankhommers

@frankhommers @marcoveeneman Quick update: I have indeed managed to figure out and implement their new authentication mechanism. screenshot

I have also brought the steering up-to-date with master: https://github.com/switchabl/FortiusANT/tree/steering

Blacktrack support still missing though. We also need to figure out how to do the calibration. This is currently botched onto the Fortius calibration which is not only messy but also means it doesn't even run if you're using another trainer. But all that is solvable. =)

switchabl avatar Nov 07 '21 22:11 switchabl

Awesome! Looks like 'only' some small changes to the protocol were needed. Just wondering, how did you figure this out?

About the calibration part, i totally agree, it's not very nicely done currently. Back when i implemented the first version of steering i was thinking about adding a new steering member to te trainer class, which would implement a steering interface. This never happened and i went the quick&dirty way unfortunately.

It would be nice to setup some structure like this:

class Steering
  ...
  def getAngle(raw_data):
    pass
  ...

class BlacktrackSteering(Steering):
  ...
  def getAngle(raw_data):
    <do blacktrack specific calculations here>
  ...

class FortiusSteering(Steering):
  ...
  def getAngle(raw_data):
    <do forties specific calculations here>
  ...

It's a while ago that i touched the FortiusANT codebase so i'm not sure where this would fit currently.

marcoveeneman avatar Nov 08 '21 07:11 marcoveeneman

Yes we should make steering calibration "pluggable" in the startup sequence in some way. Maybe @WouterJD has some ideas about this?

frankhommers avatar Nov 08 '21 22:11 frankhommers

Hi @frankhommers I'm fully confident that @switchabl will come with a good solution. Not zwifting, but still outside😉

WouterJD avatar Nov 09 '21 07:11 WouterJD

Also being interested in the steering feature for my T1901/T1932/T1905 setup.

Have previously done some code modifications as well, https://github.com/kjoglum/FortiusANT, based on the following experience:

  • Added code for retrieving/using both right, middle and left steering values from potmeter
  • Added/revised code to be able to calibrate steering for trainer not being resistance-calibration supported

kjoglum avatar Nov 09 '21 08:11 kjoglum

@marcoveeneman I don't really want to give any hints to the Zwift/Elite people, so I'm not sure I should give too many details on the "how". The basic algorithm is still very much the same. The changes they made very narrowly address the weaknesses found in the original analysis:

  1. The original version was only 16 bits, so it was possible to record and replay all possible combinations. The new one is 32 bits so this less feasible. It is however fundamentally weak and that doesn't get better with more bits.
  2. The original version only authenticated the training app, not the steering device. So simulating a steering device didn't even need the authentication table. The new version consists of two challenge/response steps, so superficially it looks like it authenticates both. It turns out this is not really the case because the second one is not random. Effectively only the steering device is authenticated now. If you just want to use an original Sterzo with your own software, you can now just replay a recorded exchange. Not sure if this is intentional or an oversight.

Also, yes, I will definitely go for a class hierarchy like that. I'm still figuring out the details though. Better get this (more or less) right the first time. Refactoring FortiusANT is always a bit scary.

@kjoglum Interesting. I'm curious what motivated the 3-point (piece-wise linear?) calibration? I was expecting a 2-point linear approach to work quite well because of the way the hardware works (raw value should be ~(R_ref + R_pot)*C). BUT, I can't really test that properly for myself because I don't actually have a T1905 (I have a Blacktrack), I use this instead for testing.. So I may well be wrong. t1905

Also, it turns out Zwift already has steering calibration built-in these days. That may or may not be good enough for our purposes. I will hopefully make some more progress on this (and Blacktrack) over the weekend.

switchabl avatar Nov 10 '21 23:11 switchabl

@switchabl: Due to irregular steering behaviour experienced as part of Zwift rides, with the 2-point approach, I ended up dismantling the steering frame to outrule any irregularities to the potmeter mount itself, followed by a 3-point approach to check actual output values for the potmeter, leading to including code for 3-point calibration. As shown below, the potmeter readings (at least for my T1905) are not 2-point linear, more like logarithmic.

The potmeter readings are varying a bit from time to time, but at an average I have step = [(calib_middle - calib_right) / 45] = 5.0 for steering right and step = [(calib_left - calib_middle) / 45] = 7.2 for steering left. Obviously, using 2-point calibration in my T1905 case would result in wrong angle values for left steering, in fact resulting in quite significant oversteering (as experienced during Zwift rides).

The potmeter readings presented below, and used for calculation above, are values retrieved just after performing calibration using the Tacx Trainer software.

Skjermbilde 2021-11-11 kl  16 58 49

kjoglum avatar Nov 11 '21 16:11 kjoglum

@kjoglum Thank you, that is definitely helpful. And somewhat unfortunate. So I guess relying on Zwift calibration is probably a non-starter. It looks like they may be using an audio pot then. I did not see that coming. If that is the case, the 3-point piecewise approach is probably a good fit. I'd still want to make sure that it's not, like, the head unit doing something weird.

@marcoveeneman Did you observe this kind of behaviour too?

I will maybe try to get my hands on an actual T1905. And focus on the Blacktrack in the meantime. I think it uses an optical encoder instead, so should be less complicated.

switchabl avatar Nov 14 '21 15:11 switchabl

IIRC I used a 2 point calibration in this PR, same as the old Tacx Fortius software did: measure center, and measure most right. Based on those values calculate the raw value to angle factor. Middle is 0, most right is 45 degrees, left should be -45.

However, i remember that the values returned by the steering frame seemed to be affected by temperature. So after a while the values start drifting causing the calculation to be wrong. If you're training in a small room the temperature will definitely change, this might be a problem. Would be nice if someone could verify this. When i have some time i'll also check it.

marcoveeneman avatar Nov 14 '21 15:11 marcoveeneman

Why would tacx conceptually build a steering unit that is different right/left, so I guess you try to compensate an individual issue. Also - like previous improvements we made on the power curve - I would not try to make the software better than the (stability) of the hardware as Marco illustrates. Even though mathematically challenging

WouterJD avatar Nov 14 '21 16:11 WouterJD

@WouterJD Yes, don't worry, I'm not quite ready to accept this either without further investigation. I still hope that this is in fact something that is weird/broken with the steering frame @kjoglum has (some alignment issue?).

From an engineering perspective using a potentiometer with a (non-linear) audio taper makes no sense of course. But it is possible that you could get those a lot cheaper somehow or the wrong ones got ordered or the linear one has a long lead time (very familiar problem right now). So you decide to use it anyway, at least for one batch, and fix it in software. It happens. More often than you might think.

If the old Fortius software used 2-point calibration that suggests this is not normal. But I think TTS4 actually does left-center-right calibration as well, so who knows.

In any case this is much simpler than the power curve issue. There are essentially just three possibilities:

  1. we can let Zwift do the calibration (would be nice)
  2. we need to do a 2-point calibration (right-center)
  3. we need to do a 3-point calibration (left-right-center)

Neither is particularly interesting from a mathematical standpoint.

switchabl avatar Nov 14 '21 17:11 switchabl