Logitech G29 Pedal, Shifter 를 PC 와 직접 연결하기

글을 쓰게 된 계기

G29 를 사용하던 도중 Thrustmaster T300RS 제품을 할인한다는 소식을 들었다.

30만원도 안되는 가격에 새 제품을 구매하게 되었다.

그러나 T300RS 의 기본 페달은 브레이크가 너무 물렁하고 클러치가 없다.

그래서 기존에 사용하던 Logitech Shifter 와 G29 Pedal 을 같이 사용 할 순 없을까? 하는 마음에 구글링을 해 보았더니 국내 자료는 잘 찾을 수가 없었고, 해외 자료는 꽤 존재하였다.

블로그를 한동안 안했지만, 이 기회를 발판 삼아 다시 시작하며, 한국어로의 번역 겸 경험기로 글을 남기기로 결정하여 이렇게 글을 쓰게 되었다.

준비물

  • 아두이노에 대한 기초적인 사용 방법, 약간의 전기 지식
  • Arduino Leonardo 등 ATmega32u4 사용하는 보드 (사용하는 Joystic 모듈에서 지원하지 않음)
  • 빵판 (Bread Board)
  • DB9 암 / 수 모듈 (구하기 힘들다면 아래 제품으로 대체 가능)
    • 핀 헤더, 납땜 도구 (쉬프터 사용시)
    • 점퍼 케이블 (G29 페달 사용시)

참고 자료

AMSTUDIO

검색을 하면 유튜브 영상이 많이 나오는데, 대부분 이 사이트가 출처이다.

Logitech Shifter

가장 먼저 연결한것은 로지텍 쉬프터이다.

이미 T300RS 를 구매할 때 기본적으로 페달이 있기 때문에 쉬프터와 연결이 되는지를 테스트 하고 싶었다.

이 영상을 보고 인터넷에서 DB9 - USB 연결 잭을 구매하여 PC 와 연결해 보았지만, 이것으로는 내가 원하는 쉬프터의 작동을 할 수가 없었다… 실패

그래서 기왕 산 DB9 를 분해하려고 했지만 제대로 분해가 되지 않아서 영상과 같이 납땜을 할 수가 없었다.

쉬프터의 DB9 소켓에는 점퍼케이블이 너무 헐거워서 제대로 꼽히지가 않았다. 조금 더 두꺼운게 필요했는데, 마침 집에 남아있던 핀헤더를 연결해보니 아주 완벽하게 딱 맞진 않지만 적당히 잘 연결된 느낌이 들어서 핀헤더에 납땜을 하였다.

conn-shifter.jpg

유튜브 영상에 나온 회로도를 그대로 아두이노와 연결한다.

diagram.png

사실 위 회로도에서 중요한것은 DB9 쪽이다. 아두이노쪽은 다른곳에 연결하더라도, 추후 코드에서 포트 번호 수정으로 쉽게 해결이 가능하기 때문이다.

회로도대로 연결을 성공하였다면 코드를 받아야 한다.

SHIFTERS

직접다운로드 링크를 걸 수도 있지만, 유튜브 영상에서도 이쪽으로 링크를 걸고 있기 때문에 나도 이쪽 링크를 걸었다.

가장 하단의 DIY LOGITECH USB SHIFTER ADAPTER 부분의 Download 를 눌러 받는다.

해당 코드를 열어보면 Joystic.h 라이브러리를 필요로 하고 있기 때문에 해당 라이브러리를 Arduino IDE 에 추가해야 한다. (방법은 영상에도 나온다)

MHeironimus/ArduinoJoystickLibrary

이후 컴파일 체크 후 업로드를 하여 제어판 - 장치 및 프린터 - Arduino Leonardo 를 찾는다.

우클릭을 하면 게임 컨트롤러 설정 을 누르고 속성 버튼을 눌러 기어가 정상적으로 동작하는지 체크해본다.

나는 1, 2, 5, 6, R 기어는 정상적으로 나타나지만 3, 4 단이 정상적으로 들어가지 않았다.

X 축의 저항값이 제대로 잡히지 않는것 같아서 디버깅 환경을 만들어서 테스트를 해보았다.

Serial 포트를 열고, Serial 로그에 X 축 값이 몇으로 잡히는지 테스트 하는 코드를 추가하였다.

