Télécommande intelligente : Différence entre versions
m (→Câblage) |
m |
||
(8 révisions intermédiaires par le même utilisateur non affichées) | |||
Ligne 5 : | Ligne 5 : | ||
'''Projet réalisé par''' [[Utilisateur:fma38|fma38]]. | '''Projet réalisé par''' [[Utilisateur:fma38|fma38]]. | ||
− | '' | + | ''Abandonné'' |
== Présentation == | == Présentation == | ||
Ligne 14 : | Ligne 14 : | ||
La partie électronique se fait via une carte [https://www.pjrc.com/store/teensypp.html Teensy++] (plein d'I/O, émulation clavier/souris/joystick si besoin...) | La partie électronique se fait via une carte [https://www.pjrc.com/store/teensypp.html Teensy++] (plein d'I/O, émulation clavier/souris/joystick si besoin...) | ||
+ | |||
+ | == Cahier des charges == | ||
+ | |||
+ | * 2 joysticks, chacun ayant : | ||
+ | ** 3 voies analogiques | ||
+ | ** 1 hat 4 directions | ||
+ | ** 4 boutons | ||
+ | * autres commandes (boutons, switchs, potars...) si besoin | ||
+ | * retour d'info : | ||
+ | ** leds | ||
+ | ** écran lcd | ||
+ | ** vibreur | ||
+ | ** visu caméra (FPV) | ||
+ | * communication BT | ||
+ | |||
+ | == Réalisation == | ||
+ | |||
+ | Cette télécommande est basée sur l'utilisation de 2 manches de joystick '''Saitek Cyborg Digital 3D'''. À l'origine, ce joystick se branchait sur un port joystick/midi (sub-D 15) ; une version série puis usb a été fabriquée par la suite. Pour ce projet, n'importe quelle version peut être utilisée, mais vu que l'électronique ne sera pas utilisée, autant acheter la version la moins chère. En fait, n'importe quel joystick peut être utilisé, à condition qu'il ne soit pas à lecture optique, comme les Sidewinder de Microsoft. | ||
+ | |||
+ | À noter que le Cyborg peut être configuré en gaucher ; c'est indispensable ici ! | ||
+ | |||
+ | [[Fichier:Saitek_cybrog_digital.jpg|200px]] | ||
+ | |||
+ | Seule la partie joystick est conservée. On commence par couper les fils qui sortent du manche lui-même en les gardant les plus longs possible : | ||
+ | |||
+ | [[Fichier:IMG_20160301_174538.jpg|300px]] | ||
+ | |||
+ | Puis on coupe la base au niveau du cylindre et on fixe les 2 manches sur une planche à l'aide d'une bride imprimée : | ||
+ | |||
+ | [[Fichier:IMG_20160301_174654.jpg|300px]] | ||
+ | [[Fichier:IMG_20160223_122655.jpg|300px]] | ||
+ | |||
+ | La connectique vers le Teensy++ : | ||
+ | |||
+ | [[Fichier:IMG_20160301_180827.jpg|300px]] | ||
+ | [[Fichier:IMG_20160301_180516.jpg|300px]] | ||
== Câblage == | == Câblage == | ||
− | + | Tableau de correspondance des fils du joystick : | |
+ | |||
+ | rouge : ground potar RZ | ||
+ | : signal potar RZ | ||
+ | : ref. potar RZ | ||
+ | |||
+ | noir : button common | ||
+ | : hat N | ||
+ | : hat S | ||
+ | : hat E | ||
+ | : hat W | ||
+ | : button left | ||
+ | : button middle | ||
+ | : button right | ||
+ | : button trigger | ||
+ | |||
+ | Câblage retenu sur le [https://www.pjrc.com/teensy/card4b.pdf Teensy++], incluant le pilotage futur d'un écran LCD graphique type xxx : | ||
A0 : X 0 | A0 : X 0 | ||
Ligne 70 : | Ligne 122 : | ||
<syntaxhighlight lang="C"> | <syntaxhighlight lang="C"> | ||
− | const uint8_t | + | #include <Bounce2.h> |
+ | |||
+ | const uint8_t DEBOUNCE_DELAY = 10; // 10ms is appropriate for most mechanical pushbuttons | ||
const uint8_t AXIS[] = { | const uint8_t AXIS[] = { | ||
Ligne 82 : | Ligne 136 : | ||
const uint8_t BUTTONS[] = { | const uint8_t BUTTONS[] = { | ||
− | + | ||
− | // Joystick right | + | // Joystick right |
10, // hat N - mapped to BTN_JOYSTICK/BTN_TRIGGER (0x120) | 10, // hat N - mapped to BTN_JOYSTICK/BTN_TRIGGER (0x120) | ||
11, // hat S - mapped to BTN_THUMB (0x121) | 11, // hat S - mapped to BTN_THUMB (0x121) | ||
Ligne 92 : | Ligne 146 : | ||
16, // right - mapped to BTN_BASE (0x126) | 16, // right - mapped to BTN_BASE (0x126) | ||
17, // trigger - mapped to BTN_BASE2 (0x127) | 17, // trigger - mapped to BTN_BASE2 (0x127) | ||
− | + | ||
// Joystick left | // Joystick left | ||
20, // hat N - mapped to BTN_BASE3 (0x128) | 20, // hat N - mapped to BTN_BASE3 (0x128) | ||
Ligne 105 : | Ligne 159 : | ||
const uint8_t SAMPLES = 10; | const uint8_t SAMPLES = 10; | ||
− | |||
uint8_t rawAxis[6][SAMPLES]; | uint8_t rawAxis[6][SAMPLES]; | ||
uint16_t axis[6]; | uint16_t axis[6]; | ||
Ligne 111 : | Ligne 164 : | ||
uint8_t buttons[32], prevButtons[32]; | uint8_t buttons[32], prevButtons[32]; | ||
uint8_t index = 0; | uint8_t index = 0; | ||
+ | |||
+ | Bounce *bouncer; | ||
Ligne 117 : | Ligne 172 : | ||
// Init Joystick | // Init Joystick | ||
Joystick.useManualSend(true); | Joystick.useManualSend(true); | ||
− | |||
− | |||
− | |||
// Init axis readings | // Init axis readings | ||
Ligne 130 : | Ligne 182 : | ||
} | } | ||
− | + | bouncer = (Bounce *)malloc(sizeof(BUTTONS) * sizeof(Bounce)); | |
for (uint8_t i=0; i<sizeof(BUTTONS); i++) { | for (uint8_t i=0; i<sizeof(BUTTONS); i++) { | ||
+ | |||
+ | // Init digital inputs (buttons) | ||
pinMode(BUTTONS[i], INPUT_PULLUP); | pinMode(BUTTONS[i], INPUT_PULLUP); | ||
+ | buttons[i] = 0; | ||
+ | prevButtons[i] = 0; | ||
+ | |||
+ | // Create bounce objects | ||
+ | bouncer[i] = Bounce(); | ||
+ | bouncer[i].attach(BUTTONS[i]); | ||
+ | bouncer[i].interval(DEBOUNCE_DELAY); | ||
} | } | ||
} | } | ||
Ligne 150 : | Ligne 211 : | ||
Joystick.X(axis[i] / SAMPLES); | Joystick.X(axis[i] / SAMPLES); | ||
break; | break; | ||
− | + | ||
case 1: | case 1: | ||
Joystick.Y(axis[i] / SAMPLES); | Joystick.Y(axis[i] / SAMPLES); | ||
break; | break; | ||
− | + | ||
case 2: | case 2: | ||
Joystick.Z(axis[i] / SAMPLES); | Joystick.Z(axis[i] / SAMPLES); | ||
break; | break; | ||
− | + | ||
case 3: | case 3: | ||
Joystick.sliderLeft(axis[i] / SAMPLES); | Joystick.sliderLeft(axis[i] / SAMPLES); | ||
break; | break; | ||
− | + | ||
case 4: | case 4: | ||
Joystick.sliderRight(axis[i] / SAMPLES); | Joystick.sliderRight(axis[i] / SAMPLES); | ||
break; | break; | ||
− | + | ||
case 5: | case 5: | ||
Joystick.Zrotate(axis[i] / SAMPLES); | Joystick.Zrotate(axis[i] / SAMPLES); | ||
break; | break; | ||
− | + | ||
default: | default: | ||
break; | break; | ||
} | } | ||
− | |||
} | } | ||
index++; | index++; | ||
Ligne 180 : | Ligne 240 : | ||
index = 0; | index = 0; | ||
} | } | ||
− | + | ||
// Read up to 32 digital pins and use them as buttons | // Read up to 32 digital pins and use them as buttons | ||
uint8_t index = 1; | uint8_t index = 1; | ||
for (uint8_t i=0; i<sizeof(BUTTONS); i++) { | for (uint8_t i=0; i<sizeof(BUTTONS); i++) { | ||
− | buttons[i] | + | |
+ | // Update buttons | ||
+ | bouncer[i].update(); | ||
+ | if (bouncer[i].read()) { | ||
+ | buttons[i] = 0; | ||
+ | } | ||
+ | else { | ||
+ | buttons[i] = 1; | ||
+ | } | ||
Joystick.button(index++, buttons[i]); | Joystick.button(index++, buttons[i]); | ||
} | } | ||
− | + | ||
// Complete USB joystick buttons (up to 32) | // Complete USB joystick buttons (up to 32) | ||
while (index <= 32) { | while (index <= 32) { | ||
Ligne 207 : | Ligne 275 : | ||
prevButtons[i] = buttons[i]; | prevButtons[i] = buttons[i]; | ||
} | } | ||
− | + | ||
// If any axis/button changed, update USB/BT | // If any axis/button changed, update USB/BT | ||
if (anyChange) { | if (anyChange) { | ||
− | + | ||
// Send datas to USB joystick channel | // Send datas to USB joystick channel | ||
Joystick.send_now(); | Joystick.send_now(); | ||
− | |||
− | |||
− | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− |
Version actuelle en date du 18 janvier 2017 à 13:51
Langue : | Français • English |
---|
Projet réalisé par fma38.
Abandonné
Présentation
Réalisation d'une télécommande intelligente pour piloter un hexapode, à base de joysticks.
L'idée est de faire un système où tout peut être fait sans enlever les mains des joysticks.
La partie électronique se fait via une carte Teensy++ (plein d'I/O, émulation clavier/souris/joystick si besoin...)
Cahier des charges
- 2 joysticks, chacun ayant :
- 3 voies analogiques
- 1 hat 4 directions
- 4 boutons
- autres commandes (boutons, switchs, potars...) si besoin
- retour d'info :
- leds
- écran lcd
- vibreur
- visu caméra (FPV)
- communication BT
Réalisation
Cette télécommande est basée sur l'utilisation de 2 manches de joystick Saitek Cyborg Digital 3D. À l'origine, ce joystick se branchait sur un port joystick/midi (sub-D 15) ; une version série puis usb a été fabriquée par la suite. Pour ce projet, n'importe quelle version peut être utilisée, mais vu que l'électronique ne sera pas utilisée, autant acheter la version la moins chère. En fait, n'importe quel joystick peut être utilisé, à condition qu'il ne soit pas à lecture optique, comme les Sidewinder de Microsoft.
À noter que le Cyborg peut être configuré en gaucher ; c'est indispensable ici !
Seule la partie joystick est conservée. On commence par couper les fils qui sortent du manche lui-même en les gardant les plus longs possible :
Puis on coupe la base au niveau du cylindre et on fixe les 2 manches sur une planche à l'aide d'une bride imprimée :
La connectique vers le Teensy++ :
Câblage
Tableau de correspondance des fils du joystick :
rouge : ground potar RZ : signal potar RZ : ref. potar RZ noir : button common : hat N : hat S : hat E : hat W : button left : button middle : button right : button trigger
Câblage retenu sur le Teensy++, incluant le pilotage futur d'un écran LCD graphique type xxx :
A0 : X 0 A1 : Y 0 A2 : RZ 0 A3 : X 1 A4 : Y 1 A5 : RZ 1 A6 : free A7 : free 0 : free 1 : free 2 : RX BT 3 : TX BT 4 : free 5 : free 6 : free (led) 7 : free 8 : CE LCD 9 : CS LCD 10 : hat N 0 11 : hat S 0 12 : hat E 0 13 : hat W 0 14 : button left 0 15 : button middle 0 16 : button right 0 17 : button trigger 0 18 : RD LCD 19 : WR LCD 20 : hat N 1 21 : hat S 1 22 : hat E 1 23 : hat W 1 24 : button left 1 25 : button middle 1 26 : button right 1 27 : button trigger 1 28 : D0 LCD 29 : D1 LCD 30 : D2 LCD 31 : D3 LCD 32 : D4 LCD 33 : D5 LCD 34 : D6 LCD 35 : D7 LCD
Soft
Exemple de code émulant 1 joystick USB avec 6 axes analogiques et 16 boutons :
#include <Bounce2.h> const uint8_t DEBOUNCE_DELAY = 10; // 10ms is appropriate for most mechanical pushbuttons const uint8_t AXIS[] = { 0, // X, joystick right - mapped to ABS_X (0x00) 1, // Y, joystick right - mapped to ABS_Y (0x01) 2, // RZ, joystick right - mapped to ABS_Z (0x02) 3, // X, joystick left - mapped to ABS_THROTTLE (0x06) 4, // Y, joystick left - mapped to ABS_RUDDER (0x07) 5 // RZ, joystick left - mapped to ABS_RZ (0x05) }; const uint8_t BUTTONS[] = { // Joystick right 10, // hat N - mapped to BTN_JOYSTICK/BTN_TRIGGER (0x120) 11, // hat S - mapped to BTN_THUMB (0x121) 12, // hat E - mapped to BTN_THUMB2 (0x122) 13, // hat W - mapped to BTN_TOP (0x123) 14, // left - mapped to BTN_TOP2 (0x124) 15, // middle - mapped to BTN_PINKIE (0x125) 16, // right - mapped to BTN_BASE (0x126) 17, // trigger - mapped to BTN_BASE2 (0x127) // Joystick left 20, // hat N - mapped to BTN_BASE3 (0x128) 21, // hat S - mapped to BTN_BASE4 (0x129) 22, // hat E - mapped to BTN_BASE5 (0x12a) 23, // hat W - mapped to BTN_BASE6 (0x12b) 24, // left - mapped to BTN_DEAD (0x12f) 25, // middle - mapped to BTN_GAMEPAD/BTN_SOUTH/BTN_A (0x130) 26, // right - mapped to BTN_EAST/BTN_B (0x131) 27, // trigger - mapped to BTN_C (0x132) }; const uint8_t SAMPLES = 10; uint8_t rawAxis[6][SAMPLES]; uint16_t axis[6]; uint8_t prevAxis[6]; uint8_t buttons[32], prevButtons[32]; uint8_t index = 0; Bounce *bouncer; void setup() { // Init Joystick Joystick.useManualSend(true); // Init axis readings for (uint8_t i=0; i<sizeof(AXIS); i++) { axis[i] = 0; prevAxis[i] = 0; for (uint8_t j=0; j<SAMPLES; j++) { rawAxis[i][j] = 0; } } bouncer = (Bounce *)malloc(sizeof(BUTTONS) * sizeof(Bounce)); for (uint8_t i=0; i<sizeof(BUTTONS); i++) { // Init digital inputs (buttons) pinMode(BUTTONS[i], INPUT_PULLUP); buttons[i] = 0; prevButtons[i] = 0; // Create bounce objects bouncer[i] = Bounce(); bouncer[i].attach(BUTTONS[i]); bouncer[i].interval(DEBOUNCE_DELAY); } } void loop() { // Read up to 6 analog inputs and use them as axis for (uint8_t i=0; i<sizeof(AXIS); i++) { axis[i] = axis[i] - rawAxis[i][index]; rawAxis[i][index] = analogRead(AXIS[i]) >> 2; // remove noisy bits axis[i] = axis[i] + rawAxis[i][index]; switch (i) { case 0: Joystick.X(axis[i] / SAMPLES); break; case 1: Joystick.Y(axis[i] / SAMPLES); break; case 2: Joystick.Z(axis[i] / SAMPLES); break; case 3: Joystick.sliderLeft(axis[i] / SAMPLES); break; case 4: Joystick.sliderRight(axis[i] / SAMPLES); break; case 5: Joystick.Zrotate(axis[i] / SAMPLES); break; default: break; } } index++; if (index >= SAMPLES) { index = 0; } // Read up to 32 digital pins and use them as buttons uint8_t index = 1; for (uint8_t i=0; i<sizeof(BUTTONS); i++) { // Update buttons bouncer[i].update(); if (bouncer[i].read()) { buttons[i] = 0; } else { buttons[i] = 1; } Joystick.button(index++, buttons[i]); } // Complete USB joystick buttons (up to 32) while (index <= 32) { Joystick.button(index++, 0); } // check to see if any axis/button changed since last time boolean anyChange = false; for (uint8_t i=0; i<sizeof(AXIS); i++) { if (axis[i] != prevAxis[i]) { anyChange = true; } prevAxis[i] = axis[i]; } for (uint8_t i=0; i<sizeof(BUTTONS); i++) { if (buttons[i] != prevButtons[i]) { anyChange = true; } prevButtons[i] = buttons[i]; } // If any axis/button changed, update USB/BT if (anyChange) { // Send datas to USB joystick channel Joystick.send_now(); }