CCGSRobotics/RoboHUD

View on GitHub
App/JS/client.js

Summary

Maintainability
F
3 days
Test Coverage
for (let i = 0; i <= 20; i++) {
  lastVals.push(0);
}

lastVals[10] = 100
/*
var GrabberSlider = document.getElementById("grabberSpeed");
var GrabberOutput = document.getElementById("grabberSpeedDisplay");
// Update the current slider value (each time you drag the slider handle)
GrabberSlider.oninput = function() {
  GrabberOutput.innerHTML = "Grabber Speed: " + this.value + "%";
  moveWheel(11,grabberMultipler * this.value * 1023/100);
}

var WristSlider = document.getElementById("wristPosition");
var WristOutput = document.getElementById("wristPositionDisplay");
// Update the current slider value (each time you drag the slider handle)
WristSlider.oninput = function() {
  WristOutput.innerHTML = "Wrist Position: " + this.value + "%";
  moveJointWithPercentage(10,this.value);
}
*/

function lineToAngle(ctx, x1, y1, length, angle, colour) {

    angle *= Math.PI / 180;

    var x2 = x1 + length * Math.cos(angle),
        y2 = y1 + length * Math.sin(angle);

    ctx.beginPath();
    ctx.strokeStyle = colour;
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.stroke();
    ctx.closePath();

    return {x: x2, y: y2};
}

function drawFlipperLines(ctx) {
  context.beginPath()
  context.font = '30px sans-serif'
  context.fillText('Up', 0, 175)
  context.fillText('Down', 250, 175)
  context.closePath()
  lineToAngle(ctx, 100, 100, 50, 180 * (lastVals[6]/100) + 90, 'Green')
  lineToAngle(ctx, 200, 100, 50, -180 * (lastVals[8]/100) + 90, 'Green')
  lineToAngle(ctx, 100, 250, 50, 180 * (lastVals[5]/100) + 90, 'Red')
  lineToAngle(ctx, 200, 250, 50, -180 * (lastVals[7]/100) + 90, 'Red')
}

var flipperCanvas = document.getElementById('flippers')
var context = flipperCanvas.getContext('2d')

drawFlipperLines(context)
// lineToAngle(context, 50, 50, 25, 45)

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

var lastCameraVals = [0, 0]
var cameraLimits = [90, 180]

// function moveCamera() {
//   var gamepad = navigator.getGamepads()[0];
//   if (gamepad.buttons[leftCameraButton].value > 0 && lastCameraVals[1] + cameraStep <= cameraLimits[1]) {
//     console.log('a')
//     clientSocket.send(`${lastCameraVals[0]},${lastVals[1] + cameraStep}`, 25565, '10.0.0.10');
//     lastVals[1] += cameraStep;
//   } else if (gamepad.buttons[rightCameraButton].value > 0 && lastCameraVals[1] - cameraStep >= 0) {
//     clientSocket.send(`${lastCameraVals[0]},${lastVals[1] - cameraStep}`, 25565, '10.0.0.10');
//     lastVals[1] -= cameraStep;
//   }
// }

var waiter = 10

function updateGrabberState() {
  document.getElementById('grabberPositionDisplay').innerHTML = `Grabber position: ${Math.round((grabberValue/60)*100)}%`;
}
var grabberServos = [true, true, true]
var grabberValues = [0, 0, 0]
async function moveGrabber(multiplier) {
  return new Promise(async function(resolve) {
    var children = document.getElementById('grabberParent').children;
    for (var i = 0; i < children.length; i++) {
      var child = children[i]
      if (child.type == "checkbox" && child.checked) {
        grabberServos[parseInt(child.value) - 1] = true
        grabberValue += (grabberStep * multiplier)
      } else {
        grabberServos[parseInt(child.value) - 1] = false
      }
      // clientSocket.send(`${grabberValue}`, 25565, '10.0.0.10');
    }
    if (grabberServos == [true, true, true]) {
      await sleep(waiter)
      clientSocket.send(`${grabberValue}`, 25565, '10.0.0.10')
    }

    for (var i = 0; i < 3; i++) {
      if (grabberServos[i] == true) {
        await sleep(waiter);
        clientSocket.send(`${i+1}i${grabberValue}`, 25565, '10.0.0.10');
      }
    }
    resolve;
  })
}