1
2
3
4
void setup() {
Serial.begin(9600); // 이 라인 추가
// ...
}
1
2
3
4
int x=analogRead(0);                 // X axis
int y=analogRead(2); // Y axis

Serial.println(x); // 이 라인 추가

이후 아두이노의 시리얼 모니터를 보며 쉬프터를 움직여보니 3, 4 단을 넣을 경우 약 540 정도의 값이 찍히고 있었다.

코드에서는 5, 6 단으로 인식하는 수치가 500정도로 설정이 되어있었고, 해당 값을 630 정도로 수정했다.

1
#define HS_XAXIS_56        630

후진 기어가 누른채로 6단을 넣을 때가 아니라 누르기만 해도 들어가는 버그와, 쉬프터를 좌측 (1단 2단 넣기위한 방향)으로 밀면 아날로그 핸드브레이크 모드로 동작하도록 하는 코드를 추가하였다.

기능들을 추가하며 전체적으로 코드 리포메팅을 하였기 때문에 변화가 많아 보일 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//Logitech Driving Force Shifter USB Adapter
//By Armandoiglesias 2018
//Based on Jason Duncan functionreturnfunction Project
//Video tutorial https://www.youtube.com/watch?v=dLpWEu8kCec
//Use Arduino Leonardo
//Install Joystick Library
//Attribution-NonCommercial-NoDerivatives 4.0 International

#include <Joystick.h>

// Create the Joystick
Joystick_ Joystick;

// H-shifter mode analog axis thresholds
#define HS_XAXIS_12 400
#define HS_XAXIS_56 500
#define HS_YAXIS_135 800
#define HS_YAXIS_246 300

// Sequential shifter mode analog axis thresholds
#define SS_UPSHIFT_BEGIN 670
#define SS_UPSHIFT_END 600
#define SS_DOWNSHIFT_BEGIN 430
#define SS_DOWNSHIFT_END 500

// Handbrake mode analog axis limits
#define HB_MAXIMUM 530
#define HB_MINIMUM 400
#define HB_RANGE (HB_MAXIMUM - HB_MINIMUM)

// Digital inputs definitions
#define DI_REVERSE 1
#define DI_MODE 3
#define DI_RED_CENTERRIGHT 4
#define DI_RED_CENTERLEFT 5
#define DI_RED_RIGHT 6
#define DI_RED_LEFT 7
#define DI_BLACK_TOP 8
#define DI_BLACK_RIGHT 9
#define DI_BLACK_LEFT 10
#define DI_BLACK_BOTTOM 11
#define DI_DPAD_RIGHT 12
#define DI_DPAD_LEFT 13
#define DI_DPAD_BOTTOM 14
#define DI_DPAD_TOP 15

// Shifter state
#define DOWN_SHIFT -1
#define NO_SHIFT 0
#define UP_SHIFT 1

// Shifter mode
#define SHIFTER_MODE 0
#define HANDBRAKE_MODE 1

// LED blink counter
int led = 0;

// Shifter state
int shift = NO_SHIFT;

// Handbrake mode
int mode = SHIFTER_MODE;

int b[16];

int gear = 0; // Default value is neutral

// Constant that maps the phyical pin to the joystick button.
//const int pinToButtonMap = 9;

void setup()
{
// G29 shifter analog inputs configuration
pinMode(A0, INPUT_PULLUP); // X axis
pinMode(A2, INPUT_PULLUP); // Y axis

pinMode(2, INPUT);

for (int i = 0; i < 16; i++)
b[i] = 0;
b[DI_MODE] = 0;
// Initialize Joystick Library
Joystick.begin();
}

// Last state of the button
int lastButtonState = 0;

