Skip to main content

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

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)

Source distribution for g29py 0.0.17
File Size Uploaded
g29py-0.0.17.tar.gz 8.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for g29py 0.0.17
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

This release

0.0.17 This release

2 release files

0.0.16

2 release files

0.0.15

2 release files

0.0.11

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page