legoremote 0.02: Add more control styles, and linear control of motors

pull/3176/head
Gordon Williams 2024-02-05 10:33:20 +00:00
parent 69071891f1
commit feea7df3eb
4 changed files with 139 additions and 52 deletions

View File

@ -1 +1,2 @@
0.01: New App! 0.01: New App!
0.02: Add more control styles

View File

@ -10,8 +10,21 @@ in the future this app will be able to support other types of remote (see below)
## Usage ## Usage
Run the app, and ensure you're not connected to your watch via Bluetooth Run the app, then choose the type of controls you want and ensure you're not connected
(a warning will pop up if so). to your watch via Bluetooth (a warning will pop up if so).
Linear mode controls A/B axes individually, and allows you to vary the speed of the
motors based on the distance you drag from the centre. Other modes just use on/off
buttons.
| Mode | up | down | left | right |
|------------|------|------|------|-------|
| **Linear** | +A | -A | -B | +B |
| **Normal** | +A | -A | -B | +B |
| **Tank** | -A+B | +A-B | +A+B | -A-B |
| **Merged** | -A-B | +A+B | +A-B | -A+B |
In all cases pressing the C/D buttons will turn on C/D outputs
Now press the arrow keys on the screen to control the robot. Now press the arrow keys on the screen to control the robot.

View File