void loop()
{

int x = analogRead(0); // X axis
int y = analogRead(2); // Y axis

int _isreverse = digitalRead(2);
int _gear_ = 0;

if (mode == HANDBRAKE_MODE)
{
int mapped = map(x, 300, 500, 0, 1024);
Joystick.setThrottle(mapped);
}
else
{
if (_isreverse == 1)
{
b[DI_REVERSE] = 1;
}
else
{
if (b[DI_MODE] == 0) // H-shifter mode?
{
if (x < HS_XAXIS_12) // Shifter on the left?
{
if (y > HS_YAXIS_135)
_gear_ = 1; // 1st gear
if (y < HS_YAXIS_246)
_gear_ = 2; // 2nd gear
}
else if (x > HS_XAXIS_56) // Shifter on the right?
{
if (y > HS_YAXIS_135)
_gear_ = 5; // 5th gear
if (y < HS_YAXIS_246)
_gear_ = 6; // 6th gear
}
else // Shifter is in the middle
{
if (y > HS_YAXIS_135)
_gear_ = 3; // 3rd gear
if (y < HS_YAXIS_246)
_gear_ = 4; // 4th gear
}
}
}

if (gear == 6 && _isreverse == 1) // Reverse gear is allowed only on 6th gear position
{
b[DI_REVERSE] = 1;
_gear_ = 8;
}
if (_gear_ != gear)
{
gear = _gear_;
desactivar();
Joystick.setButton(gear - 1, HIGH);
}
}
delay(50);
}

void desactivar()
{
// Depress virtual button for current gear
for (int i = 0; i <= 10; i++)
Joystick.setButton(i, LOW);
}

G29 Pedal

페달도 위 쉬프터 방법과 비슷하다.

다만 페달의 경우 점퍼케이블과 연결이 가능해서 납땜은 필요하지 않다.

영상을 참고해 1~4, 6, 9 번 핀을 연결한다.

한가지 아두이노 보드에 페달과 쉬프터를 모두 연결 할 예정이므로, 나는 2, 3, 4 번 포트를 각각 A3, A4, A5 에 연결하였다.

conn-pedal.jpg

이후 아래 코드를 통해 컴파일하여 업로드를 하고, 아까와 같이 잘 동작하는지 확인을 해 보았는데 모두 정상적으로 동작하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//Logitech Driving Force Shifter USB Adapter
//By Armandoiglesias 2018
//Based on Jason Duncan functionreturnfunction Project
//Video tutorial https://www.youtube.com/watch?v=dLpWEu8kCec
//Use Arduino Leonardo
//Install Joystick Library
//Attribution-NonCommercial-NoDerivatives 4.0 International

#include <Joystick.h>

// Create the Joystick
Joystick_ Joystick;

// H-shifter mode analog axis thresholds
#define HS_XAXIS_12 400
#define HS_XAXIS_56 500
#define HS_YAXIS_135 800
#define HS_YAXIS_246 300

// Sequential shifter mode analog axis thresholds
#define SS_UPSHIFT_BEGIN 670
#define SS_UPSHIFT_END 600
#define SS_DOWNSHIFT_BEGIN 430
#define SS_DOWNSHIFT_END 500

// Handbrake mode analog axis limits
#define HB_MAXIMUM 530
#define HB_MINIMUM 400
#define HB_RANGE (HB_MAXIMUM - HB_MINIMUM)

// Digital inputs definitions
#define DI_REVERSE 1
#define DI_MODE 3
#define DI_RED_CENTERRIGHT 4
#define DI_RED_CENTERLEFT 5
#define DI_RED_RIGHT 6
#define DI_RED_LEFT 7
#define DI_BLACK_TOP 8
#define DI_BLACK_RIGHT 9
#define DI_BLACK_LEFT 10
#define DI_BLACK_BOTTOM 11
#define DI_DPAD_RIGHT 12
#define DI_DPAD_LEFT 13
#define DI_DPAD_BOTTOM 14
#define DI_DPAD_TOP 15

// Shifter state
#define DOWN_SHIFT -1
#define NO_SHIFT 0
#define UP_SHIFT 1

// Shifter mode
#define SHIFTER_MODE 0
#define HANDBRAKE_MODE 1

// LED blink counter
int led = 0;

// Shifter state
int shift = NO_SHIFT;

// Handbrake mode
int mode = SHIFTER_MODE;

int b[16];

int gear = 0; // Default value is neutral

// Constant that maps the phyical pin to the joystick button.
//const int pinToButtonMap = 9;

void setup()
{
// For Debugging code
// Serial.begin(9600);

// G29 shifter analog inputs configuration
pinMode(A0, INPUT_PULLUP); // X axis
pinMode(A2, INPUT_PULLUP); // Y axis
pinMode(2, INPUT);

// Logitech G29 Pedal Input
pinMode(A3, INPUT_PULLUP); // Accelerator axis
pinMode(A4, INPUT_PULLUP); // Brake axis
pinMode(A5, INPUT_PULLUP); // Clutch axis

for (int i = 0; i < 16; i++)
b[i] = 0;
b[DI_MODE] = 0;
// Initialize Joystick Library
Joystick.begin();
}