// function moveGrabberSlider() {
//   var slider = document.getElementById('grabberPosition');
//   if (canMove) {
//     grabberValue = parseInt(slider.value);
//     console.log(grabberValue, slider)
//     updateGrabberState();
//   }
// }

// document.onkeydown = async function(e) {
//   var key = e.key;
//   if (key == "ArrowLeft") {
//     // sendWheelValue(11, -1024);
//     clientSocket.send('111024', 9999, '10.0.0.10');
//   } else if (key == "ArrowRight") {
//     clientSocket.send('11-1024', 9999, '10.0.0.10');
//   } else if (key == "ArrowDown" && grabberValue > 0) {
//     // grabberValue -= grabberStep;
//     updateGrabberState();
//     await moveGrabber(-1);
//     // clientSocket.send(`${grabberValue}`, 25565, '10.0.0.10');
//   } else if (key == "ArrowUp" && grabberValue < 60) {
//     // grabberValue += grabberStep;
//     updateGrabberState();
//     await moveGrabber(1);
//     // clientSocket.send(`${grabberValue}`, 25565, '10.0.0.10');
//   }
// }

// document.onkeyup = async function(e) {
//   var key = e.key;
//   if (key == "ArrowLeft" || key == "ArrowRight") {
//     clientSocket.send('110', 9999, '10.0.0.10');
//   }
// }

function grabberDirection(G_M) {grabberMultipler = G_M;}

function sendWithCheck(message, port, ip) {
  if (!message.includes('NaN')) {
    clientSocket.send(message, port, ip);
  } else {
    console.log(message);
  }
}
// Tells the server to restart the dynamixels through the relay circuit.
function restart() {sendWithCheck("restart", 9999, '10.0.0.10');}

function softwareResetServos() {sendWithCheck("softwareResetServos", 9999, '10.0.0.10');}

/**
 * Moves any dynamixel that has been assigned jointMode in terms of\
 * the percentage of maximum rotation of the servo
 * @param {!number} ID The ID of the dynamixel to control
 * @param {!number} percentage The percentage out of 100\
 * that you want to move the joint to
 * @example <caption>Moving servo 5 to 50% of its range,\
 * or straight forwards</caption>
 * moveJointWithPercentage(5, 50);
 */

function moveJointWithPercentage(ID, percentage) {
  lastVals[ID] = percentage;
  destination = 1023 + (percentage * 2048) / 100;
  if (ID == 5 || ID == 8) {
    destination = 3071 - (percentage*2048)/100;
  }
  if (ID == 9) {
    destination = (percentage * 2680) / 100;
  }
  if (ID == 10) {
    destination = (percentage * 476) / 100;
  }
  if (ID == 12) {
    destination = (percentage * 1023) / 100
  }
  // console.log(flipperJointLimits[ID])
  // Ensures sent servo destination data fits within their limits.
  if(destination > flipperJointLimits[ID][1]) {destination = flipperJointLimits[ID][1];}
  if(destination < flipperJointLimits[ID][0]) {destination = flipperJointLimits[ID][0];}
  if (ID < 9) {
    sendWithCheck(`0${ID} ${destination} 200`, 9999, '10.0.0.10');
  } else if (ID == 9) {
    sendWithCheck(`09 ${destination} 1024`, 9999, '10.0.0.10');
  } else if (ID == 12 || ID == 13) {
      console.log(destination)
      sendWithCheck(`${ID} ${destination} 100`, 9999, '127.0.0.1');
  } else {
    sendWithCheck(`${ID} ${destination} 200`, 9999, '10.0.0.10');
  }
}

