g29py
python driver for logitech g29 wheel/pedals
Install
pip install g29py
g29py depends on the PyPI hidapi package, which provides prebuilt wheels on common platforms.
If a wheel is not available for your platform and pip falls back to a source build on Linux, you may still need system HID dependencies such as:
sudo apt install libusb-1.0-0-dev libudev-dev
Use
import time
from g29py import G29
g29 = G29()
try:
g29.set_range(500)
g29.set_friction(0.5)
g29.listen()
while True:
state = g29.get_state()
events = g29.get_events()
print(state["steering"], state["accelerator"], state["brake"])
if events:
print(events)
time.sleep(0.01)
except KeyboardInterrupt:
pass
finally:
g29.force_off()
g29.stop()
Read
State vs Events
The driver exposes two read models:
get_state()- latest snapshot
- use for steering, pedals, and held buttons
get_events()- buffered transient input events
- use for button edges and dial pulses
Rule of thumb:
- if you want to know what is true now, use state
- if you want to know what happened since the last poll, use events
Pedals/Steering
| Pedal | Value Range | Neutral Position |
|---|---|---|
steering |
Float: -1 to 1 | 0 (Centered) |
accelerator |
Float: -1 to 1 | -1 (Not pressed) |
clutch |
Float: -1 to 1 | -1 (Not pressed) |
brake |
Float: -1 to 1 | -1 (Not pressed) |
Buttons
| Button | Value |
|---|---|
up |
0/1 |
down |
0/1 |
left |
0/1 |
right |
0/1 |
X |
0/1 |
O |
0/1 |
S |
0/1 |
T |
0/1 |
R2 |
0/1 |
R3 |
0/1 |
L2 |
0/1 |
L3 |
0/1 |
right_paddle |
0/1 |
left_paddle |
0/1 |
Share |
0/1 |
Options |
0/1 |
+ |
0/1 |
- |
0/1 |
back |
0/1 |
PS |
0/1 |
State is returned in a flattened shape:
state = {
"steering": 0.0,
"accelerator": -1.0,
"clutch": -1.0,
"brake": -1.0,
"buttons": {
"up": 0,
"down": 0,
"left": 0,
"right": 0,
"X": 0,
"O": 0,
"S": 0,
"T": 0,
"R2": 0,
"R3": 0,
"L2": 0,
"L3": 0,
"right_paddle": 0,
"left_paddle": 0,
"Share": 0,
"Options": 0,
"+": 0,
"-": 0,
"back": 0,
"PS": 0,
},
}
Events
Transient inputs are exposed through get_events().
events = g29.get_events()
Current event shapes:
{"type": "button_down", "control": "X"}
{"type": "button_up", "control": "X"}
{"type": "dial", "delta": 1}
{"type": "dial", "delta": -1}
get_events() clears the buffered event queue on read.
Write
| Method Name | Default Parameters | Parameter Types |
|---|---|---|
reset |
wait_seconds=5.0 |
wait_seconds: float |
force_constant |
val=0.0 |
val: float (-1 to 1) |
set_friction |
val=0.5 |
val: float |
set_range |
val=400 |
val: int (400-900) |
set_autocenter |
ccw_proportion=0.5, cw_proportion=0.5, force=0.5 |
ccw_proportion: float (0-1), cw_proportion: float (0-1), force: float (0-1) |
set_anticenter |
slot=1, cw_position=0.5, ccw_position=0.5, cw_proportion=0.5, ccw_proportion=0.5, cw_reverse=False, ccw_reverse=False, force=0.5 |
slot: int (1-4), cw_position: float (0-1), ccw_position: float (0-1), cw_proportion: float (0-1), ccw_proportion: float (0-1), cw_reverse: bool, ccw_reverse: bool, force: float (0-1) |
autocenter_off |
None | None |
force_off |
slot=0xf3 |
slot: int off-mask / slot command (0xf3 clears active force effects) |
Torque Simulation
g29py.advanced includes a higher-level steering feel controller built from set_anticenter() and set_friction().
import time
from g29py import G29
from g29py.advanced import SteeringTorqueController
g29 = G29()
controller = SteeringTorqueController(g29)
try:
g29.listen()
while True:
state = g29.get_state()
speed_m_s = get_vehicle_speed_m_s()
command = controller.update(
longitudinal_velocity_m_s=speed_m_s,
steering=state["steering"],
)
print(command.target_position, command.force, command.friction)
time.sleep(0.05)
finally:
g29.force_off()
g29.stop()
Behavior:
- parked: target holds the current wheel position with high friction
- rolling: target is center, force ramps with speed, friction drops with speed
- caller owns speed input; feed real vehicle speed in meters per second when available
To make the wheel follow an external steering target, pass target_steering.
The target uses the same normalized -1.0..1.0 steering range as
state["steering"].
command = controller.update(
longitudinal_velocity_m_s=speed_m_s,
steering=state["steering"],
target_steering=model_steering,
)
With target_steering=None, the controller keeps the default speed-based
behavior. With target_steering set, that target replaces the rolling center
target while speed still controls force and friction.
Development
Use Python 3.9+
Setup:
poetry install
Useful commands:
make test
make build
make twine-check
make release-test
Examples:
poetry run python -u examples/dial_events.py
poetry run python scripts/test_effects.py set_friction --val 0.5 --hold 5
Support
Only Logitech G29 Driving Force Racing Wheels & Pedals kit supported on linux in ps3 mode.
On linux, remove sudo requirements by adding udev rule.
echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="c24f", MODE="0664", GROUP="plugdev"' \
| sudo tee /etc/udev/rules.d/99-g29py.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=usb --attr-match=idVendor=046d --attr-match=idProduct=c24f
Sources
- Effect behavior has been hand-checked against a real Logitech G29 on Linux; see
docs/effect-map.md. - Commands were originally informed by nightmode's logitech-g29 node.js driver.
- Effects/layout were cross-checked against WiiBrew's Logitech USB steering wheel reference.
- HID access is provided by the Python
hidapipackage.
Release files for g29py 0.0.17
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| g29py-0.0.17.tar.gz | 8.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| g29py-0.0.17-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.9 kB
Release files / g29py-0.0.17.tar.gz
| Download URL | g29py-0.0.17.tar.gz |
|---|---|
| Size | 8.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b3ac1aebe117c948b67591fad92734d99d6fb97030bc77cd564959aa6a35b1c4
|
|
BLAKE2b-256 checksum How to use checksums |
3ab1ca5a835f4a69d9b9232f5c28c4865c8ae0bf964561f830c1380afffbbc8a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.3.3 CPython/3.12.3 Linux/7.0.0-28-generic
|
Release files / g29py-0.0.17-py3-none-any.whl
| Download URL | g29py-0.0.17-py3-none-any.whl |
|---|---|
| Size | 9.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
85d75b74cb3ca1ebdbed1ea43b6406c0d615b991a8551f4154ba815be152084d
|
|
BLAKE2b-256 checksum How to use checksums |
f6e3cf5fabf9429c212f3565704b2181e7a3e34184cf49bf1c7673525bbaee9c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.3.3 CPython/3.12.3 Linux/7.0.0-28-generic
|