// Last state of the button
int lastButtonState = 0;

void loop()
{
int x = analogRead(0); // X axis
int y = analogRead(2); // Y axis

int ac = analogRead(3); // Accelerator axis
int br = analogRead(4); // Brake axis
int cl = analogRead(5); // Clutch axis

// Serial.print(ac);
// Serial.print(" ");
// Serial.print(br);
// Serial.print(" ");
// Serial.println(cl);

int mappedAc = map(ac, 100, 925, 0, 1024);
int mappedBr = map(br, 400, 935, 0, 1024);
int mappedCl = map(cl, 135, 950, 0, 1024);

Joystick.setXAxis(mappedAc);
Joystick.setYAxis(mappedBr);
Joystick.setZAxis(mappedCl);

int _isreverse = digitalRead(2);
int _gear_ = 0;

if (mode == HANDBRAKE_MODE)
{
int mapped = map(x, 300, 500, 0, 1024);
Joystick.setThrottle(mapped);
}
else
{
if (_isreverse == 1)
{
b[DI_REVERSE] = 1;
}
else
{
if (b[DI_MODE] == 0) // H-shifter mode?
{
if (x < HS_XAXIS_12) // Shifter on the left?
{
if (y > HS_YAXIS_135)
_gear_ = 1; // 1st gear
if (y < HS_YAXIS_246)
_gear_ = 2; // 2nd gear
}
else if (x > HS_XAXIS_56) // Shifter on the right?
{
if (y > HS_YAXIS_135)
_gear_ = 5; // 5th gear
if (y < HS_YAXIS_246)
_gear_ = 6; // 6th gear
}
else // Shifter is in the middle
{
if (y > HS_YAXIS_135)
_gear_ = 3; // 3rd gear
if (y < HS_YAXIS_246)
_gear_ = 4; // 4th gear
}
}
}

if (gear == 6 && _isreverse == 1) // Reverse gear is allowed only on 6th gear position
{
b[DI_REVERSE] = 1;
_gear_ = 8;
}
if (_gear_ != gear)
{
gear = _gear_;
desactivar();
Joystick.setButton(gear - 1, HIGH);
}
}
delay(50);
}

void desactivar()
{
// Depress virtual button for current gear
for (int i = 0; i <= 10; i++)
Joystick.setButton(i, LOW);
}

만약 페달의 최소 위치와 최대 위치등을 조절하려면, 113~115 라인의 앞에 숫자 2가지 부분을 잘 조절하면 된다.

조절은 107~111 라인의 숫자를 기반으로 누르지 않은 상태와 끝까지 누른 상태의 적당한 값을 넣어서 맞추면 된다.

게임에서의 테스트

이렇게 연결하게 되면 문제점이 있다.

게임에서는 2가지의 레이싱 장비가 인식될 것이고, 휠과 쉬프터, 페달의 세팅을 게임마다 수동으로 지정을 해 주어야 한다.

아세토코르사 및 프로젝트카스2, 호라이즌4 에서는 조금 불편하지만 설정을 하게 되면 정상적으로 동작하는것을 확인했다.

다른 장비에서도 사용 가능할까?

이게 가능한 원리를 보면 결국 쉬프터나 페달들이 모두 가변저항의 아날로그 신호값을 통해 수치화를 하고 있는것을 알 수 있다.

요점은 연결에 사용되는 아날로그 신호의 단자를 찾는것일것 같다.

페달쪽 영상을 보면 테스터기를 통해 어떤 단자인지 찾는 부분이 보인다.

이 방법을 참고해서 배선만 잘 딴다면 어떤 장비던 사실 모두 적용이 가능하리라 본다.

문제는 c++ 을 조금 다룰 줄 알아야 자기가 원하는 동작을 하도록 구현이 가능한 것…

내가 이렇게 사용하게 된 계기는 결국 다른 페달과 쉬프터를 아직 구하지 못했기 때문이지만, 누군가에게는 이 글이 도움이 될 것 같아 남겨둔다.

댓글