function changeFlipperSelection() {
  if(flipperSelect) {
    flipperDirection.innerHTML = `Flippers: back`
    flipperSelect = false;
  }
  else {
    flipperDirection.innerHTML = `Flippers: front`
    flipperSelect = true;
  }
}

/**
 * Sends a wheel value to the server given an ID and a speed,\
 * providing the instruction has not already been sent
 * @param {!number} dynamixel The ID of the dynamixel you wish to move
 * @param {!number} val The speed at which you wish to move
 */
function sendWheelValue(dynamixel, val) {
  if (!(lastVals[dynamixel] == val)) {
    sendWithCheck(`0${dynamixel}${val}`, 9999, '10.0.0.10');
    lastVals[dynamixel] = val;
  }
}

/**
 * Interprets an action on the controller to pass onto sendWheelValue
 * @param {!number} dynamixel The ID of the dynamixel you wish to move
 * @param {!number} axis The index of the axis on the gamepad to get data from
 * @param {object} gamepad Any gamepad object in the array returned from\
 *  navigator.getGamepads()
 * @param {boolean} sticks True if using sticks, false for triggers
 */
function moveWheel(dynamixel, axis, gamepad, sticks) {
  let val;
  if (sticks) {
    val = Math.round((gamepad.axes[axis] + 1) * 512);
    val = (val - 512) * -2;
  } else {
    val = Math.round((gamepad.buttons[axis].value) * 1024);
  }

  if (val < -1024 || val > 1024) {
    console.error('Controller value is out of bounds! (' + val + ')');
  }

  if (dynamixel == 2 || dynamixel == 4) {
    val = -val;
    val *= multipliers[0][1];
  } else {
    val *= multipliers[1][1];
  }

  // if (-150 <= val >= 150) {
  //   val = 0;
  // }
  sendWheelValue(dynamixel, val);
}

/**
 * Moves the arm joint of a servo if the corresponding button has been pressed
 * @param {!number} dynamixel The ID of the dynamixel you wish to move
 * @param {!number} upButton The index of the button for moving the arm up
 * @param {!number} downButton The index of the button for moving the arm down
 */
function moveArm(dynamixel, upButton, downButton) {
  gamepad = navigator.getGamepads()[0];
  if (gamepad.buttons[upButton].value > 0) {
    if (lastVals[dynamixel] != lastVals[dynamixel]+1 && lastVals[dynamixel] < 100) {
      moveJointWithPercentage(dynamixel, lastVals[dynamixel]+1);
      lastVals[dynamixel] += 1;
    }
  } else if (gamepad.buttons[downButton].value > 0) {
    if (lastVals[dynamixel] != lastVals[dynamixel] - 1 &&
      lastVals[dynamixel] > 0) {
      moveJointWithPercentage(dynamixel, lastVals[dynamixel] - 1);
      lastVals[dynamixel] -= 1;
    }
  }
}

/**
 * Moves the wrist joint of a servo if the corresponding button has been pressed
 * @param {!number} dynamixel The ID of the dynamixel you wish to move
 * @param {!number} upButton The index of the button for moving the arm up
 * @param {!number} downButton The index of the button for moving the arm down
 */
function moveWrist(dynamixel, upButton, downButton) {
  gamepad = navigator.getGamepads()[0];
  if (gamepad.buttons[upButton].value > 0) {
    if (lastVals[dynamixel] < 100) {
      moveJointWithPercentage(dynamixel, lastVals[dynamixel]+1);
      lastVals[dynamixel] += 1;
    }
  } else if (gamepad.buttons[downButton].value > 0) {
    if (lastVals[dynamixel] > 0) {
      moveJointWithPercentage(dynamixel, lastVals[dynamixel] - 1);
      lastVals[dynamixel] -= 1;
    }
  }
}

