diff --git a/curveEditor.js b/curveEditor.js index b84c9c1..65ea8fc 100644 --- a/curveEditor.js +++ b/curveEditor.js @@ -143,7 +143,7 @@ export class CurveEditor { endPoint: { x: this.timelineLength * this.pixelsPerSecond, y: this.canvas.height / 2 } } ]); - console.log("TL LENGTH: " + this.timelineLength); + //console.log("TL LENGTH: " + this.timelineLength); this.curveSets[motorID] = this.curves; } diff --git a/feetechDefinitions.js b/feetechDefinitions.js index c8a8bef..8bd7669 100644 --- a/feetechDefinitions.js +++ b/feetechDefinitions.js @@ -31,7 +31,7 @@ export class ServoMotor { this.CURRENT_CURRENT = (payload[30] << 8) | payload[31]; this.VOLTAGE = payload[32]; } else { - // Simplified constructor + // Simplified constructor used by robot config loader this.CHANNEL = arg1; this.ID = arg2; @@ -44,7 +44,7 @@ export class ServoMotor { // Takes Motor object and updates simulated value, returns packet for real device -export function writeData(motor, key) { +export function writeData(targetID, motor, key) { const entry = DataMap[key]; if (!entry) { throw new Error(`Invalid data key: ${key}`); @@ -68,7 +68,7 @@ export function writeData(motor, key) { } } - const packet = [motor.CHANNEL, motor.ID, address, length]; // channel, id, address, value + const packet = [motor.CHANNEL, targetID, address, length]; // channel, id, address, value if (length === 2) { packet.push(value & 0xFF); diff --git a/nodeeditor/NodeEditor.js b/nodeeditor/NodeEditor.js index 29f1b79..9a52206 100644 --- a/nodeeditor/NodeEditor.js +++ b/nodeeditor/NodeEditor.js @@ -27,8 +27,8 @@ export class NodeEditor { } generateDefaultNodes(curveSets, motorIDs) { - console.log("Generating Default Nodes"); - console.log(curveSets, motorIDs); + //console.log("Generating Default Nodes"); + //console.log(curveSets, motorIDs); for (var i = 0; i < motorIDs.length; i++) { let inputNode = this.addCurveNode(200, 20 + i * 140, "Curve", motorIDs[i]); diff --git a/robot.js b/robot.js index 9b2a614..31397b4 100644 --- a/robot.js +++ b/robot.js @@ -1,4 +1,4 @@ -import { ServoMotor } from './feetechDefinitions.js'; +import { getModelType, ServoMotor } from './feetechDefinitions.js'; export class Robot { constructor(name, firmwareVersionId) { @@ -6,7 +6,8 @@ export class Robot { this.firmwareVersion = { major: 0, minor: 0 }; // Map of position ID → ServoMotor - this.positionMap = new Map(); + //this.positionMap = new Map(); + this.motors = []; } // Assign a motor to a position @@ -14,39 +15,38 @@ export class Robot { if (!(motor instanceof ServoMotor)) { throw new Error('Assigned motor must be a ServoMotor instance'); } - this.positionMap.set(positionId, motor); + //this.positionMap.set(positionId, motor); + this.motors.push(motor); } - // Get motor assigned to a position - getMotor(positionId) { - return this.positionMap.get(positionId); + getMotor(motorID) { + for (let i = 0; i < this.motors.length; i++) { + console.log(motorID, this.motors[i].ID); + if (String(this.motors[i].ID) === String(motorID)) { + return this.motors[i]; + } } + return null; +} + // Remove motor from a position - removeMotor(positionId) { - this.positionMap.delete(positionId); + removeMotor(motorID) { + this.motors = this.motors.filter(motor => motor.ID !== motorID); } - // Get all position assignments - getAllAssignments() { - const assignments = []; - for (const [position, motor] of this.positionMap.entries()) { - assignments.push({ position, motor }); - } - return assignments; - } // Optional: Find position by motor ID - findPositionByMotorId(id) { - for (const [position, motor] of this.positionMap.entries()) { - if (motor.ID === id) return position; - } - return null; - } + // findPositionByMotorId(id) { + // for (const [position, motor] of this.positionMap.entries()) { + // if (motor.ID === id) return position; + // } + // return null; + // } static fromBytes(bytes) { console.log("Loading Robot from:"); - console.log(bytes); + //console.log(bytes); const data = bytes instanceof Uint8Array ? bytes : Uint8Array.from(bytes); let offset = 0; @@ -73,8 +73,12 @@ export class Robot { const name = String.fromCharCode(...data.slice(offset, offset + nameLen)); offset += nameLen; + const modelMajor = data[offset++]; + const modelMinor = data[offset++]; + const modelType = getModelType(modelMajor, modelMinor); + const position = (data[offset++] << 8) | data[offset++]; - const motor = new ServoMotor(0, motorID, null, name); + const motor = new ServoMotor(0, motorID, modelType, name); robot.assignMotor(motorID, motor); // motorID used as position ID } diff --git a/script.js b/script.js index 4135df1..4c86bb8 100644 --- a/script.js +++ b/script.js @@ -34,7 +34,42 @@ window.onload = () => { - const dialColors = ['red', 'green', 'blue', 'orange', 'purple']; + const dialColors = [ + '#F50057', // Raspberry + '#6200EA', // Deep Violet + '#FFB400', // Bright Amber + '#2979FF', // Royal Blue + '#FF5252', // Coral Red + '#00C853', // Vivid Green + '#FF80AB', // Bubblegum + '#00B8D4', // Sky Cyan + '#FF9100', // Neon Orange + '#651FFF', // Electric Indigo + '#FF4F81', // Vibrant Pink + '#AEEA00', // Chartreuse + '#FFAB40', // Sunset Orange + '#00E5FF', // Aqua + '#FF6F00', // Vivid Orange + '#64DD17', // Leaf Green + '#FFEA00', // Vivid Yellow + '#C51162', // Deep Rose + '#40C4FF', // Sky Blue + '#D500F9', // Vivid Purple + '#76FF03', // Lime Green + '#FF4081', // Hot Pink + '#00B0FF', // Electric Blue + '#FF1744', // Crimson + '#B388FF', // Soft Violet + '#1DE9B6', // Minty Teal + '#AA00FF', // Vivid Lavender + '#FFB347', // Pastel Orange + '#00C1D4', // Bright Cyan + '#7C4DFF' // Neon Purple + ]; + + + + let dials = []; const frameSlider = document.getElementById('frameSlider'); @@ -44,7 +79,7 @@ window.onload = () => { const curveCanvas = document.getElementById('curveCanvas'); - const curveEditor = new CurveEditor(curveCanvas, 6, frameSlider); + const curveEditor = new CurveEditor(curveCanvas, 10, frameSlider); // Animation File List @@ -77,13 +112,14 @@ window.onload = () => { console.log(connectedRobot); let motorIDList = [] clearDials(); - for (const [position, motor] of connectedRobot.positionMap.entries()) { - console.log(`Assigning ${position} motor with ID ${motor.ID}`); + for (const motor of connectedRobot.motors) { curveEditor.addChannel(motor.ID); motorIDList.push(motor.ID); addDial(motor.ID, motor.NAME); } - setSelectedMotor(10); + if (connectedRobot.motors.length > 0){ + setSelectedMotor(connectedRobot.motors[0].ID); + } nodeEditor = new NodeEditor(nodeCanvas, { @@ -95,7 +131,7 @@ window.onload = () => { function setSelectedMotor(motorID) { - console.log(motorID); + //console.log(motorID); curveEditor.selectMotor(motorID); selectedDial = motorID; @@ -109,7 +145,7 @@ window.onload = () => { } }); - console.log("Selected motor:", motorID); + //console.log("Selected motor:", motorID); // Any other logic you want to run @@ -134,8 +170,7 @@ window.onload = () => { // Retrieve motor by position //console.log(robot.getMotor('eyelids')); - // List all assignments - console.log(robot.getAllAssignments()); + return robot; } @@ -417,12 +452,15 @@ window.onload = () => { case 0x06: // CMD_MESSAGE - console.log(`Message Recieved`); + //console.log(`Message Recieved`); const decoder = new TextDecoder(); - console.log(payload); + //console.log(payload); const stringPayload = decoder.decode(new Uint8Array(payload)); - console.log(stringPayload); + //console.log(stringPayload); document.getElementById('log').value += "MSG: " + stringPayload + `\n`; + const logBox = document.getElementById('log'); +logBox.value += "MSG: " + stringPayload + `\n`; +logBox.scrollTop = logBox.scrollHeight; // 🔹 Do something with the file //handleLoadedFile(fileData); break; @@ -479,15 +517,21 @@ window.onload = () => { }); function handlePositionStreamPacket(data) { - for (let i = 0; i < 5; i++) { - const high = data[i * 2]; // High byte - const low = data[i * 2 + 1]; // Low byte - const value = (high << 8) | low; // Combine into uint16_t + const motorCount = Math.floor(data.length / 2); // Each motor uses 2 bytes + for (let i = 0; i < motorCount; i++) { + const high = data[i * 2]; // High byte + const low = data[i * 2 + 1]; // Low byte + const value = (high << 8) | low; // Combine into uint16_t + + if (dials[i]) { dials[i].value = value; } } + console.log(data); +} + function handleLoadedFile(data) { const raw = new Uint8Array(data); const view = new DataView(raw.buffer); @@ -1033,7 +1077,9 @@ window.onload = () => { let dataKey = packets[i].title; let value = packets[i].value; servoMotor[dataKey] = value; - let dataPacket = writeData(servoMotor, dataKey); + let dataPacket = writeData(packets[i].id, servoMotor, dataKey); + //dataPacket[1] = packets[i].id; + console.log(dataPacket); serial.requestWriteData(dataPacket); } console.log(servoMotors); @@ -1073,6 +1119,12 @@ window.onload = () => { console.log(motor.MODEL, motor.POSITION, motor.CURRENT_SPEED); servoMotors[motor.CHANNEL].push(motor); + // If motor is in robot config already, grab the name + let configMotor = connectedRobot.getMotor(motor.ID); + if (configMotor != null){ + motor.NAME = configMotor.NAME; + } + insertTableRow(motor); }