Library to handle SpaceBall, SpaceMouse and SpaceOrb on serial port. Gets access to 3D rotation and translation vector as well as button status. (USB is not supported)

Dependents:   SpaceBall_Example

Library to handle SpaceBall, SpaceMouse and SpaceOrb on serial port. Gets access to 3D rotation and translation vector as well as button status. (USB is not supported)

All handling and decoding is done in the RX interrupt and the vector values can be read out asynchronously with different coordinate mappings.

Example:

#include "mbed.h"
#include "SpaceBall.h"
 
PwmOut led[] = {(LED1), (LED2), (LED3), (LED4) };
SpaceBall SBall(p9, p10);   // tx, rx, bSOrb
 
int main() {
    SBall.Init();
    
    while(1) {
 
        led[0] = abs( SBall[TX] ) + abs( SBall[TY] ) + abs( SBall[TZ] );
        led[1] = abs( SBall[RX] );
        led[2] = abs( SBall[RY] );
        led[3] = abs( SBall[RZ] );
        
        wait_us(500);
    }
}

In this exaple the 4 LEDs are powered dependent on force at the Spaceball. LED1 shows the sum of all translation forces. LED2 to LED4 shows the rotation forces.

For more information about SpaceBall devices see manufactorers page http://www.3dconnexion.com

For connecting a SpaceBall (or SpaceMouse or SpaceOrb) to mbed see page wiki/Serial-Connection

Example: SpaceBall 4000

/media/uploads/jocis/spaceball1.jpg