/**
 * Interprts an action on the controller to pass onto moveJointWithPercentage
 * @param {!number} dynamixel The ID of the dynamixel you wish to move
 * @param {!number} axis The index of the axis on the gamepad to get
 *  postional data from
 * @param {boolean} holdMode [false] If the flipper is moved by clicking
 *  the axis button
 * @param {number} holdButton [0] The index of the button to hold
 */
function moveFlipper(dynamixel, axis) {
  const gamepad = navigator.getGamepads()[0];
  const change = Math.round((gamepad.axes[axis])*5);
  if(flipperSelect && (dynamixel == 5 || dynamixel == 6)) {
    var val = lastVals[dynamixel] + change;
    if(val < 0) {val = 0;}
    else if (val > 100) {val = 100;}
    if (val != lastVals[dynamixel]) {
      lastVals[dynamixel] = val;
      moveJointWithPercentage(dynamixel, val);
    }
  }
  else if(!flipperSelect && (dynamixel == 7 || dynamixel == 8)) {
    var val = lastVals[dynamixel] - change;
    if(val < 0) {val = 0;}
    else if (val > 100) {val = 100;}
    if (val != lastVals[dynamixel]) {
      lastVals[dynamixel] = val;
      moveJointWithPercentage(dynamixel, val);
    }
  }

}

var flipperDirection = document.getElementById('flipperDirection');
var leftWheelDirection = document.getElementById('leftWheelsDirection');
var rightWheelDirection = document.getElementById('rightWheelsDirection');

function centerCamera() {
  clientSocket.send('10 1023 200', 9999, '10.0.0.10')
  lastVals[10] = 1023
  clientSocket.send('12 512 200', 9999, '10.0.0.10')
  lastVals[12] = 512
  clientSocket.send('13 816 200', 9999, '10.0.0.10')
  lastVals[13] = 816
}

function cameraLeft() {
  clientSocket.send('12 0 200', 9999, '10.0.0.10')
  lastVals[12] = 0
}

function cameraRight() {
  clientSocket.send('12 1023 200', 9999, '10.0.0.10')
  lastVals[12] = 1023
}

function panCamera(ID, leftButton, rightButton) {
  var gamepad = navigator.getGamepads()[0];
  if (gamepad.buttons[leftButton].value > 0 && lastVals[ID] + 5 <= flipperJointLimits[ID][1]) {
    console.log(lastVals[ID] + 5)
    moveJointWithPercentage(ID, lastVals[ID] + 5)
    lastVals[ID] += 5
  } else if (gamepad.buttons[rightButton].value > 0 && lastVals[ID] - 5 >= flipperJointLimits[ID][0]) {
    moveJointWithPercentage(ID, lastVals[ID] - 5)
    lastVals[ID] -= 5
  }
}

/**
 * Writes the default values to the server
 */
async function writeDefaultValues() {
  panDirection = panDirectionDefault;
  tiltDirection = tiltDirectionDefault;
  for (let i = 1; i <= 4; i++) {
    sendWheelValue(i, 0);
    lastVals[i] = 0;
  }
  for (let i = 5; i <= 8; i++) {
    moveJointWithPercentage(i, 100);
    lastVals[i] = 100;
  }
  moveJointWithPercentage(9, 0);
  lastVals[9] = 0;

  moveJointWithPercentage(10, 100);
  lastVals[10] = 100;

  centerCamera()

  // moveJointWithPercentage(11, 50);
  // lastVals[11] = 50;

  grabberValue = 0;
  moveGrabber(1);

  flipperDirection.innerHTML = 'Flippers: front';
  leftWheelDirection.innerHTML = 'Left wheels: forwards';
  rightWheelDirection.innerHTML = 'Right wheels: forwards'

  setTimeout(function() {
    clientSocket.send('165,100', 25565, '10.0.0.10')
    lastCameraVals = [165, 100]
  }, 100)
}

/**
 *
 * @param {object} gamepad Any gamepad object in the array
 * returned from navigator.getGamepads()
 * @param {boolean} sticks [false] True if the user controls via sticks,
 * false for triggers
 */
