Skip to content

Commit

Permalink
connection improvements, adding rotate by degrees block, improving tu…
Browse files Browse the repository at this point in the history
…rning command, other improvements
  • Loading branch information
kaspesla committed Nov 9, 2015
1 parent bb30295 commit e8f84e4
Show file tree
Hide file tree
Showing 2 changed files with 1,086 additions and 53 deletions.
200 changes: 147 additions & 53 deletions ev3_scratch.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var DEBUG_NO_EV3 = false;
var theEV3Device = theEV3Device || null;
var EV3ScratchAlreadyLoaded = EV3ScratchAlreadyLoaded || false;
var EV3Connected = EV3Connected || false;
var potentialEV3Devices = potentialEV3Devices || [];

(function(ext) {
// Cleanup function when the extension is unloaded
Expand All @@ -39,9 +40,8 @@ var EV3Connected = EV3Connected || false;

var connecting = false;
var notifyConnection = false;

var potentialDevices = []; // copy of the list
var warnedAboutBattery = false;
var potentialDevices = [];
var deviceTimeout = 0;

ext._deviceConnected = function(dev)
Expand All @@ -59,12 +59,20 @@ var EV3Connected = EV3Connected || false;
if ((dev.id.indexOf('/dev/tty.serialBrick') === 0 && dev.id.indexOf('-SerialPort') != -1) || dev.id.indexOf('COM') === 0)
{

if (potentialDevices.filter(function(e) { return e.id == dev.id; }).length == 0) {
potentialDevices.push(dev); }
if (potentialEV3Devices.filter(function(e) { return e.id == dev.id; }).length == 0) {
potentialEV3Devices.push(dev); }

if (!deviceTimeout)
deviceTimeout = setTimeout(tryNextDevice, 1000);
deviceTimeout = setTimeout(tryAllDevices, 1000);
}
};

function tryAllDevices()
{
potentialDevices = potentialEV3Devices.slice(0);
// start recursive loop
tryNextDevice();
}

var poller = null;
var pingTimeout = null;
Expand All @@ -87,7 +95,7 @@ var EV3Connected = EV3Connected || false;

var counter = 0;

function reconnect()
function tryToConnect()
{
clearSensorStatuses();
counter = 0;
Expand Down Expand Up @@ -119,8 +127,16 @@ function startupBatteryCheckCallback(result)
warnedAboutBattery = true;
}

// no watchdog right now. reconnection is too flakey so there is no point
// setupWatchdog();
setupWatchdog();

if (deferredCommandArray)
{
var tempCommand = deferredCommandArray;
deferredCommandArray = null;
window.setTimeout(function() {
sendCommand(tempCommand);
}, 2500);
}
}

function setupWatchdog()
Expand Down Expand Up @@ -149,7 +165,7 @@ function pingTimeOutCallback()

EV3Connected = false;

alert("The connection to the brick was lost. Check your brick and refresh the page to reconnect. (Don't forget to save your project first!)");
// alert("The connection to the brick was lost. Check your brick and refresh the page to reconnect. (Don't forget to save your project first!)");
/* if (r == true) {
reconnect();
} else {
Expand All @@ -168,13 +184,16 @@ function connectionTimeOutCallback()

if (potentialDevices.length == 0)
{
alert("Failed to connect to a brick.\n\nMake sure your brick is:\n 1) powered on with Bluetooth On\n 2) named starting with serial (if on a Mac)\n 3) paired with this computer\n 4) the iPhone/iPad/iPod check box is NOT checked\n 5) Do not start a connection to or from the brick in any other way. Let the Scratch plug-in handle it!\n\nand then try reloading the webpage.");
console.log(timeStamp() + ": Tried all devices with no luck.");

// alert("Failed to connect to a brick.\n\nMake sure your brick is:\n 1) powered on with Bluetooth On\n 2) named starting with serial (if on a Mac)\n 3) paired with this computer\n 4) the iPhone/iPad/iPod check box is NOT checked\n 5) Do not start a connection to or from the brick in any other way. Let the Scratch plug-in handle it!\n\nand then try reloading the webpage.");
/* if (r == true) {
reconnect();
} else {
// do nothing
}
*/
theEV3Device = null;
}
else
{
Expand Down Expand Up @@ -234,7 +253,7 @@ function playStartUpTones()

if (!DEBUG_NO_EV3)
{
reconnect();
tryToConnect();
}
}

