From 99118c5147dc2f2d453ba58feedb98ad2f2ace8b Mon Sep 17 00:00:00 2001 From: "Sai Viswhak .C" Date: Mon, 26 Jan 2026 16:01:43 -0800 Subject: [PATCH 1/9] created send mission method --- server/src/controllers/mission.controller.mjs | 2 +- server/src/index.mjs | 49 ++++++- server/src/services/mavlink.service.mjs | 121 ++++++++++++------ 3 files changed, 132 insertions(+), 40 deletions(-) diff --git a/server/src/controllers/mission.controller.mjs b/server/src/controllers/mission.controller.mjs index d9b3a11..79bfcde 100644 --- a/server/src/controllers/mission.controller.mjs +++ b/server/src/controllers/mission.controller.mjs @@ -58,7 +58,7 @@ export async function getMissionByIdController(req, res) { res.status(500).json({ error: error.message }); } } - +// call mavlink sendmission corrdinaytion in this method export async function createMissionController(req, res) { try { const body = req.body || {}; diff --git a/server/src/index.mjs b/server/src/index.mjs index 7b77c88..058d95d 100644 --- a/server/src/index.mjs +++ b/server/src/index.mjs @@ -2,7 +2,7 @@ import express from 'express'; import cors from 'cors'; import { createServer } from 'http'; import { Server } from 'socket.io'; - +import { sendMissionCoordinates } from "./services/mavlink.service.mjs"; import { serverConfig } from './config/server.config.mjs'; import missionRoutes from './routes/mission.routes.js'; import botRoutes from './routes/bot.routes.mjs'; @@ -21,6 +21,12 @@ const io = new Server(httpServer, { } }); + + + + + + // Middleware app.use(cors({ origin: serverConfig.corsOrigin, @@ -34,6 +40,47 @@ app.use('/api/missions', missionRoutes); app.use('/api/bots', botRoutes); app.use('/api/temperature', temperatureRoutes); + +// ================= ROUTES ================= + +app.post('/api/send-coordinates', async (req, res) => { + try { + let coords = req.body; + + if (!coords || Object.keys(coords).length === 0) { + console.log("No coordinates provided. Generating random test coordinates..."); + + coords = { + lat1: 499394300, + lon1: -1193964200, + lat2: 499394500, + lon2: -1193964500, + lat3: 499394700, + lon3: -1193964300, + lat4: 499394900, + lon4: -1193964700 + }; + } + + console.log("Website requested send-coordinates:"); + console.log(coords); + + await sendMissionCoordinates(coords); + + return res.status(200).json({ + success: true, + message: "Mission coordinates successfully sent to robot.", + sent: coords + }); + + } catch (error) { + console.error("Error sending coordinates:", error); + return res.status(500).json({ error: "Failed to send mission coordinates." }); + } +}); + + + // Setup Socket.IO handlers setupSocketHandlers(io); diff --git a/server/src/services/mavlink.service.mjs b/server/src/services/mavlink.service.mjs index fb073d0..b5ec354 100644 --- a/server/src/services/mavlink.service.mjs +++ b/server/src/services/mavlink.service.mjs @@ -1,13 +1,10 @@ +// mavlinkHandler.mjs import { SerialPort } from "serialport"; import mavlink from "node-mavlink"; import fetch from "node-fetch"; let storeMavlinkDataCallback = null; -export function setStoreMavlinkDataCallback(callback) { - storeMavlinkDataCallback = callback; -} - const { MavLinkPacketSplitter, MavLinkPacketParser, @@ -17,47 +14,103 @@ const { ardupilotmega, } = mavlink; -//create a registry of mappings between msg id and data +export function setStoreMavlinkDataCallback(callback) { + storeMavlinkDataCallback = callback; +} + +// --- START CHANGE: Singleton Serial Port Setup --- +let serialPort = null; + +function getSerialPort() { + if (!serialPort) { + serialPort = new SerialPort({ + path: "/dev/ttyUSB0", // <-- Change this if you use by-id path + baudRate: 57600, + }); + + serialPort.on("open", () => { + console.log("Serial port open."); + }); + + serialPort.on("error", (err) => { + console.error("Serial port error:", err); + }); + } + return serialPort; +} +// --- END CHANGE: Singleton Serial Port Setup --- + + + +// Registry for message parsing const REGISTRY = { ...minimal.REGISTRY, ...common.REGISTRY, ...ardupilotmega.REGISTRY, }; -// substitute /dev/ttyACM0 with your serial port! +// --- START CHANGE: Reuse serial port for mission upload --- +async function sendMissionCoordinates(coords) { + const { lat1, lon1, lat2, lon2, lat3, lon3, lat4, lon4 } = coords; + + console.log("Sending mission coordinates to robot..."); + + const port = getSerialPort(); // <-- REUSED SINGLETON + + // Helper to send one waypoint + const sendWp = (seq, lat, lon) => { + const wp = new common.MissionItemInt( + 1, // target system id + 1, // target component id + seq, // waypoint index + 0, // frame (0 = global) + 16, // command (16 = NAV_WAYPOINT) + 0, // current + 1, // autocontinue + 0, 0, 0, 0, + lat, // latitude * 1e7 + lon, // longitude * 1e7 + 50 // altitude 50m + ); + + const buffer = mavEncoder.pack(wp); + port.write(buffer); + console.log(`Sent WP ${seq}: lat=${lat}, lon=${lon}`); + }; -function handleMavlinkData() { + // Send 4 mission points + sendWp(0, lat1, lon1); + sendWp(1, lat2, lon2); + sendWp(2, lat3, lon3); + sendWp(3, lat4, lon4); + + console.log("All mission coordinates sent."); +} +// --- END CHANGE: Reuse serial port for mission upload --- - //serialPort.close(); - const portSerialNumber = "/dev/ttyUSB0"; +// --- START CHANGE: Reuse serial port for reading MAVLink --- +function handleMavlinkData() { + const port = getSerialPort(); // <-- REUSED SINGLETON - const serialPort = new SerialPort({ - path: portSerialNumber, - baudRate: 57600, - }); + // constructing a reader that will emit each packet separately + const mavlinkRead = port + .pipe(new mavlink.MavLinkPacketSplitter()) + .pipe(new mavlink.MavLinkPacketParser()); - //constructing a reader that will emit each packet separately - const mavlinkRead = serialPort - .pipe(new MavLinkPacketSplitter()) - .pipe(new MavLinkPacketParser()); - console.log("hello from mavlink"); - //storeMavlinkData(1); + console.log("MAVLink reader initialized."); - //setup mavlink to listen for packets - mavlinkRead.on("data", async (packet) => { - console.log("Packet received"); + mavlinkRead.on("data", (packet) => { const clazz = REGISTRY[packet.header.msgid]; if (clazz) { const data = packet.protocol.data(packet.payload, clazz); data.timeBootMs = new Date(); - //process the parsed data based on type switch (clazz.MSG_NAME) { case "GLOBAL_POSITION_INT": - console.log("GLOBAL_POSITION_INT"); + console.log("GLOBAL_POSITION_INT received"); processGlobalPositionMessage(data); break; case "NAMED_VALUE_FLOAT": - console.log("NAMED_VALUE_FLOAT"); + console.log("NAMED_VALUE_FLOAT received"); processTemperatureMessage(data); break; default: @@ -66,20 +119,13 @@ function handleMavlinkData() { } }); - mavlinkRead.on("error", (error) => { - console.error("Error reading Mavlink data:", error); + mavlinkRead.on("error", (err) => { + console.error("Error reading MAVLink:", err); }); } +// --- END CHANGE: Reuse serial port for reading MAVLink --- -/* - Function to simulate incoming temp/position/battery data, trying to copy the format of data objects that previous devs were processing in below functions (processTemperatureMessage and processGlobalPositionMessage, which I have mostly not touched since then). I assumed that the data format for temp and position data will stay the same as Apr 2024, because I was told that this code worked during the demo last year. - - This function simulates - 1) Every 5 seconds, either position or temperature data with a 50/50 chance, coming in from a bot with random ID between 1-5 - 2) Every 15 seconds, data for percentage battery remaining for all 5 bots. - - NOTE: data format for simulated battery data is arbitrary; i.e. the keys do not correspond to actual incoming data, because battery percentage is new and I do not yet know the format in which battery % will be sent by the bot. Once format is finalized, function processBatteryMessage() as well as the 'battery' table in DB must both be changed, and the battery simulation part of the function will break unless also changed accordingly. -*/ +// Simulate data (unchanged) function simulateMavlinkData() { console.log("Simulating MAVLink data..."); const NUM_SIMULATED_BOTS = 3; @@ -221,5 +267,4 @@ function processBatteryMessage(data) { // storeMavlinkData(batteryData); } - -export { handleMavlinkData, simulateMavlinkData }; +export { handleMavlinkData, simulateMavlinkData, sendMissionCoordinates }; From fc413e5e30a3f481c3740af752e63c314b34568d Mon Sep 17 00:00:00 2001 From: devasilmy Date: Mon, 23 Feb 2026 12:33:57 -0800 Subject: [PATCH 2/9] Refactor sendMissionCoordinates to include botID Updated sendMissionCoordinates to accept botID and refactored waypoint creation. --- server/src/services/mavlink.service.mjs | 33 ++++++++++++------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/server/src/services/mavlink.service.mjs b/server/src/services/mavlink.service.mjs index b5ec354..d3e4d79 100644 --- a/server/src/services/mavlink.service.mjs +++ b/server/src/services/mavlink.service.mjs @@ -50,7 +50,7 @@ const REGISTRY = { }; // --- START CHANGE: Reuse serial port for mission upload --- -async function sendMissionCoordinates(coords) { +async function sendMissionCoordinates(botID, coords) { const { lat1, lon1, lat2, lon2, lat3, lon3, lat4, lon4 } = coords; console.log("Sending mission coordinates to robot..."); @@ -59,22 +59,21 @@ async function sendMissionCoordinates(coords) { // Helper to send one waypoint const sendWp = (seq, lat, lon) => { - const wp = new common.MissionItemInt( - 1, // target system id - 1, // target component id - seq, // waypoint index - 0, // frame (0 = global) - 16, // command (16 = NAV_WAYPOINT) - 0, // current - 1, // autocontinue - 0, 0, 0, 0, - lat, // latitude * 1e7 - lon, // longitude * 1e7 - 50 // altitude 50m - ); - - const buffer = mavEncoder.pack(wp); - port.write(buffer); + const wp = new common.MissionItemInt(); + wp.target_system = 1; // target system id + wp.target_componenet = 1; // target component id + wp.seq = seq; // waypoint index + wp.frame = 0; // frame (0 = global) + wp.command = 16; // command (16 = NAV_WAYPOINT) + wp.current = 0; // current + wp.autocontinue = 1; // autocontinue + wp.param1 = botID; wp.param2 = 0; wp.param3 = 0; wp.param4 = 0; + wp.x = lat * 1e7; // latitude * 1e7 + wp.y = lon * 1e7; // longitude * 1e7 + wp.z = 50.0; // altitude 50m + + + send(port, wp, new MavLinkProtocolV2()); console.log(`Sent WP ${seq}: lat=${lat}, lon=${lon}`); }; From dd388225ea0f015131d423e2c4453a1ef5420927 Mon Sep 17 00:00:00 2001 From: devasilmy Date: Mon, 23 Feb 2026 12:37:42 -0800 Subject: [PATCH 3/9] Fix botID usage in send-coordinates logging --- server/src/index.mjs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/index.mjs b/server/src/index.mjs index 058d95d..eb53cc0 100644 --- a/server/src/index.mjs +++ b/server/src/index.mjs @@ -61,11 +61,11 @@ app.post('/api/send-coordinates', async (req, res) => { lon4: -1193964700 }; } - - console.log("Website requested send-coordinates:"); + botID = 1; + console.log("Website requested send-coordinates (botID = 1):"); console.log(coords); - - await sendMissionCoordinates(coords); + + await sendMissionCoordinates(botID, coords); return res.status(200).json({ success: true, From f5649dd4a5ec40c77202556d3f48a21eb9b1af81 Mon Sep 17 00:00:00 2001 From: devasilmy Date: Thu, 26 Feb 2026 13:26:08 -0800 Subject: [PATCH 4/9] Implement mission coordinates retrieval and sending Add mission coordinates handling and sending logic --- server/src/services/database.service.mjs | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/server/src/services/database.service.mjs b/server/src/services/database.service.mjs index a1a164b..5f3512a 100644 --- a/server/src/services/database.service.mjs +++ b/server/src/services/database.service.mjs @@ -1,5 +1,6 @@ import { pool } from '../config/database.config.mjs'; import assert from 'assert'; +import { sendMissionCoordinates } from "./mavlink.service.mjs"; // Helper to parse JSON columns safely const parseJSON = (value, fallback = null) => { @@ -378,6 +379,40 @@ export async function startMission(missionId, startTime, bots) { `UPDATE bot SET assignmentStatus = 'active' WHERE botID IN (${bots.map(() => '?').join(',')})`, bots ); + + // 1. Get the assigned botID + const botIDs = getAssignmentsForMission(missionID); + // for now let's check to see if botID contains 1. + //If so then proceed to the next steps, otherwise skip 2-4. + + // 2. Query the database for mission coordinates using missionId + const mission = await getMissionByID(missionId); + // mission is a json object. + // Inspect the 'areaCoordinates' field it will look like 'areaCoordinates: { east: , west: , north: , south: }' + //in the console.log below. + console.log(mission) + // Store the areaCoordinates in a seperate variable + + // 3. Create a coords object using the variable + // Now the areaCoordinates has 2 (lat, lon) pairs that point to + //the top-left corner and bottom-right corner of the area(square). + // The top-left corner mapping is (north, west) + // The top-right corner mapping is (north, east) + // The bottom-right corner mapping is (south, east) + // The bottom-right corner mapping is (south, west) + + // Use the information above to construct the object coords below: + + /*const coords = { + lat1 ; lon1; + lat2 ; lon2; + lat3; lon3; + lat4; lon4; + } */ + + + // 4. send coords with botID using the sendMissionCoordinates function you defined. + return { success: true }; } catch (error) { console.error('Error starting mission:', error); From b026667fbd1fa7aa97547a5621e3a6e2935c9e78 Mon Sep 17 00:00:00 2001 From: Abdul Date: Sat, 7 Mar 2026 10:27:33 -0800 Subject: [PATCH 5/9] Changed the mavlink communication type to allow for more parameters. Added a custom encoder for the mavlink message parameters. Added a handshake to verify received mavlink message. Handled retries after specified failed acknowledgements --- server/src/services/mavlink.service.mjs | 114 +++++++++++++++++------- 1 file changed, 84 insertions(+), 30 deletions(-) diff --git a/server/src/services/mavlink.service.mjs b/server/src/services/mavlink.service.mjs index d3e4d79..ec94110 100644 --- a/server/src/services/mavlink.service.mjs +++ b/server/src/services/mavlink.service.mjs @@ -1,6 +1,7 @@ // mavlinkHandler.mjs import { SerialPort } from "serialport"; import mavlink from "node-mavlink"; +import { MavLinkProtocolV2, send} from 'node-mavlink'; import fetch from "node-fetch"; let storeMavlinkDataCallback = null; @@ -49,41 +50,90 @@ const REGISTRY = { ...ardupilotmega.REGISTRY, }; -// --- START CHANGE: Reuse serial port for mission upload --- -async function sendMissionCoordinates(botID, coords) { +/// +function encodeMissionData(numTempReadings , coords) { + const { lat1, lon1, lat2, lon2, lat3, lon3, lat4, lon4 } = coords; - console.log("Sending mission coordinates to robot..."); + const lats = [lat1,lat2,lat3,lat4]; + const lons = [lon1,lon2,lon3,lon4]; - const port = getSerialPort(); // <-- REUSED SINGLETON + // Create a buffer for the full MAVLink payload (249 bytes) + const buffer = Buffer.alloc(249); + let offset = 0; - // Helper to send one waypoint - const sendWp = (seq, lat, lon) => { - const wp = new common.MissionItemInt(); - wp.target_system = 1; // target system id - wp.target_componenet = 1; // target component id - wp.seq = seq; // waypoint index - wp.frame = 0; // frame (0 = global) - wp.command = 16; // command (16 = NAV_WAYPOINT) - wp.current = 0; // current - wp.autocontinue = 1; // autocontinue - wp.param1 = botID; wp.param2 = 0; wp.param3 = 0; wp.param4 = 0; - wp.x = lat * 1e7; // latitude * 1e7 - wp.y = lon * 1e7; // longitude * 1e7 - wp.z = 50.0; // altitude 50m - - - send(port, wp, new MavLinkProtocolV2()); - console.log(`Sent WP ${seq}: lat=${lat}, lon=${lon}`); - }; + // Pack number of temperature readings + buffer.writeInt32LE(numTempReadings, offset); + offset += 4; + + // Pack Latitudes (Int32, Little Endian) + lats.forEach(lat => { + buffer.writeInt32LE((lat*1e7), offset); + offset += 4; + }); + + // Pack Longitudes (Int32, Little Endian) + lons.forEach(lon => { + buffer.writeInt32LE(lon*1e7, offset); + offset += 4; + }); + + // Return the 249-byte array ready for MAVLink + return Array.from(buffer); +} +/// - // Send 4 mission points - sendWp(0, lat1, lon1); - sendWp(1, lat2, lon2); - sendWp(2, lat3, lon3); - sendWp(3, lat4, lon4); +// --- START CHANGE: Reuse serial port for mission upload --- +let receivedAck = false; - console.log("All mission coordinates sent."); +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +async function sendMissionCoordinates(botId, numTempReadings , coords) { +/// + const payload = encodeMissionData(numTempReadings , coords); + + const msg = new common.LoggingDataAcked(); + msg.target_system = botId; + msg.target_component = 0; + msg.seq = 0; + msg.length = 249; + msg.first_message_offset = 0; + msg.data = payload; + + console.log("Sending mission data to bot " + botId + "..."); + + const port = getSerialPort(); + + await send(port, msg, new MavLinkProtocolV2()); + + let timer = 0; + const timeLimit = 5; // maximum wait time(in seconds) to receive acknowledgement + let countSend = 1; + const sendLimit = 3; // limit of amount time for data to be sent until acknowledgement is received + while(receivedAck == false && countSend <= sendLimit) { + while(receivedAck == false && timer <= timeLimit) { + await sleep(1000); + timer++; + } + timer = 0; // reset the timer + + if (receivedAck == true) { + console.log("Received acknowledgement from bot", botId); + } + else { + console.error("Did not receive acknowledgement from bot", botId); + console.log("Trying again..."); + await send(port, msg, new MavLinkProtocolV2()); + } + countSend++; + } + if(receivedAck == false) { + throw new Error("Failed to receive acknowledgement from bot " + botId + + " after trying " + sendLimit + " times"); + } + receivedAck = false; } // --- END CHANGE: Reuse serial port for mission upload --- @@ -112,6 +162,10 @@ function handleMavlinkData() { console.log("NAMED_VALUE_FLOAT received"); processTemperatureMessage(data); break; + case "LOGGING_ACK": + console.log("LOGGING_ACK received"); + receivedAck = true; + break; default: console.log("Unknown message type:", clazz.MSG_NAME); } @@ -266,4 +320,4 @@ function processBatteryMessage(data) { // storeMavlinkData(batteryData); } -export { handleMavlinkData, simulateMavlinkData, sendMissionCoordinates }; +export { handleMavlinkData, simulateMavlinkData, sendMissionCoordinates }; \ No newline at end of file From f626b7427d6b31b8ab01355d4a9737754c6df06a Mon Sep 17 00:00:00 2001 From: Abdul Azeez Date: Sat, 7 Mar 2026 10:38:46 -0800 Subject: [PATCH 6/9] Updated logic to receive success on startMission before updating the bot status. Alert the user if startMission failed to start. --- client/src/app/missions/[id]/page.tsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/client/src/app/missions/[id]/page.tsx b/client/src/app/missions/[id]/page.tsx index d127700..cf099e7 100644 --- a/client/src/app/missions/[id]/page.tsx +++ b/client/src/app/missions/[id]/page.tsx @@ -26,6 +26,22 @@ export default function MissionDetail() { console.log('Updating mission:', id); if (start) { + + try { + // Push update to the database + const response = start + ? await startMission(missionId, time) + : await endMission(missionId, time); + + if (response.status == 200) { + console.log("mission " + missionId + " sent: " + response.data.message); + } + + } catch (error) { + alert(`Mission failed to start: ${error.response?.data?.error || error.message}`); + return; + } + mission!.timeStart = time; } else if (!start) { mission!.timeEnd = time; @@ -49,9 +65,6 @@ export default function MissionDetail() { } setMission(mission!); - // Push update to the database - const response = await (start ? startMission(missionId, time) : endMission(missionId, time)); - console.log(`Mission ${start ? 'started' : 'ended'}:`, response); }; const handleDelete = async (missionId: number, missionName: string) => { From cd830d85f819546d2166dc82a339f6d15331744a Mon Sep 17 00:00:00 2001 From: Abdul Azeez Date: Sat, 7 Mar 2026 10:39:57 -0800 Subject: [PATCH 7/9] Return response object instead of just data to access metadata of the response. --- client/src/api/missions.api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/api/missions.api.ts b/client/src/api/missions.api.ts index e8e397e..5ede7b0 100644 --- a/client/src/api/missions.api.ts +++ b/client/src/api/missions.api.ts @@ -126,7 +126,7 @@ export const startMission = async (id: number, time: string) => { headers: { 'Content-Type': 'application/json' }, }, ); - return response.data as { message: string }; + return response; }; export const endMission = async (id: number, time: string) => { From 96260e0375162c574f0d5563275801ffe86065c3 Mon Sep 17 00:00:00 2001 From: Abdul Azeez Date: Sat, 7 Mar 2026 10:42:38 -0800 Subject: [PATCH 8/9] Included import for handleMavlinkData --- server/src/index.mjs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/server/src/index.mjs b/server/src/index.mjs index eb53cc0..b49e37a 100644 --- a/server/src/index.mjs +++ b/server/src/index.mjs @@ -2,7 +2,7 @@ import express from 'express'; import cors from 'cors'; import { createServer } from 'http'; import { Server } from 'socket.io'; -import { sendMissionCoordinates } from "./services/mavlink.service.mjs"; +import { sendMissionCoordinates, handleMavlinkData } from "./services/mavlink.service.mjs"; import { serverConfig } from './config/server.config.mjs'; import missionRoutes from './routes/mission.routes.js'; import botRoutes from './routes/bot.routes.mjs'; @@ -88,8 +88,9 @@ setupSocketHandlers(io); setStoreMavlinkDataCallback((data) => storeMavlinkData(data, io)); // Start MAVLink data simulation -// handleMavlinkData(); // for real data -simulateMavlinkData(); // for simulated data +handleMavlinkData(); // for real data +// simulateMavlinkData(); // for simulated data + // Start server httpServer.listen(serverConfig.port, () => { @@ -97,3 +98,5 @@ httpServer.listen(serverConfig.port, () => { console.log(`WebSocket server ready`); console.log(`Environment: ${serverConfig.environment}`); }); + + From 6ab70175d2646e08f7b735c53067f566744783a7 Mon Sep 17 00:00:00 2001 From: "Sai Viswhak .C" Date: Wed, 25 Mar 2026 13:53:43 -0700 Subject: [PATCH 9/9] database --- server/src/services/database.service.mjs | 67 +++++++++++++----------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/server/src/services/database.service.mjs b/server/src/services/database.service.mjs index 5f3512a..aeb1d35 100644 --- a/server/src/services/database.service.mjs +++ b/server/src/services/database.service.mjs @@ -380,38 +380,41 @@ export async function startMission(missionId, startTime, bots) { bots ); - // 1. Get the assigned botID - const botIDs = getAssignmentsForMission(missionID); - // for now let's check to see if botID contains 1. - //If so then proceed to the next steps, otherwise skip 2-4. - - // 2. Query the database for mission coordinates using missionId - const mission = await getMissionByID(missionId); - // mission is a json object. - // Inspect the 'areaCoordinates' field it will look like 'areaCoordinates: { east: , west: , north: , south: }' - //in the console.log below. - console.log(mission) - // Store the areaCoordinates in a seperate variable - - // 3. Create a coords object using the variable - // Now the areaCoordinates has 2 (lat, lon) pairs that point to - //the top-left corner and bottom-right corner of the area(square). - // The top-left corner mapping is (north, west) - // The top-right corner mapping is (north, east) - // The bottom-right corner mapping is (south, east) - // The bottom-right corner mapping is (south, west) - - // Use the information above to construct the object coords below: - - /*const coords = { - lat1 ; lon1; - lat2 ; lon2; - lat3; lon3; - lat4; lon4; - } */ - - - // 4. send coords with botID using the sendMissionCoordinates function you defined. + // 1. Get the assigned botIDs +const botIDs = await getAssignmentsForMission(missionId); + + +if (!botIDs || botIDs.length === 0) { + return { success: true }; // nothing to send +} + +// 2. Get mission data +const missionResult = await getMissionByID(missionId); +if (!missionResult.success) { + throw new Error("Mission not found"); +} + +const mission = missionResult.data; + +// Parse coordinates safely +const area = parseJSON(mission.areaCoordinates); + +if (!area) { + throw new Error("Invalid areaCoordinates"); +} + +// 3. Construct coords object (4 corners) +const coords = { + lat1: area.north, lon1: area.west, // top-left + lat2: area.north, lon2: area.east, // top-right + lat3: area.south, lon3: area.east, // bottom-right + lat4: area.south, lon4: area.west // bottom-left +}; + +// 4. Send to each bot +for (const botID of botIDs) { + await sendMissionCoordinates(botID, coords); +} return { success: true }; } catch (error) {