async function pollGamepad(gamepad, sticks = false) {
  gamepad = navigator.getGamepads()[0];

  moveWheel(1, 6, navigator.getGamepads()[0], false);
  moveWheel(3, 6, navigator.getGamepads()[0], false);
  moveWheel(2, 7, navigator.getGamepads()[0], false);
  moveWheel(4, 7, navigator.getGamepads()[0], false);
  moveFlipper(5, 1);
  moveFlipper(7, 1);
  moveFlipper(6, 3);
  moveFlipper(8, 3);
  moveArm(9, 3, 2);
  moveWrist(10, 1, 0);
  panCamera(12, 14, 15)
  // moveJointWithPercentage(11,50);

  // moveCamera()
  context.beginPath();
  context.clearRect(0, 0, 100000000000, 100000000000000);
  context.stroke();
  context.closePath();
  drawFlipperLines(context);
}

function moveStraight() {
  clientSocket.send('011024', 9999, '10.0.0.10')
  clientSocket.send('031024', 9999, '10.0.0.10')
  clientSocket.send('02-1024', 9999, '10.0.0.10')
  clientSocket.send('04-1024', 9999, '10.0.0.10')
}

function stop() {
  clientSocket.send('010', 9999, '10.0.0.10')
  clientSocket.send('030', 9999, '10.0.0.10')
  clientSocket.send('020', 9999, '10.0.0.10')
  clientSocket.send('040', 9999, '10.0.0.10')
}
// client.connect(5000, '10.0.0.10', function() {
//   console.log("Connected to server interface");
// })
//
// function writeToServer(data) {
//   client.write(data);
//   console.log(`Wrote '${data}' to server`);
// }
let gamepadInterval;
console.log(lastVals)
writeDefaultValues();
window.addEventListener('gamepadconnected', function(event) {
  gamepadInterval = setInterval(() => {
    const gamepad = navigator.getGamepads()[0];
    if (gamepad.buttons[9].value > 0) {
      writeDefaultValues();
      multipliers = [[false, 1], [false, 1]];
    }

    pollGamepad(event.gamepad, 40, false);

    if (gamepad.buttons[5].pressed && !multipliers[0][0]) {
      multipliers[0][1] *= -1;
      multipliers[0][0] = true;
      if (multipliers[0][1] == 1) {
        rightWheelDirection.innerHTML = `Right wheels: forwards`;
      } else {
        rightWheelDirection.innerHTML = `Right wheels: backwards`;
      }
    } else if(!gamepad.buttons[5].pressed){
      multipliers[0][0] = false;
    }
    

    if (gamepad.buttons[4].pressed && !multipliers[1][0]) {
      multipliers[1][1] *= -1;
      multipliers[1][0] = true;
      if (multipliers[1][1] == 1) {
        leftWheelDirection.innerHTML = `Left wheels: forwards`;
      } else {
        leftWheelDirection.innerHTML = `Left wheels: backwards`;
      }
    } else if(!gamepad.buttons[4].pressed) {
      multipliers[1][0] = false;
      // leftWheelDirection.innerHTML = `Left wheels: backwards`;
    }

    if (gamepad.buttons[16].pressed) {
      restart();
      //softwareResetServos();
    }
    if (gamepad.buttons[8].pressed && !b_button_state) {
      b_button_state = true;

      changeFlipperSelection();
    }
    // if (gamepad.buttons[15].pressed) {
    //   lastVals[11] = lastVals[11] - 10

    //   moveJointWithPercentage(11,lastVals[11]);
    // }
    // if (gamepad.buttons[14].pressed) {
    //   lastVals[11] = lastVals[11] - 10

    //   moveJointWithPercentage(11,lastVals[11]);
    // }

    else if(!gamepad.buttons[8].pressed) {
      b_button_state = false;
    }
  }, 50);
});
window.addEventListener('gamepaddisconnected', function(event) {
  clearInterval(gamepadInterval);
});