SHAKE interaction with the Bluetooth SHAKE device


SHAKE will configure, collect and stream data from a SHAKE Bluetooth device.


The SHAKE class handles a number of configuration and data structures through instance methods and variables. See the examples below.


If you haven't used the SHAKE before with SuperCollider, of if you have used it with another example, it may be advisable to rest the settings of the device to the original factory settings:


// see if any SHAKE devices are set-up with your system. If an empty array is returned, 

// you need to set the device up with your Bluetooth set-up assistant*.


a = SHAKE.findSHAKE;


SHAKE.resetToFacSettings(a[0]);


// and, to use this SC class, run this config on the device. 


SHAKE.initForSC(a[0]); //Config for SuperCollider


// otherwise, connect to the SHAKE


z = SHAKE(a[0]); // if you know the address of the SHAKE, you can also enter it here


// MAKE SURE THE SHAKE IS ON!!! Then, connect


z.connect;


// you should see something like this in your post window:


SHAKE SK6 

Copyright 2006 SAMH Engineering Services 

Firmware Revision 2.11

Hardware Revision 1.21

Serial Number SK6-0086

Gyro Module SK6-G01 Installed in Slot 0

No option module detected in Slot 1

$ACK,0002,00

$ACK,0008,00

$ACK,0009,00

$ACK,000A,00

$ACK,000B,00

$ACK,000C,00

$ACK,000D,00

// if you don't, try running the following SC configuration. initConfig sets all data output values 

// to 0. then, close and reopen the connection. See debugging suggestions at the bottom of

// the file


z.initConfig;


// close the connection to the SHAKE

z.close;


Global Methods.

powerAll - power all sensors.

requestSplash - request the initial splash screen

initConfig - set output to ASCII, and zero all output rates.

close - close the SHAKE connection.

sendMsg("String") - send an ASCII string command to the SHAKE. Most valid 

commands are implemented in the methods below.

For other debugging info, see the bottom of the file.

Data Access.


The SuperCollider configuration turns off all data streaming from the device. The user should specify in your code what data you want, and how often. Data is stored in instance variable of the SHAKE, and can be routed to a control bus for use in SynthDefs.


*Componants of the SHAKE can be powered down if they aren't going to be used. This will save battery power.


For all of the following examples, this instance of SHAKE will be used:


a = SHAKE.findSHAKE;

z = SHAKE(a[0]);

// MAKE SURE THE SHAKE IS ON!!! Then, connect

z.connect; // Don't forget to close the SHAKE when finished


Accessing Accelerometer data - methods and controls

accelPower_(bool) - true or false. Turn power on or off to the accelerometer.

accel - the last polled sum of all three axes of the accelerometer.

accelX - the last polled value of the x-axis.

accelY - the last polled value of the y-axis.

accelZ - the last polled value of the z-axis

requestAccel - request a reading of the accelerometer.

setAccelRate(rate) - tell the SHAKE to stream accelerometer data at rate in HZ.

accelToControl(accelXBus, accelYBus, accelZBus, accelBus, speedBus) - route 

accelerometer data out to a control bus. If bus values are nil, they will be allocated 

for you. Individual data streams can also be sent using:

accelXToControl(aBus)

accelYToControl(aBus)

accelZToControl(aBus)

accelSumToControl(aBus)

Individual control busses can be accessed as:

accelXBus

accelYBus

accelZBus

accelBus

calibrateAccel - enter the accelerometer calibration mode. This should be used rarely,

and only if needed, with very flat surfaces, a level and a steady hand. Really.

z.setAccelRate(5);


t = CtkSynthDef(\test, {

Out.ar(0, SinOsc.ar(440, 0, XLine.kr(0.1, 0.0001, 1, doneAction: 2)))

});

z.setAccelTrigger(0.1, {z.accel > 0.1}, {t.new.play});


r.stop;


z.close


z.accelSumToControl;


// poll the accel sum, and Lag it to control amplitude

f = {SinOsc.ar(440, 0, Lag2.kr(In.kr(z.accelBus)).abs * 0.5)}.play(s);

f.free;


z.setAccelRate(0);


