From feea7df3eb3c01bfa9a615c019528f956b3762a1 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 5 Feb 2024 10:33:20 +0000 Subject: [PATCH] legoremote 0.02: Add more control styles, and linear control of motors --- apps/legoremote/ChangeLog | 1 + apps/legoremote/README.md | 17 +++- apps/legoremote/app.js | 171 ++++++++++++++++++++++++---------- apps/legoremote/metadata.json | 2 +- 4 files changed, 139 insertions(+), 52 deletions(-) diff --git a/apps/legoremote/ChangeLog b/apps/legoremote/ChangeLog index 5560f00bc..b86638553 100644 --- a/apps/legoremote/ChangeLog +++ b/apps/legoremote/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Add more control styles diff --git a/apps/legoremote/README.md b/apps/legoremote/README.md index a95b7b154..b6cd82979 100644 --- a/apps/legoremote/README.md +++ b/apps/legoremote/README.md @@ -10,8 +10,21 @@ in the future this app will be able to support other types of remote (see below) ## Usage -Run the app, and ensure you're not connected to your watch via Bluetooth -(a warning will pop up if so). +Run the app, then choose the type of controls you want and ensure you're not connected +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. diff --git a/apps/legoremote/app.js b/apps/legoremote/app.js index 1c76a54a8..40935cabf 100644 --- a/apps/legoremote/app.js +++ b/apps/legoremote/app.js @@ -1,5 +1,4 @@ var lego = require("mouldking"); -lego.start(); E.on('kill', () => { // return to normal Bluetooth advertising NRF.setAdvertising({},{showName:true}); @@ -12,59 +11,133 @@ var controlState = ""; Bangle.loadWidgets(); Bangle.drawWidgets(); 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() { - g.reset().clearRect(R); - var c, ninety = Math.PI/2; - var colOn = "#f00", colOff = g.theme.fg; - c = getBoxCoords(1.5, 0.5); - g.setColor(controlState=="up"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:0}); - 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); +function startLegoButtons(controls) { + // 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 + }; } -} -draw(); -NRF.on('connect', draw); -NRF.on('disconnect', draw); -function setControlState(s) { - controlState = s; - var c = {}; - var speed = 3; - if (s=="up") c={a:-speed,b:-speed}; - if (s=="down") c={a:speed,b:speed}; - if (s=="left") c={a:speed,b:-speed}; - if (s=="right") c={a:-speed,b:speed}; + function draw() { + g.reset().clearRect(R); + var c, ninety = Math.PI/2; + var colOn = "#f00", colOff = g.theme.fg; + c = getBoxCoords(1.5, 0.5); + g.setColor(controlState=="up"?colOn:colOff).drawImage(arrowIcon,c.x,c.y,{rotate:0}); + 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); + } + 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(); - lego.set(c); + NRF.on('connect', draw); + NRF.on('disconnect', draw); } -Bangle.on('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==1) setControlState("up"); - } else if (y==1) { - if (x==0) setControlState("left"); - if (x==1) setControlState("down"); - if (x==2) setControlState("right"); +function startLegoLinear() { + var mx = R.x+R.w/2; + var my = R.y+R.h/2; + var x=0,y=0; + var scale = 10; + + function draw() { + g.reset().clearRect(R); + for (var i=3;i<60;i+=10) + g.drawCircle(mx,my,i); + g.setColor("#F00"); + var px = E.clip(mx + x*scale, R.x+20, R.x2-20); + 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), }); diff --git a/apps/legoremote/metadata.json b/apps/legoremote/metadata.json index c86251860..8fe4c4b44 100644 --- a/apps/legoremote/metadata.json +++ b/apps/legoremote/metadata.json @@ -1,7 +1,7 @@ { "id": "legoremote", "name": "LEGO Remote control", "shortName":"LEGO Remote", - "version":"0.01", + "version":"0.02", "description": "Use your Bangle.js to control LEGO models. See the README for compatibility", "icon": "app.png", "tags": "toy,lego,bluetooth",