Original GUI
index.html
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <link rel="stylesheet" href="styles.css" /> <script src='https://cdn.plot.ly/plotly-2.16.1.min.js'> <script type="text/javascript" src="http://static.robotwebtools.org/EventEmitter2/current/eventemitter2.min.js"></script> <script type="text/javascript" src="http://static.robotwebtools.org/roslibjs/current/roslib.min.js"></script> <script type="text/javascript" src="https://static.robotwebtools.org/roslibjs/current/roslib.js"></script> <script src="https://static.robotwebtools.org/threejs/current/three.js"></script> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ros3d@1/build/ros3d.min.js"></script> </head> <!-- <body onload="init()"> --> <body > <div class="center"> <div class="box"> <h1>Nekton GUI roslib Example</h1> <p>Check your web console for an output.</p> <hr /> <div class="btn-group"> <button id="pause_physics" type="button" onclick="pausePhysics()"> Pause Physics </button> <button id="unpause_physics" type="button" onclick="unpausePhysics()"> Unpause Physics </button> </div> <img id="my_image" style='height: 100%; width: 100%; object-fit: contain' src="hzttps://user-images.githubusercontent.com/33184844/207543214-2cd65dfa-8473-4bc8-94ac-f6c2d934cd48.png"> </div> </div> <div class="center"id='myDiv'> <!-- Plotly chart will be drawn inside this DIV --> </div> <script type="text/javascript" src="index.js"></script> <!-- </div> <div class="center"> <h1>Simple PointCloud2 Example</h1> <p>Run the following commands in the terminal then refresh the page.</p> <ol> <li><tt>roscore</tt></li> <li><tt>roslaunch rosbridge_server rosbridge_websocket.launch</tt></li> <li><tt>rosrun tf2_web_republisher tf2_web_republisher</tt></li> <li><tt>roslaunch openni_launch openni.launch depth_registration:=true</tt></li> </ol> <div id="viewer"></div> </div> --> </body> </html>
index.js
index.js
/** * Setup all visualization elements when the page is loaded. */ var ros = new ROSLIB.Ros({ url : 'ws://localhost:9090' }); ros.on("connection", function () { console.log("Connected to websocket server."); }); ros.on("error", function (error) { console.log("Error connecting to websocket server: ", error); }); ros.on("close", function () { console.log("Connection to websocket server closed."); }); // Subscribing to a Topic var listener = new ROSLIB.Topic({ ros: ros, name: "/listener", messageType: "std_msgs/String", }); listener.subscribe(function (message) { console.log("Received message on " + listener.name + ": " + message.data); listener.unsubscribe(); }); // Creating a Service var pausePhysicsService = new ROSLIB.Service({ ros: ros, name: "/pause_physics", serviceType: "std_srvs/srv/Empty", }); var unpausePhysicsService = new ROSLIB.Service({ ros: ros, name: "/unpause_physics", serviceType: "std_srvs/srv/Empty", }); // Function that calls a Service function pausePhysics() { pausePhysicsService.callService(new ROSLIB.ServiceRequest({})); console.log('Physics is now paused.') } function unpausePhysics() { unpausePhysicsService.callService(new ROSLIB.ServiceRequest({})); console.log('Physics is now unpaused.') } // Set up Plotly chart for sonar point cloud let x_coords = []; let y_coords = []; var trace1 = { type: "pointcloud", mode: "markers", marker: { sizemin: 0.5, sizemax: 45, arearatio: 0, color: "rgba(0, 0, 255, 0.8)" }, x: x_coords, y: y_coords } var data = [trace1]; var layout = { plot_bgcolor:"black", paper_bgcolor:"black", title: { text: 'Forward Sonar Point Cloud', font: { family: 'Courier New, monospace', size: 30, color: 'Red' } }, xaxis: { type: "linear", range: [ 0, 91], autorange: false }, yaxis: { type: "linear", range: [0.131,0.146], autorange: false }, height: 598, width: 1080, autosize: true, showlegend: false } Plotly.newPlot('myDiv', data, layout); // Subscribing to parsed point cloud topic var sonar_xy = new ROSLIB.Topic({ ros: ros, name: "/onboard/test_topic", messageType: "std_msgs/msg/Float64MultiArray", }); sonar_xy.subscribe(function (message) { console.log('sonar_xy'); console.log(message.data); let x_coords = []; let y_coords = []; for (let i = 0; i < message.data.length; i++){ // console.log(message.data[i]); if (i % 2 === 0){ x_coords.push(message.data[i]); } else { y_coords.push(message.data[i]); } } var data_update = { x: [x_coords], y: [y_coords] }; console.log(data_update); Plotly.update('myDiv', data_update); // sonar_xy.unsubscribe(); });
style.css
style.css
h1 { text-align: center; padding-left: 20px; padding-right: 20px; margin-bottom: 0px; } body { background-color: cadetblue; } h2 { margin-bottom: 0px; } .center { margin: auto; width: fit-content; padding: 10px; } .box { text-align: center; width: fit-content; margin-left: 10px; margin-top: 10px; padding: 5px; background-color: white; border-radius: 15px; } .btn-group button { background-color: grey; border: 1px solid grey; color: white; padding: 10px 24px; cursor: pointer; float: center; border-radius: 10px; } .btn-group:after { content: ""; clear: both; display: table; } .btn-group button:not(:last-child) { border-right: none; } .btn-group button:hover { background-color: lightgray; }
Updated GUI
index.html
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <link rel="stylesheet" href="styles.css" /> <script type="module" src="./components/nekton-components.js"></script> <script type="text/javascript" src="lib/eventemitter2.js"></script> <script type="text/javascript" src="lib/roslib.min.js"></script> <script type="text/javascript" src="index.js"></script> </head> <body> <canvas id="canvas"></canvas> <div class="center"> <div class="grid-container"> <test-comp text="Box 1"></test-comp> <div class="box">Box 2</div> <div class="box">Box 3</div> <div class="box">Box 4</div> <div class="box">Box 5</div> <test-comp text="Box 6"></test-comp> </div> <sim-controls></sim-controls> </div> </body> </html>
index.js
index.js
// Connecting to ROS var ros = new ROSLIB.Ros({ url: "ws://localhost:9090", }); ros.on("connection", function () { console.log("Connected to websocket server."); }); ros.on("error", function (error) { console.log("Error connecting to websocket server: ", error); }); ros.on("close", function () { console.log("Connection to websocket server closed."); }); // Subscribing to a Topic var listener = new ROSLIB.Topic({ ros: ros, name: "/nekton/pressure", messageType: "sensor_msgs/FluidPressure", }); listener.subscribe(function (message) { const x = message.fluid_pressure / 10051.8; //not sure which formula is correct const myElement = document.getElementById('my-element'); myElement.innerHTML = "Depth: " + x; console.log("Received message on " + x); }); // Subscribe to image_raw topic var image_listener = new ROSLIB.Topic({ ros: ros, name: "/nekton/camera_forward/image_raw", messageType: "sensor_msgs/msg/Image", }); // Create canvas const can = document.createElement("canvas"); const ctx = can.getContext("2d"); image_listener.subscribe(function (image_message) { console.log("Received image message on " + image_listener.name + ": " + image_message.width + " " + image_message.height); // Create a canvas of correct size and obtain a CanvasRenderingContext2D can.width = image_message.width; can.height = image_message.height; // Create an image buffer to hold the pixels const imgData = ctx.createImageData(image_message.width, image_message.height); const data = imgData.data; const inData = atob(image_message.data); var j = 0, i = 4; // j data in, i data out while (j < inData.length) { const w1 = inData.charCodeAt(j++); // Read 3 16-bit words representing 1 pixel const w2 = inData.charCodeAt(j++); const w3 = inData.charCodeAt(j++); if (!image_message.is_bigendian) { data[i++] = w1; // red data[i++] = w2; // green data[i++] = w3; // blue } else { data[i++] = (w1 >> 8) + ((w1 & 0xFF) << 8); data[i++] = (w2 >> 8) + ((w2 & 0xFF) << 8); data[i++] = (w3 >> 8) + ((w3 & 0xFF) << 8); } data[i++] = 255; // alpha } // Put pixel data into the canvas ctx.putImageData(imgData, 0, 0); // Add canvas to the HTML document.body.appendChild(can); }); // Creating a Service var pausePhysicsService = new ROSLIB.Service({ ros: ros, name: "/pause_physics", serviceType: "std_srvs/srv/Empty", }); var unpausePhysicsService = new ROSLIB.Service({ ros: ros, name: "/unpause_physics", serviceType: "std_srvs/srv/Empty", }); var cmdVel = new ROSLIB.Topic({ ros: ros, name: '/nekton/cmd_vel', messageType: 'geometry_msgs/Twist', }); // Initializes the Keyboard Map let keyboard = { w: 0, a: 0, s: 0, d: 0, q: 0, e: 0, ArrowUp: 0, ArrowDown: 0, ArrowRight: 0, ArrowLeft: 0, z: 0, c: 0 }; let velocityMod = 14; let twistMsg;
style.css
style.css
h1 { text-align: center; padding-left: 20px; padding-right: 20px; margin-bottom: 0px; }
body { background-color: cadetblue; } h2 { margin-bottom: 0px; } .center { margin: auto; width: fit-content; padding: 10px; } .box { text-align: center; width: fit-content; margin-left: 10px; margin-top: 10px; padding: 5px; background-color: white; border-radius: 15px; } .btn-group button { background-color: grey; border: 1px solid grey; color: white; padding: 10px 24px; cursor: pointer; float: center; border-radius: 10px; } .btn-group:after { content: ""; clear: both; display: table; } .btn-group button:not(:last-child) { border-right: none; } .btn-group button:hover { background-color: lightgray; } .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); grid-gap: 5%; margin: auto; width: fit-content; /* padding: 10px; / } .grid-item { / background-color:ccc; */ padding: 20px; text-align: center; }