Accessing Gyroscope (Angular Rate Sensor) data - methods and controls

gyroPower_(bool) - true or false. Turn power on or off to the gyroscope.

gyroX - the last polled value of the x-axis.

gyroY - the last polled value of the y-axis.

gyroZ - the last polled value of the z-axis.

gyroXSum - a running sum of gyroX values.

gyroYSum - a running sum of gyroY values.

gyroZSum - a running sum of gyroZ values.

zeroGyroXSum - zero out the sum on the x-axis

zeroGyroYSum - zero out the sum on the y-axis

zeroGyroZSum - zero out the sum on the z-axis

requestGyro - request a reading of the gyroscope.

setGyroRate(rate) - tell the SHAKE to stream gyroscope data at rate in HZ.

gyroToControl(gyroXBus, gyroYBus, gyroZBus, gyroXSumBus, gyroYSumBus,

gyroZSumBus) - route gyroscope data out to a control bus. If bus values are nil, 

they will be allocated for you. Individual data streams can also be sent using:

gyroXToControl(aBus)

gyroYToControl(aBus)

gyroZToControl(aBus)

gyroXSumToControl(aBus)

gyroYSumToControl(aBus)

gyroZSumToControl(aBus)

Individual control busses can be accessed as:

gyroXBus

gyroYBus

gyroZBus

gyroXSumBus

gyroYSumBus

gyroZSumBus

calibrateGyro - enter the gyroscope's calibration mode. This should be used rarely,

and only if needed, with very flat surfaces, and a good 45 RPM turntable. Really.



z.setGyroRate(0);


r = Routine.run({

loop({

[z.gyroZ, z.gyroZSum, z.accel].postln;

1.wait;

})

});

r.stop;


z.gyroZSumToControl;

z.zeroGyroZSum;


z.setGyroRate(20);

z.gyroZSumToControl;


z.gyroZSumBus;


f = {GrainIn.ar(2, Impulse.kr(10), 0.05, PinkNoise.ar(0.2), In.kr(z.gyroZSumBus) * 0.5)}.play


f.free


// poll the accel sum, and Lag it to control amplitude

f = {SinOsc.ar(

Lag2.kr(In.kr(z.gyroZSumBus)) * 440 +

SinOsc.ar(Lag2.kr(In.kr(z.gyroYSumBus)) * 400, 0, 

Lag2.kr(In.kr(z.gyroZSumBus) * 400)), 0, 0.4)}.play(s);

f.free;


z.zeroGyroXSum;z.zeroGyroYSum;z.zeroGyroZSum;


z.setGyroRate(0);


Accessing Magnometer data - methods and controls

magPower_(bool) - true or false. Turn power on or off to the magnometer.

mag - the sum of the last polled x, y and z axis values.

magX - the last polled value of the x-axis.

magY - the last polled value of the y-axis.

magZ - the last polled value of the z-axis

requestMag - request a reading of the magnometer.

setMagRate(rate) - tell the SHAKE to stream magnometer data at rate in HZ.

magToControl(xBus, yBus, zBus, magBus) - route magnometer data out

to a control bus. If bus values are nil, they will be allocated for you. Individual data streams

can also be sent using:

magXToControl(aBus)

magYToControl(aBus)

magZToControl(aBus)

magSumToControl(aBus)

Individual control busses can be accessed as:

magXBus

magYBus

magZBus

magBus

calibrateMag - enter the accelerometer calibration mode. This should be used rarely,

and only if needed. See the SHAKE manual for what needs to be done.


Accessing Compass data - methods and controls

compass - the last polled compass reading

requestCompass - request a compass reading

setCompassRate(rate) - tell the SHAKE to stream compass data at rate in HZ

compassToControl(compassBus) - route compass data out

to a control bus. If bus values are nil, they will be allocated for you.

compassBus - returns the control bus number where compass data is written to.


Accessing Capcitive Sensor data - methods and controls

csPower_(bool) - true or false. Turn power on or off to the capacitive sensors.

cs0 - access the proximity data on the capacitive sensor 0 (cs0 - right).

cs1 - access the proximity data on the capacitive sensor 1 (cs1 - left).