Expand Down Expand Up @@ -447,19 +466,21 @@ function playStartUpTones()
// int bytes using weird serialization method
function getPackedOutputHexString(num, lc)
{
// f-ed up nonsensical unsigned bit packing. see cOutputPackParam in c_output-c in EV3 firmware
var a = new ArrayBuffer(2);
// nonsensical unsigned byte packing. see cOutputPackParam in c_output-c in EV3 firmware
var a = new ArrayBuffer(4);
var sarr = new Int8Array(a);
var uarr = new Uint8Array(a);

sarr[0] = num & 0x000000FF;
sarr[1] = (num >> 8) & 0x000000FF;
sarr[2] = (num >> 16) & 0x000000FF;
sarr[3] = (num >> 24) & 0x000000FF;

if (lc == 0)
{
var powerbits = uarr[0];
powerbits &= 0x0000003F;
return hexcouplet(powerbits);
var bits = uarr[0];
bits &= 0x0000003F;
return hexcouplet(bits);
}
else if (lc == 1)
{
Expand All @@ -469,7 +490,11 @@ function playStartUpTones()
{
return "82" + hexcouplet(uarr[0]) + hexcouplet(uarr[1]);
}

else if (lc == 3)
{
return "83" + hexcouplet(uarr[0]) + hexcouplet(uarr[1]) + hexcouplet(uarr[2]) + hexcouplet(uarr[3]);
}

return "00";
}

Expand All @@ -481,6 +506,7 @@ function playStartUpTones()
var SET_MOTOR_SPEED = "A400";
var SET_MOTOR_STOP = "A300";
var SET_MOTOR_START = "A600";
var SET_MOTOR_STEP_SPEED = "AC00";
var NOOP = "0201";
var PLAYTONE = "9401";
var INPUT_DEVICE_READY_SI = "991D";
Expand Down Expand Up @@ -518,34 +544,98 @@ function playStartUpTones()
var COLOR_RAW_RGB = "04";
var READ_FROM_MOTOR = "FOOBAR";



var deferredCommandArray = null;

function sendCommand(commandArray)
{
if ((EV3Connected || connecting) && theEV3Device)
{
theEV3Device.send(commandArray.buffer);
}
else
{
deferredCommandArray = commandArray;
if (theEV3Device && !connecting)
{
tryToConnect(); // try to connect
}
else if (!connecting)
{
tryAllDevices(); // try device list again
}

}
}

ext.allMotorsOn = function(which, power)
ext.startMotors = function(which, speed)
{
clearDriveTimer();

console.log("motor " + which + " power: " + power);
console.log("motor " + which + " speed: " + speed);

motor(which, power);
motor(which, speed);
}

function motor(which, power)
{
var motorBitField = getMotorBitsHexString(which);

function capSpeed(speed)
{
if (speed > 100) { speed = 100; }
if (speed < -100) { speed = -100; }
return speed;
}

ext.motorDegrees = function(which, speed, degrees, howStop)
{
speed = capSpeed(speed);

var powerBits = getPackedOutputHexString(power, 1);
var motorBitField = getMotorBitsHexString(which);
var speedBits = getPackedOutputHexString(speed, 1);
var stepRampUpBits = getPackedOutputHexString(0, 3);
var stepConstantBits = getPackedOutputHexString(degrees, 3);
var stepRampDownBits = getPackedOutputHexString(0, 3);
var howHex = howStopHex(howStop);

var motorsCommand = createMessage(DIRECT_COMMAND_PREFIX + SET_MOTOR_STEP_SPEED + motorBitField + speedBits
+ stepRampUpBits + stepConstantBits + stepRampDownBits + howHex
+ SET_MOTOR_START + motorBitField);

sendCommand(motorsCommand);
}

function motor(which, speed)
{
speed = capSpeed(speed);
var motorBitField = getMotorBitsHexString(which);

var speedBits = getPackedOutputHexString(speed, 1);

var motorsOnCommand = createMessage(DIRECT_COMMAND_PREFIX + SET_MOTOR_SPEED + motorBitField + speedBits + SET_MOTOR_START + motorBitField);

sendCommand(motorsOnCommand);
}

var motorsOnCommand = createMessage(DIRECT_COMMAND_PREFIX + SET_MOTOR_SPEED + motorBitField + powerBits + SET_MOTOR_START + motorBitField);

sendCommand(motorsOnCommand);
function motor2(which, speed)
{
speed = capSpeed(speed);
var p = which.split("+");

var motorBitField1 = getMotorBitsHexString(p[0]);
var motorBitField2 = getMotorBitsHexString(p[1]);
var motorBitField = getMotorBitsHexString(which);

var speedBits1 = getPackedOutputHexString(speed, 1);
var speedBits2 = getPackedOutputHexString(speed * -1, 1);

var motorsOnCommand = createMessage(DIRECT_COMMAND_PREFIX
+ SET_MOTOR_SPEED + motorBitField1 + speedBits1
+ SET_MOTOR_SPEED + motorBitField2 + speedBits2

+ SET_MOTOR_START + motorBitField);

sendCommand(motorsOnCommand);
}


var frequencies = { "C4" : 262, "D4" : 294, "E4" : 330, "F4" : 349, "G4" : 392, "A4" : 440, "B4" : 494, "C5" : 523, "D5" : 587, "E5" : 659, "F5" : 698, "G5" : 784, "A5" : 880, "B5" : 988, "C6" : 1047, "D6" : 1175, "E6" : 1319, "F6" : 1397, "G6" : 1568, "A6" : 1760, "B6" : 1976, "C#4" : 277, "D#4" : 311, "F#4" : 370, "G#4" : 415, "A#4" : 466, "C#5" : 554, "D#5" : 622, "F#5" : 740, "G#5" : 831, "A#5" : 932, "C#6" : 1109, "D#6" : 1245, "F#6" : 1480, "G#6" : 1661, "A#6" : 1865 };

var colors = [ "none", "black", "blue", "green", "yellow", "red", "white"];
Expand Down Expand Up @@ -624,15 +714,21 @@ function playFreqM2M(freq, duration)
var driveTimer = 0;
driveCallback = 0;

function howStopHex(how)
{
if (how == 'break')
return '01';
else
return '00';
}

function motorsStop(how)
{
console.log("motorsStop");

var motorBitField = getMotorBitsHexString("all");

var howHex = '00';
if (how == 'break')
howHex = '01';
var howHex = howStopHex(how);

var motorsOffCommand = createMessage(DIRECT_COMMAND_PREFIX + SET_MOTOR_STOP + motorBitField + howHex);

Expand All @@ -647,29 +743,23 @@ function playFreqM2M(freq, duration)
ext.steeringControl = function(ports, what, duration, callback)
{
clearDriveTimer();
var defaultPower = 50;
var defaultSpeed = 50;
if (what == 'forward')
{
motor(ports, defaultPower);
motor(ports, defaultSpeed);
}
else if (what == 'reverse')
{
motor(ports, -1 * defaultPower);
}
else
{
var p = ports.split("+");
if (what == 'left')
{
motor(p[0], -1 * defaultPower);
motor(p[1], defaultPower);
}
else if (what == 'right')
{
motor(p[1], -1 * defaultPower);
motor(p[0], defaultPower);
}
motor(ports, -1 * defaultSpeed);
}
else if (what == 'right')
{
motor2(ports, defaultSpeed);
}
else if (what == 'left')
{
motor2(ports, -1 * defaultSpeed);
}
driveCallback = callback;
driveTimer = window.setTimeout(function()
{
Expand Down Expand Up @@ -881,7 +971,7 @@ function playFreqM2M(freq, duration)

ext.reconnectToDevice = function()
{
reconnect();
tryAllDevices();
}

function UIRead(port, subtype)
Expand All @@ -898,15 +988,16 @@ function playFreqM2M(freq, duration)
var descriptor = {
blocks: [
['w', 'drive %m.dualMotors %m.turnStyle %n seconds', 'steeringControl', 'B+C', 'forward', 3],
[' ', 'start motor %m.whichMotorPort speed %n', 'allMotorsOn', 'B+C', 100],
[' ', 'start motor %m.whichMotorPort speed %n', 'startMotors', 'B+C', 100],
[' ', 'rotate motor %m.whichMotorPort speed %n by %n degrees then %m.breakCoast', 'motorDegrees', 'A', 100, 360, 'break'],
[' ', 'stop all motors %m.breakCoast', 'allMotorsOff', 'break'],
['h', 'when button pressed on port %m.whichInputPort', 'whenButtonPressed','1'],
['h', 'when IR remote %m.buttons pressed port %m.whichInputPort', 'whenRemoteButtonPressed','Top Left', '1'],
['R', 'button pressed %m.whichInputPort', 'readTouchSensorPort', '1'],
['w', 'play note %m.note duration %n ms', 'playTone', 'C5', 500],
['w', 'play frequency %n duration %n ms', 'playFreq', '262', 500],
['R', 'light sensor %m.whichInputPort %m.lightSensorMode', 'readColorSensorPort', '1', 'color'],
// ['w', 'wait until light sensor %m.whichInputPort detects black line', 'waitUntilDarkLinePort', '1'],
// ['w', 'wait until light sensor %m.whichInputPort detects black line', 'waitUntilDarkLinePort', '1'],
['R', 'measure distance %m.whichInputPort', 'readDistanceSensorPort', '1'],
['R', 'remote button %m.whichInputPort', 'readRemoteButtonPort', '1'],
// ['R', 'gyro %m.gyroMode %m.whichInputPort', 'readGyroPort', 'angle', '1'],
Expand All @@ -931,6 +1022,9 @@ function playFreqM2M(freq, duration)
};

var serial_info = {type: 'serial'};

// should we even call register again if already loaded? seems to work.

ScratchExtensions.register('EV3 Control', descriptor, ext, serial_info);
console.log("EV3ScratchAlreadyLoaded: " + EV3ScratchAlreadyLoaded);
EV3ScratchAlreadyLoaded = true;
Expand Down
Loading

0 comments on commit e8f84e4

Please sign in to comment.