Committer:
jocis
Date:
Wed Sep 03 07:36:43 2014 +0000
Revision:
4:f953792e45cb
Parent:
2:a7c0fcd157f7
Added documentation

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jocis 1:e6282b645d9b 1 #include "SpaceBall.h"
jocis 1:e6282b645d9b 2
jocis 2:a7c0fcd157f7 3 #define Sleep(x) wait_ms(x)
jocis 1:e6282b645d9b 4
jocis 2:a7c0fcd157f7 5 //extern Serial pc;
jocis 1:e6282b645d9b 6
jocis 1:e6282b645d9b 7 ///////////////////////////////////////////////////////////////////////////////
jocis 1:e6282b645d9b 8
jocis 1:e6282b645d9b 9 /*
jocis 1:e6282b645d9b 10 Convert characters to nibbles
jocis 1:e6282b645d9b 11 */
jocis 1:e6282b645d9b 12 int DecodeSM(char c)
jocis 1:e6282b645d9b 13 {
jocis 1:e6282b645d9b 14 int n;
jocis 1:e6282b645d9b 15
jocis 1:e6282b645d9b 16 switch (c) {
jocis 1:e6282b645d9b 17 case '0': n = 0; break;
jocis 1:e6282b645d9b 18 case 'A': n = 1; break;
jocis 1:e6282b645d9b 19 case 'B': n = 2; break;
jocis 1:e6282b645d9b 20 case '3': n = 3; break;
jocis 1:e6282b645d9b 21 case 'D': n = 4; break;
jocis 1:e6282b645d9b 22 case '5': n = 5; break;
jocis 1:e6282b645d9b 23 case '6': n = 6; break;
jocis 1:e6282b645d9b 24 case 'G': n = 7; break;
jocis 1:e6282b645d9b 25 case 'H': n = 8; break;
jocis 1:e6282b645d9b 26 case '9': n = 9; break;
jocis 1:e6282b645d9b 27 case ':': n = 10; break;
jocis 1:e6282b645d9b 28 case 'K': n = 11; break;
jocis 1:e6282b645d9b 29 case '<': n = 12; break;
jocis 1:e6282b645d9b 30 case 'M': n = 13; break;
jocis 1:e6282b645d9b 31 case 'N': n = 14; break;
jocis 1:e6282b645d9b 32 case '?': n = 15; break;
jocis 1:e6282b645d9b 33 default: n = 0; break;
jocis 1:e6282b645d9b 34 }
jocis 1:e6282b645d9b 35
jocis 1:e6282b645d9b 36 return(n);
jocis 1:e6282b645d9b 37 }
jocis 1:e6282b645d9b 38
jocis 1:e6282b645d9b 39 ///////////////////////////////////////////////////////////////////////////////
jocis 1:e6282b645d9b 40
jocis 1:e6282b645d9b 41 void SpaceBall::InitSB()
jocis 1:e6282b645d9b 42 {
jocis 1:e6282b645d9b 43 m_resetoccured=0;
jocis 1:e6282b645d9b 44
jocis 2:a7c0fcd157f7 45 m_spaceball4000 = 0; /* re-determine which type it is */
jocis 1:e6282b645d9b 46 m_leftymode4000 = 0; /* re-determine if its in lefty mode */
jocis 1:e6282b645d9b 47
jocis 2:a7c0fcd157f7 48 _fScaleT = 1.0 / 5000.0;
jocis 2:a7c0fcd157f7 49 _fScaleR = 1.0 / 2000.0;
jocis 2:a7c0fcd157f7 50
jocis 1:e6282b645d9b 51 if (!m_resetoccured) {
jocis 1:e6282b645d9b 52 m_resetoccured=1;
jocis 1:e6282b645d9b 53 _serial.printf ( "@\r" ); /* force reset */
jocis 1:e6282b645d9b 54 }
jocis 1:e6282b645d9b 55
jocis 1:e6282b645d9b 56 Sleep(10);
jocis 1:e6282b645d9b 57
jocis 1:e6282b645d9b 58 // pc.printf("Sending initialization sequence to spaceball...\n");
jocis 1:e6282b645d9b 59
jocis 1:e6282b645d9b 60 _serial.printf ( "CB\r" );
jocis 1:e6282b645d9b 61 Sleep(10);
jocis 1:e6282b645d9b 62 _serial.printf ( "NT\r" );
jocis 1:e6282b645d9b 63 Sleep(10);
jocis 1:e6282b645d9b 64 _serial.printf ( "FTp\r" );
jocis 1:e6282b645d9b 65 Sleep(10);
jocis 1:e6282b645d9b 66 _serial.printf ( "FRp\r" );
jocis 1:e6282b645d9b 67 Sleep(10);
jocis 1:e6282b645d9b 68 _serial.printf ( "P@r@r\r" );
jocis 1:e6282b645d9b 69 Sleep(10);
jocis 1:e6282b645d9b 70 _serial.printf ( "MSSV\r" );
jocis 1:e6282b645d9b 71 Sleep(10);
jocis 1:e6282b645d9b 72 _serial.printf ( "Z\r" );
jocis 1:e6282b645d9b 73 Sleep(10);
jocis 1:e6282b645d9b 74 _serial.printf ( "BcCcC\r" );
jocis 1:e6282b645d9b 75
jocis 1:e6282b645d9b 76 Sleep(10);
jocis 1:e6282b645d9b 77 _serial.printf ( "\rvz\r" );
jocis 1:e6282b645d9b 78 Sleep(10);
jocis 1:e6282b645d9b 79 _serial.printf ( "vQ\r" );
jocis 1:e6282b645d9b 80 Sleep(10);
jocis 1:e6282b645d9b 81 _serial.printf ( "kQ\r" );
jocis 1:e6282b645d9b 82 Sleep(10);
jocis 1:e6282b645d9b 83 _serial.printf ( "m3\r" );
jocis 1:e6282b645d9b 84 }
jocis 1:e6282b645d9b 85
jocis 1:e6282b645d9b 86 ///////////////////////////////////////////////////////////////////////////////
jocis 1:e6282b645d9b 87
jocis 1:e6282b645d9b 88 void SpaceBall::ProcessSB ( char data )
jocis 1:e6282b645d9b 89 {
jocis 1:e6282b645d9b 90 switch (data) {
jocis 1:e6282b645d9b 91 case '\r': //0xd:
jocis 1:e6282b645d9b 92 _data[_idx] = 0;
jocis 1:e6282b645d9b 93 ProcessPacketSB();
jocis 1:e6282b645d9b 94 _idx = 0;
jocis 1:e6282b645d9b 95 _escape = 0;
jocis 1:e6282b645d9b 96 break;
jocis 1:e6282b645d9b 97 case '^':
jocis 1:e6282b645d9b 98 if (!_escape) {
jocis 1:e6282b645d9b 99 _escape = 1;
jocis 1:e6282b645d9b 100 break;
jocis 1:e6282b645d9b 101 }
jocis 1:e6282b645d9b 102 _escape = 0;
jocis 1:e6282b645d9b 103 case 'M':
jocis 1:e6282b645d9b 104 case 'Q':
jocis 1:e6282b645d9b 105 case 'S':
jocis 1:e6282b645d9b 106 if (_escape) {
jocis 1:e6282b645d9b 107 _escape = 0;
jocis 1:e6282b645d9b 108 data &= 0x1f;
jocis 1:e6282b645d9b 109 }
jocis 1:e6282b645d9b 110 default:
jocis 1:e6282b645d9b 111 if (_escape)
jocis 1:e6282b645d9b 112 _escape = 0;
jocis 1:e6282b645d9b 113 if (_idx < SPACEBALL_MAX_LENGTH)
jocis 1:e6282b645d9b 114 _data[_idx++] = data;
jocis 1:e6282b645d9b 115 break;
jocis 1:e6282b645d9b 116 }
jocis 1:e6282b645d9b 117 }
jocis 1:e6282b645d9b 118
jocis 1:e6282b645d9b 119 ///////////////////////////////////////////////////////////////////////////////
jocis 1:e6282b645d9b 120
jocis 1:e6282b645d9b 121 void SpaceBall::ProcessPacketSB ( void )
jocis 1:e6282b645d9b 122 {
jocis 1:e6282b645d9b 123 int i;
jocis 1:e6282b645d9b 124
jocis 1:e6282b645d9b 125 if (_idx < 2) return;
jocis 1:e6282b645d9b 126
jocis 1:e6282b645d9b 127 switch (_data[0]) {
jocis 1:e6282b645d9b 128
jocis 1:e6282b645d9b 129 case 'D': /* Ball data */
jocis 1:e6282b645d9b 130 if (_idx != 15) return;
jocis 1:e6282b645d9b 131 for (i = 0; i < 6; i++) {
jocis 2:a7c0fcd157f7 132 _axis[i] = (short)( (_data[2*i + 3] << 8) | _data[2*i + 2] );
jocis 1:e6282b645d9b 133 }
jocis 1:e6282b645d9b 134 DoChangedAxis();
jocis 1:e6282b645d9b 135 break;
jocis 1:e6282b645d9b 136
jocis 1:e6282b645d9b 137 case 'd': /* Ball data */
jocis 1:e6282b645d9b 138 //pc.printf("d%d",_idx);
jocis 1:e6282b645d9b 139 if (_idx != 25) return;
jocis 1:e6282b645d9b 140 for (i = 0; i < 6; i++) {
jocis 2:a7c0fcd157f7 141 _axis[i] = (short)( (
jocis 1:e6282b645d9b 142 DecodeSM(_data[4*i+4]) | (DecodeSM(_data[4*i+3])<<4) | (DecodeSM(_data[4*i+2])<<8) | (DecodeSM(_data[4*i+1])<<12) )
jocis 1:e6282b645d9b 143 ^ 0x8000 );
jocis 1:e6282b645d9b 144 }
jocis 1:e6282b645d9b 145 DoChangedAxis();
jocis 1:e6282b645d9b 146 break;
jocis 1:e6282b645d9b 147
jocis 1:e6282b645d9b 148 case 'K': /* Button data */
jocis 1:e6282b645d9b 149 if (_idx != 3) return;
jocis 1:e6282b645d9b 150 /* Spaceball 2003A, 2003B, 2003 FLX, 3003 FLX, 4000 FLX */
jocis 1:e6282b645d9b 151 /* button packet. (4000 only for backwards compatibility) */
jocis 1:e6282b645d9b 152 /* The lowest 5 bits of the first byte are buttons 5-9 */
jocis 1:e6282b645d9b 153 /* Button '8' on a Spaceball 2003 is the rezero button */
jocis 1:e6282b645d9b 154 /* The lowest 4 bits of the second byte are buttons 1-4 */
jocis 1:e6282b645d9b 155 /* For Spaceball 2003, we'll map the buttons 1-7 normally */
jocis 1:e6282b645d9b 156 /* skip 8, as its a hardware "rezero button" on that device */
jocis 1:e6282b645d9b 157 /* and call the "pick" button "8". */
jocis 1:e6282b645d9b 158 /* On the Spaceball 3003, the "right" button also triggers */
jocis 1:e6282b645d9b 159 /* the "pick" bit. We OR the 2003/3003 rezero bits together */
jocis 1:e6282b645d9b 160
jocis 1:e6282b645d9b 161 /* if we have found a Spaceball 4000, then we ignore the 'K' */
jocis 1:e6282b645d9b 162 /* packets entirely, and only use the '.' packets. */
jocis 1:e6282b645d9b 163 if (m_spaceball4000)
jocis 1:e6282b645d9b 164 break;
jocis 1:e6282b645d9b 165
jocis 2:a7c0fcd157f7 166 _buttons =
jocis 1:e6282b645d9b 167 ((_data[1] & 0x10) << 8) | /* 2003 pick button is ??? */
jocis 1:e6282b645d9b 168 ((_data[1] & 0x20) << 9) | /* 3003 rezero button */
jocis 1:e6282b645d9b 169 ((_data[1] & 0x08) << 11) | /* 2003 rezero button */
jocis 1:e6282b645d9b 170 ((_data[1] & 0x07) << 4) | /* 5,6,7 (2003/4000) */
jocis 1:e6282b645d9b 171 ((_data[2] & 0x30) << 8) | /* 3003 Left/Right buttons */
jocis 1:e6282b645d9b 172 ((_data[2] & 0x0F)); /* 1,2,3,4 (2003/4000) */
jocis 1:e6282b645d9b 173
jocis 1:e6282b645d9b 174 DoChangedButtons();
jocis 1:e6282b645d9b 175 break;
jocis 1:e6282b645d9b 176
jocis 1:e6282b645d9b 177 case 'k': /* Button data */
jocis 1:e6282b645d9b 178 //pc.printf("k%d",_idx);
jocis 2:a7c0fcd157f7 179 //pc.printf("<%s>\r\n",_data);
jocis 1:e6282b645d9b 180 if (_idx != 4) return;
jocis 2:a7c0fcd157f7 181 _buttons = DecodeSM(_data[1]) | (DecodeSM(_data[2])<<4) | (DecodeSM(_data[3])<<8);
jocis 1:e6282b645d9b 182
jocis 1:e6282b645d9b 183 DoChangedButtons();
jocis 1:e6282b645d9b 184 break;
jocis 1:e6282b645d9b 185
jocis 1:e6282b645d9b 186 case '.': /* Advanced button data */
jocis 1:e6282b645d9b 187 if (_idx != 3) return;
jocis 1:e6282b645d9b 188 /* Spaceball 4000 FLX "expanded" button packet, with 12 buttons */
jocis 1:e6282b645d9b 189
jocis 1:e6282b645d9b 190 /* extra packet validity check, since we use this packet type */
jocis 1:e6282b645d9b 191 /* to override the 'K' button packets, and determine if its a */
jocis 1:e6282b645d9b 192 /* Spaceball 4000 or not... */
jocis 1:e6282b645d9b 193
jocis 1:e6282b645d9b 194 /* if we got a valid '.' packet, this must be a Spaceball 4000 */
jocis 1:e6282b645d9b 195 m_spaceball4000 = 1; /* Must be talking to a Spaceball 4000 */
jocis 1:e6282b645d9b 196
jocis 1:e6282b645d9b 197 /* Spaceball 4000 series "expanded" button press event */
jocis 1:e6282b645d9b 198 /* includes data for 12 buttons, and left/right orientation */
jocis 2:a7c0fcd157f7 199 _buttons =
jocis 1:e6282b645d9b 200 (((~_data[1]) & 0x20) << 10) | /* "left handed" mode */
jocis 1:e6282b645d9b 201 ((_data[1] & 0x1F) << 7) | /* 8,9,10,11,12 */
jocis 1:e6282b645d9b 202 ((_data[2] & 0x3F) ) | /* 1,2,3,4,5,6 (4000) */
jocis 1:e6282b645d9b 203 ((_data[2] & 0x80) >> 1); /* 7 (4000) */
jocis 1:e6282b645d9b 204
jocis 1:e6282b645d9b 205 /* set "lefty" orientation mode if "lefty bit" is _clear_ */
jocis 1:e6282b645d9b 206 if ((_data[1] & 0x20) == 0)
jocis 1:e6282b645d9b 207 m_leftymode4000 = 1; /* left handed mode */
jocis 1:e6282b645d9b 208 else
jocis 1:e6282b645d9b 209 m_leftymode4000 = 0; /* right handed mode */
jocis 1:e6282b645d9b 210
jocis 1:e6282b645d9b 211 DoChangedButtons();
jocis 1:e6282b645d9b 212 break;
jocis 1:e6282b645d9b 213
jocis 1:e6282b645d9b 214 case 'E': /* Device error */
jocis 1:e6282b645d9b 215 case 'e': /* Device error */
jocis 1:e6282b645d9b 216 //printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1);
jocis 1:e6282b645d9b 217 break;
jocis 1:e6282b645d9b 218
jocis 1:e6282b645d9b 219 case '?': /* Bad command packet */
jocis 1:e6282b645d9b 220 //printk(KERN_ERR "spaceball: Bad command. [%s]\n", spaceball->data + 1);
jocis 1:e6282b645d9b 221 break;
jocis 1:e6282b645d9b 222
jocis 1:e6282b645d9b 223 case 'C': /* Communications mode packet */
jocis 1:e6282b645d9b 224 case 'F': /* Spaceball sensitization packet */
jocis 1:e6282b645d9b 225 case 'P': /* Spaceball update rate packet */
jocis 1:e6282b645d9b 226 case 'M': /* Spaceball movement mode packet */
jocis 1:e6282b645d9b 227 case 'N': /* Null region packet */
jocis 1:e6282b645d9b 228 case '\r': /* carriage return at poweron */
jocis 1:e6282b645d9b 229 case '\v': /* XON at poweron */
jocis 1:e6282b645d9b 230 /* eat and ignore these packets */
jocis 1:e6282b645d9b 231 break;
jocis 1:e6282b645d9b 232
jocis 1:e6282b645d9b 233 case '@': /* Reset packet */
jocis 1:e6282b645d9b 234 case 'z': /* Reset packet */
jocis 1:e6282b645d9b 235 /* if we get a reset packet, we have to re-initialize */
jocis 1:e6282b645d9b 236 /* the device, and assume that its completely schizophrenic */
jocis 1:e6282b645d9b 237 /* at this moment, we must reset it again at this point */
jocis 1:e6282b645d9b 238 m_resetoccured=1;
jocis 1:e6282b645d9b 239 //Init();
jocis 1:e6282b645d9b 240 break;
jocis 1:e6282b645d9b 241
jocis 1:e6282b645d9b 242 case 'b': /* Beep */
jocis 1:e6282b645d9b 243 case 'c': /* */
jocis 1:e6282b645d9b 244 case 'p': /* */
jocis 1:e6282b645d9b 245 case 'm': /* mode changed */
jocis 1:e6282b645d9b 246 case 'n': /* Zero radius */
jocis 1:e6282b645d9b 247 case 'q': /* Sensitivity */
jocis 1:e6282b645d9b 248 case 'v': /* Version number follows */
jocis 1:e6282b645d9b 249 /* eat and ignore these packets */
jocis 1:e6282b645d9b 250 break;
jocis 1:e6282b645d9b 251
jocis 1:e6282b645d9b 252 default:
jocis 2:a7c0fcd157f7 253 //pc.printf("<%s>\r\n",_data);
jocis 1:e6282b645d9b 254 break;
jocis 1:e6282b645d9b 255 }
jocis 1:e6282b645d9b 256 }
jocis 1:e6282b645d9b 257
jocis 1:e6282b645d9b 258 ///////////////////////////////////////////////////////////////////////////////
jocis 1:e6282b645d9b 259 ///////////////////////////////////////////////////////////////////////////////
jocis 1:e6282b645d9b 260 ///////////////////////////////////////////////////////////////////////////////