requestCs0 - request a reading from cs0.

requestCs1 - request a reading from cs1.

setCsRate(rate) - tell the SHAKE to stream cs data at rate in HZ.

setCs0rate and setCs1Rate can also be set.

csToControl(cs0Bus, cs1Bus) - route cs data out to control busses. If bus values are nil, 

they will be allocated for you. Individual data streams can also be sent using:

cs0ToControl(aBus)

cs1ToControl(aBus)

Individual control busses can be accessed as:

cs0Bus

cs1Bus

s.boot;

z = SHAKE("/dev/tty.SHAKESK6R00SN0086-KC-SPP-1")

z.connect

z.setCs1Rate(20);

z.csToControl;


Routine.run({

loop({

[z.cs0, z.cs1].postln;

0.1.wait;

})

})


f = {SinOsc.ar(440, 0, Lag2.kr(In.kr(z.cs0Bus)) / 30)}.play

f.free;


z.setCs0Rate(0);

z.close


Navigation Switch Functionality

navswitch - the current value of the switch. Up = 1, Down = -1, released = 0, pressed = 2.

navUpAction_(aFunction) - a Function to evaluate when the nav switch is in the up position 

navDownAction_(aFunction) - a Function to evaluate when the nav switch is in the down position

navRelAction_(aFunction) - a Function to evaluate when the nav switch is released

navPressAction_(aFunction) - a Function to evaluate when the nav switch is pressed

navToControl(aBus) -  route nav switch data out to control busses. If bus value is nil, it will

be allocated for you.

Use navBus to access the bus id.

SynthDef(\test, {

Out.ar(0, SinOsc.ar(440, 0, XLine.kr(0.1, 0.0001, 1, doneAction: 2)))

}).load(s);

z.navUpAction_({"It Works!".postln});

z.navPressAction_({

s.sendMsg(\s_new, \test, s.nextNodeID, 0, 1);

});


Vibrotactile Display

vibPower_(bool) - true or false. Turn power on or off to the Vibrotactile Display.

setVibProfile(memSlot, [speed1, dur1], [speed2, dur2], ... [speedN, durN]) -

set up a vibration profile to memSlot. memSlot values should be between 1 and 255.

speed values are between 0 (off) and 1 (full speed). Each dur slot can be up to 2.55 seconds.

vibrate(motor, memSlot) - play the vibration profile in memSlot on motor. motor = 0 indicates the 

built in motor, 1 indicates the left motor on the analog connection, 2 the right. motor defaults

to 0 (built-in).


z.setVibProfile(1, [0.25, 0.5], [0.5, 0.5], [0.25, 0.5], [1.0, 1.0]);

z.vibrate(0, 1);


// close the connection.

z.close;


/*


Bluetooth set-up of the SHAKE on OS X-


Turn the Bluetooth on

Select 'Set up Bluetooth Device'

Step through the assistant - 

type = Any Device

once found - choose Passkey Options, and set it to not use a Passkey


Debugging - SHAKE operates through the SerialPort SC object, and it can sometimes be twitchy.

If the SHAKE doesn't seem to be responding, and if you still have control of the computer:

- recompile the library (this seems to at least break a faulty connection

- try to run SHAKE.initForSC 

- try to run SHAKE.resetToFacSettings, then initForSC again.

- close the connection, and try to reconnect.

- force a disconnect (close off the Bluetooth in the computer, shut off the SHAKE,

and recompile the library, restart in the same order).

- restart the computer and try again to re-connect

- if it still doesn't work... try to connect to the Shake simply as a SerialPort:

e.g:

(

p = SerialPort(

"/dev/tty.SHAKESK6R00SN0086-KC-SPP-1",

crtscts: true,

baudrate: 230400);

);

p.putAll("$WRI,0002,00");

// disable streaming on all channels

p.putAll("$WRI,0008,00");

p.putAll("$WRI,0009,00");

p.putAll("$WRI,000A,00");

p.putAll("$WRI,000B,00");

p.putAll("$WRI,000C,00");

p.putAll("$WRI,000D,00");

p.next

// run this until you get nils or an error

1000.do({p.next.postln})


p.close;



*/