AFFBWheel
Arduino based racing wheel controller with force feedback
Install / Use
/learn @vsulako/AFFBWheelREADME
AFFBWheel (Arduino Force FeedBack Wheel)
This is project of Arduino based wheel controller with force feedback. To configure the controller parameters, you need to use the graphical interface AFFBWheelGUI
- 8 axes: steering(X), accelerator(Y), brake(Z), clutch(Rx), and 4 additional(Ry, Rz, Slider, Dial - e.g. for thumbstick, handbrake, etc).
- 32 buttons.
- FFB effects: constant/ramp/square/sine/triangle/sawtooth/spring/damper/inertia/friction
- Wheel range can be changed on the fly: 1080/900/360/270/180 degree or any other value.
Unfortunately, there isn't much information about conditional FFB effects, my implementation can be incorrect.
However, modern games typically use only constant force to emulate other effects.
Hardware:
- Arduino Atmega32U4 board (Leonardo, ProMicro, Micro, etc)
- incremental encoder or TLE5010/AS5600 sensor for steering axis.
- potentiometers for analog axes
- 4x shift registers 74HC165 (alternately - I2C expanders MCP23017)
- BTS7960 driver
- DC motor
- 12-24v DC power source for motor
- 5v DC power source for Arduino 5v (optional - can be powered from USB)
- optional: ADC MCP3204, ADS1015, or analog multiplexer 74HC4051/74HC4052/74HC4067 + shift register 74HC164
Project uses USB HID communication code from VNWheel project (great thanks to hoantv's work).
Instructions for the firmware
- Download the project from github as zip: <br>
<br>
And unzip the archive to any convenient folder. - Download Arduino IDE. Version 1.8.19 is recommended, later versions may have errors.
- Download additional libraries:
- Install the downloaded libraries:
- 4.1. Download the library as zip.
- 4.2. Open Arduino IDE, then click Sketch > Include Library > Add .ZIP Library.... and select zip with downloaded library. Instruction in English: <br>

- Open the folder where you unpacked the project archive, go to the AFFBWheel folder and open the AFFBWheel.ino file in Arduino IDE.
- Make the necessary changes to the config.h file for customization.
- Connect the Arduino board to your PC.
- Select your board type Arduino Tools > Board (Leonardo, ProMicro, Micro, etc.): <br>

- Select the port on which Arduino is detected Tools > Port: <br>

- Click the upload button: <br>

- Wait for the firmware process to finish. All is ready!
Wiring diagram:

The connection diagram is shown on the example of Arduino Pro Micro, for the rest of the boards, the pinout is exactly the same with the same numbers. There are slight differences for Arduino Leonardo in the location of pins on the board.
There are also several options motor driver connection.
There are two separate lines of shift registers, 16 buttons each.
Thus, 16 buttons can be placed on wheel, and 16 more on wheelbase or gearbox.
Decoupling

For lowering noise it is recommended to add decoupling capacitors (ceramic 100nf...1uf between VCC and GND) to all bare IC's (TLE5010, 74HC165, 74HC4052, MCP2304...) close as possible to IC. Modules already have these.
Encoder PPR
Set encoder PPR in config.h, in line #define ENCODER_PPR 400.
Blocking unneeded analog axes.
If analog axis pin is not connected to potentiometer, axis will produce noise. To avoid that, either pull axis pin to GND with 1-10kOhm resistor, or disable axis output with command axisdisable. So, axis will always report same value and will not mess up when detecting axes in games.
Also, 4 additional axes (AUX1-AUX4) can be disabled in config.h. Just comment out line #define PIN_AUXN ...
Disabled axis will be excluded from polling (saving ~45us of computing time) and will always report 0%.
If a game does not support DIY wheels
You can try to use controller emulator GIMX. You will need an Atmega32U4 board (Leonardo/promicro/teensy2/etc) and CP1202 USB-UART adapter.
Alternate hardware configurations.
Testing software:
Configuration.
Configuration options are in config.h, mostly for different hardware configurations (see below).
Settings and commands.
Changeable settings can be changed on the fly using GUI or commands on serial port.
For most commands, if no value is given, command prints current setting.
-
center
Set current wheel position as center. -
centerbtn
centerbtn <button>
Print/set centering button.<button>- number of button, 1-32. 0 value means no centering button.
One button can be selected for performing "center" command. This button will be excluded from input. -
range
range <degrees>
Print/set wheel range in degrees (e.g. 900). -
axisinfo <axis>
Enable data output (axis current position and other values are printed to serial port) for one of axes.
Axes are:
0 - wheel
1 - accelerator
2 - brake
3 - clutch
4 - aux1
5 - aux2
6 - aux3
7 - aux4
no value - disable output
This output slows down, do not forget to disable it when you do not need it. -
limit <axis>
limit <axis> <min> <max>
Print/set minimum and maximum raw values for analog axis.
Wheel limits are changed withrangecommand. -
axiscenter <axis>
axiscenter <axis> <pos>
Print/set raw center position for analog axis.
Use it when axis has distinct center position (e.g. thumbstick. Pedals do not need center) and does not align well.
If center position is set beyond limits (less than min or greater than max), it becomes disabled.
Disabled center means that center will be set automatically in middle between min and max (autocenter=1). -
axisdz <axis>
axisdz <axis> <dz>
Print/set center deadzone for analog axis.
If axis has center set withaxiscentercommand, a deadzone for center position can be applied.
Units are raw. (e.g., if axis has center=500, and dz=10, axis will return 0 when raw position is between 490 and 510).
If you need deadzones at edges, just set axis limits less than actual limits.
Deadzone does not apply if axis have no center set (autocenter=1). -
axisdisable <axis>
Enable/disable axis output.
Axis with disabled output will report permanent minimum value (0%). -
axistrim <axis>
axistrim <axis> <trimlevel>
Print/set bit trimming value for analog axis.
This reduces resolution of raw axis reading for lowering noise. E.g. if<trimlevel>is 3, axis value will change with steps of 8 (2 in power of 3). If axis has noise, you can try to raise this value (however, it's better to find cause of noise, instead of hiding it with this) -
autolimit <axis>
Enables/disables autosetting min/max values for analog axis [1..5].
Each time when axis exceeds current min/max, it's position becomes new limit.
(i.e.: enable autolimit, push pedal from limit to limit, disable autolimit - limits are set)
This setting disables center position and deadzone. -
debounce <count>
Print/set debounce value for buttons.
If it is greater than zero, change in buttons state will be registered only if buttons do not change state for<count>cycles (1 cycle is about 1ms)
If you encounter button bouncing, try increasing this value. -
gain <effectNum>
gain <effectNum> <value>
Print/set gain for effect.
Possible values of<effectNum>are:
0 - total (applies to all effects except endstop),
1 - constant
2 - ramp
3 - square
4 - sine
5 - triangle
6 - sawtoothdown
7 - sawtoothup
8 - spring
9 - damper
10 - inertia
11 - friction
12 - endstop (force that does not allow to turn wheel beyond range)
Default value is 1024 which equals 100%. 2048 = 200%, 512 = 50% and so on. -
forcelimit <minforce> <maxforce> <cutforce>
Print/set minimum/maximum PWM value for FFB (in internal units, [0..16383]) and force cutting value.
If force is not zero, it's absolute value will be scaled from [1..16383] range to [minforce...maxforce].
There is a tiny slope at low values, to avoid kicking when going from negative minforce to positive and vice versa.
If resulting absolute force is greater than<cutforce>value, it will be constrained to<cutforce>.
Default values areminforce=0,maxforce=16383andcutforce=16383(which results in no changes). -
maxvd
maxvd <value>
Print/set maximum velocity value for damper effect.
Effect calculating requires setting of maximum velocity which will correspond to maximum force.
Increasing this parameter decre
