forked from PK-420/iBus2USB
-
Notifications
You must be signed in to change notification settings - Fork 0
/
iBus2USB.ino
145 lines (127 loc) · 6.69 KB
/
iBus2USB.ino
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
/** iBus2USB v1.2.1 ****************************************************************************
By: Patrick Kerr
Target: Arduino Leonardo Pro Micro
Prerequisite: Have the Joystick library included in your "Arduino/libraries" folder
Wiring receiver (~5V):
# + on RAW pin (near USB port)
# - on GND pin
# Signal on Rx1 pin
This Sketch takes FlySky i-Bus Serial data from the receiver
and turns it into an USB Joystick to use with various drone simulators
(Tested in LiftOff, VelociDrone and DRL Simulator)
Using the ArduinoJoystickLibrary from MHeironimus on GitHub : https://git.io/Jvb7j
Also inspired by iBus2PPM from povlhp on GitHub for the iBus data reading loop
iBus2PPM : https://git.io/Jvb5e adapted for Leonardo board.
I am using a FlySky FS-i6 transmitter with custom firmware from benb0jangles on GitHub,
FlySky-i6-Mod- : https://git.io/Jvb54 which unlocks all 10 channels when using iBus and 8 in PPM,
but who wants to use PPM when almost every receiver can do iBus for the same price.
Copyright (c) 2017, Patrick Kerr
This source code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This source code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
**********************************************************************************************/
#include "Joystick.h"
// #define LED 9 // Error LED pin
#define RC_CHAN 11 // Maximum 14 due to buffer size limitations. // using 11 here due to Joystick analog axies limitation
#define MIN_COMMAND 1000 // Minimum value that the RC can send (Typically 1000us)
#define MAX_COMMAND 2000 // Maximum value that the RC can send (Typically 2000us)
#define STICK_CENTER (MIN_COMMAND+((MAX_COMMAND-MIN_COMMAND)/2))
#define IBUS_BUFFSIZE 32 // iBus packet size (2 byte header, space for 14 channels x 2 bytes, 2 byte checksum)
enum { // enum defines the order of channels
ROLL, // Channel 1 , index 0
PITCH,
THROTTLE,
YAW,
AUX1, // First Auxilary, Channel 5, index 4...
AUX2,
AUX3,
AUX4,
AUX5,
AUX6,
AUX7,
AUX8,
AUX9,
AUX10,
};
static Joystick_ Joystick(0x420, JOYSTICK_TYPE_JOYSTICK, 0, 0, true, true, true, true, true, true, true, true, true, true, true); // Maxed out 11 Analog Aux inputs
// Joystick_ Name( Joystick ID, Joystick Type, Btn,Hat, X, Y, Z, rX, rY, rZ, Rud., Thr., Acc., Brk., Str.
static uint8_t ibusIndex = 0; // Index counter, obviously...
static uint8_t ibus[IBUS_BUFFSIZE] = {0}; // iBus Buffer array
static uint16_t rcValue[RC_CHAN] = {0}; // RC/Joystick Values array
void setup() {
setupJoystick();
Serial1.begin(115200); // Serial1.(...) for Leonardo duhh
#ifdef LED
pinMode(LED, OUTPUT);
digitalWrite(LED, HIGH); // LED ON Until Proper iBUS RX signal is detected
#endif
}
void setupJoystick() {
Joystick.setXAxisRange(MIN_COMMAND, MAX_COMMAND); // Set ranges
Joystick.setYAxisRange(MIN_COMMAND, MAX_COMMAND);
Joystick.setZAxisRange(MIN_COMMAND, MAX_COMMAND);
Joystick.setRxAxisRange(MIN_COMMAND, MAX_COMMAND);
Joystick.setRyAxisRange(MIN_COMMAND, MAX_COMMAND);
Joystick.setRzAxisRange(MIN_COMMAND, MAX_COMMAND);
Joystick.setThrottleRange(MIN_COMMAND, MAX_COMMAND);
Joystick.setRudderRange(MIN_COMMAND, MAX_COMMAND);
Joystick.setAcceleratorRange(MIN_COMMAND, MAX_COMMAND);
Joystick.setBrakeRange(MIN_COMMAND, MAX_COMMAND);
Joystick.setSteeringRange(MIN_COMMAND, MAX_COMMAND);
Joystick.begin(false); // Initialize Joystick without autoSend State
}
void loop() {
if (Serial1.available()) {
uint8_t val = Serial1.read();
// Look for 0x2040 as start of packet
if (ibusIndex == 0 && val != 0x20) return; // Not 0x20 at index 0, // Skip all and wait another loop for a new byte
if (ibusIndex == 1 && val != 0x40) { // Not the expected 0x40 at index 1,
ibusIndex = 0; // so we have to reset the index.
return; // Skip all and wait next loop for another byte.
}
if (ibusIndex < IBUS_BUFFSIZE) ibus[ibusIndex] = val; // populate ibus array with current byte
ibusIndex++;
if (ibusIndex == IBUS_BUFFSIZE) { // End of packet, Verify integrity
ibusIndex = 0;
uint16_t chksum = 0xFFFF; // 16 bit Checksum starts at 0xFFFF ...
for (uint8_t i = 0; i < IBUS_BUFFSIZE - 2; i++) chksum -= ibus[i]; // ... and substracts every received byte (8 bit chunks) from the stream, including the header but not the 2 last bytes.
uint16_t rxsum = ibus[IBUS_BUFFSIZE - 2] + (ibus[IBUS_BUFFSIZE - 1] << 8); // Mash the 2 last bytes to form the received 16 bit Checksum, admire the bitshifting trickery to re-order bytes,
if (chksum == rxsum) { // Good Packet // Least Significant Byte always received first. Example: Receive "0xDC05" means "0x05DC" = 1500
for (uint8_t i = 0; i < RC_CHAN; i++) { // Put each channel value in its place
uint16_t rcVal = (ibus[(2*i)+3] << 8) + ibus[(2*i)+2]; // Mash the 2 bytes from each channel together to get 16 bit rcValue, First 2 bytes ignored (0x2040)
if ((rcVal < MIN_COMMAND) || (rcVal > MAX_COMMAND)) return; // if rcValue is out of bounds (MIN_COMMAND/MAX_COMMAND) the frame is discarded;
rcValue[i] = rcVal;
}
updateJoystick(); // When RX Frame is done, update Joystick values and send its state to the computer.
#ifdef LED
digitalWrite(LED, LOW); // OK Packet, Clear LED
#endif
}
#ifdef LED
else digitalWrite(LED, HIGH); // Checksum Error
#endif
}
}
}
void updateJoystick() {
Joystick.setXAxis(rcValue[ROLL]);
Joystick.setYAxis(rcValue[PITCH]);
Joystick.setThrottle(rcValue[THROTTLE]);
Joystick.setRzAxis(rcValue[YAW]);
Joystick.setZAxis(rcValue[AUX1]);
Joystick.setRxAxis(rcValue[AUX2]);
Joystick.setRyAxis(rcValue[AUX3]);
Joystick.setRudder(rcValue[AUX4]);
Joystick.setAccelerator(rcValue[AUX5]);
Joystick.setBrake(rcValue[AUX6]);
Joystick.setSteering(rcValue[AUX7]);
Joystick.sendState();
}