@ -1,5 +1,4 @@
var lego = require("mouldking"); var lego = require("mouldking");
lego.start();
E.on('kill', () => { E.on('kill', () => {
// return to normal Bluetooth advertising // return to normal Bluetooth advertising
NRF.setAdvertising({},{showName:true}); NRF.setAdvertising({},{showName:true});
@ -12,59 +11,133 @@ var controlState = "";
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
var R = Bangle.appRect; var R = Bangle.appRect;
// we'll divide up into 3x3
function getBoxCoords(x,y) {
return {
x : R.x + R.w*x/3,
y : R.y + R.h*y/3
};
}
function draw() { function startLegoButtons(controls) {
g.reset().clearRect(R); // we'll divide up into 3x3
var c, ninety = Math.PI/2; function getBoxCoords(x,y) {
var colOn = "#f00", colOff = g.theme.fg; return {
c = getBoxCoords(1.5, 0.5); x : R.x + R.w*x/3,
g.setColor(controlState=="up"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:0}); y : R.y + R.h*y/3
c = getBoxCoords(2.5, 1.5); };
g.setColor(controlState=="right"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:ninety});
c = getBoxCoords(0.5, 1.5);
g.setColor(controlState=="left"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:-ninety});
c = getBoxCoords(1.5, 1.5);
g.setColor(controlState=="down"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:ninety*2});
if (NRF.getSecurityStatus().connected) {
c = getBoxCoords(1.5, 2.5);
g.setFontAlign(0,0).setFont("6x8").drawString("WARNING:\nBluetooth Connected\nYou must disconnect\nbefore LEGO will work",c.x,c.y);
} }
}
draw();
NRF.on('connect', draw);
NRF.on('disconnect', draw);
function setControlState(s) { function draw() {
controlState = s; g.reset().clearRect(R);
var c = {}; var c, ninety = Math.PI/2;
var speed = 3; var colOn = "#f00", colOff = g.theme.fg;
if (s=="up") c={a:-speed,b:-speed}; c = getBoxCoords(1.5, 0.5);
if (s=="down") c={a:speed,b:speed}; g.setColor(controlState=="up"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:0});
if (s=="left") c={a:speed,b:-speed}; c = getBoxCoords(2.5, 1.5);
if (s=="right") c={a:-speed,b:speed}; g.setColor(controlState=="right"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:ninety});
c = getBoxCoords(0.5, 1.5);
g.setColor(controlState=="left"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:-ninety});
c = getBoxCoords(1.5, 1.5);
g.setColor(controlState=="down"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:ninety*2});
if (NRF.getSecurityStatus().connected) {
c = getBoxCoords(1.5, 2.5);
g.setFontAlign(0,0).setFont("6x8").drawString("WARNING:\nBluetooth Connected\nYou must disconnect\nbefore LEGO will work",c.x,c.y);
}
g.setFont("6x8:3").setFontAlign(0,0);
c = getBoxCoords(0.5, 0.5);
g.setColor(controlState=="c"?colOn:colOff).drawString("C",c.x,c.y);
c = getBoxCoords(2.5, 0.5);
g.setColor(controlState=="d"?colOn:colOff).drawString("D",c.x,c.y);
}
function setControlState(s) {
controlState = s;
var c = {};
if (s in controls)
c = controls[s];
draw();
lego.set(c);
}
lego.start();
Bangle.setUI({mode:"custom", drag : e => {
var x = Math.floor(E.clip((e.x - R.x) * 3 / R.w,0,2.99));
var y = Math.floor(E.clip((e.y - R.y) * 3 / R.h,0,2.99));
if (!e.b) {
setControlState("");
return;
}
if (y==0) { // top row
if (x==0) setControlState("c");
if (x==1) setControlState("up");
if (x==2) setControlState("d");
} else if (y==1) {
if (x==0) setControlState("left");
if (x==1) setControlState("down");
if (x==2) setControlState("right");
}
}});
draw(); draw();
lego.set(c); NRF.on('connect', draw);
NRF.on('disconnect', draw);
} }
Bangle.on('drag',e => { function startLegoLinear() {
var x = Math.floor(E.clip((e.x - R.x) * 3 / R.w,0,2.99)); var mx = R.x+R.w/2;
var y = Math.floor(E.clip((e.y - R.y) * 3 / R.h,0,2.99)); var my = R.y+R.h/2;
if (!e.b) { var x=0,y=0;
setControlState(""); var scale = 10;
return;
} function draw() {
if (y==0) { // top row g.reset().clearRect(R);
if (x==1) setControlState("up"); for (var i=3;i<60;i+=10)
} else if (y==1) { g.drawCircle(mx,my,i);
if (x==0) setControlState("left"); g.setColor("#F00");
if (x==1) setControlState("down"); var px = E.clip(mx + x*scale, R.x+20, R.x2-20);
if (x==2) setControlState("right"); var py = E.clip(my + y*scale, R.y+20, R.y2-20);
g.fillCircle(px, py, 20);
} }
lego.start();
Bangle.setUI({mode:"custom", drag : e => {
x = Math.round((e.x - mx) / scale);
y = Math.round((e.y - my) / scale);
if (!e.b) {
x=0; y=0;
}
lego.set({a:x, b:y});
draw();
}});
draw();
NRF.on('connect', draw);
NRF.on('disconnect', draw);
}
// Mappings of button to output
const CONTROLS = {
normal : {
up : {a: 7,b: 0},
down : {a:-7,b: 0},
left : {a: 0,b:-7},
right: {a: 0,b: 7},
c : {c:7},
d : {d:7}
}, tank : {
up : {a:-7,b:7},
down : {a: 7,b:-7},
left : {a: 7,b:7},
right: {a:-7,b:-7},
c : {c:7},
d : {d:7}
}, merged : {
up : {a: 7,b: 7},
down : {a:-7,b:-7},
left : {a: 7,b:-7},
right: {a:-7,b: 7},
c : {c:7},
d : {d:7}
}
};
E.showMenu({ "" : {title:"LEGO Remote", back:()=>load()},
"Linear" : () => startLegoLinear(),
"Normal" : () => startLego(CONTROLS.normal),
"Tank" : () => startLego(CONTROLS.tank),
"Marged" : () => startLego(CONTROLS.merged),
}); });

View File

@ -1,7 +1,7 @@
{ "id": "legoremote", { "id": "legoremote",
"name": "LEGO Remote control", "name": "LEGO Remote control",
"shortName":"LEGO Remote", "shortName":"LEGO Remote",
"version":"0.01", "version":"0.02",
"description": "Use your Bangle.js to control LEGO models. See the README for compatibility", "description": "Use your Bangle.js to control LEGO models. See the README for compatibility",
"icon": "app.png", "icon": "app.png",
"tags": "toy,lego,bluetooth", "tags": "toy,lego,bluetooth",