Skip to content

Commit

Permalink
Speedometer, Waypoints PoseArray (#95)
Browse files Browse the repository at this point in the history
* added PoseArray support to Waypoints

* added tf speedometer

* fixed navsat tile culling in rotationless mode

* tf deletion timeout 10x, bugfixes

* navsat import/export for saved tiles, pose color fix for dot, speedometer tf link fetch fix

* navsat description update

* prevent pwa refresh when screen dragging elements

* removed unused tf_tree, recursive timestamp updating
  • Loading branch information
MoffKalast authored Sep 15, 2024
1 parent 37fd245 commit cb29d1b
Show file tree
Hide file tree
Showing 18 changed files with 780 additions and 110 deletions.
94 changes: 94 additions & 0 deletions public/assets/speedometer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 65 additions & 0 deletions public/assets/speedometer_dial.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
104 changes: 104 additions & 0 deletions public/assets/speedometer_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions public/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ html, body {
text-rendering: optimizeLegibility;

overflow: hidden;
overscroll-behavior:none;
touch-action: none; /* Safari zooming chaos prevention */
}

Expand Down Expand Up @@ -43,6 +44,33 @@ object {
transform: translate(-50%, -50%);
font-weight: bold;
font-size: 0.8em;
pointer-events: none;
}

.icon-text-dial {
position: absolute;
top: 45%;
left: 50%;
margin: 0;
width: 100%;
transform: translate(-68%, 35%);
font-weight: bold;
font-size: 0.7em;
color: black;
text-align: right;
}

.icon-text-dial-unit {
position: absolute;
top: 45%;
left: 50%;
margin: 0;
width: 100%;
transform: translate(-50%, -100%);
font-weight: bold;
font-size: 0.5em;
color: black;
text-align: center;
}

.icon-img {
Expand Down
6 changes: 6 additions & 0 deletions public/js/modules/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ export class IndexedDatabase {
});
}

async getAllKeys(){
return await this._performTransaction('readonly', (store) => {
return store.getAllKeys();
});
}

async _performTransaction(mode, operation) {
return new Promise((resolve, reject) => {
if (!this.db) {
Expand Down
38 changes: 38 additions & 0 deletions public/js/modules/navsat.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,44 @@ async function dataToImage(data){
})
}

export async function exportDatabase(filename) {
const allData = [];

async function dumpData() {
const keylist = await db.getAllKeys();
await Promise.all(keylist.map(async (url) => {
const value = await db.getObject(url);
allData.push({
key: url,
value: value
});
}));
}

await dumpData();

const dataBlob = new Blob([JSON.stringify(allData)], {type: 'application/json'});

const url = URL.createObjectURL(dataBlob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();

URL.revokeObjectURL(url);
}

export async function importDatabase(file) {
const data = JSON.parse(file);
try {
await Promise.all(data.map(item => db.setObject(item.key, item.value)));
alert("Tiles imported successfully! (it might take a bit for them to save to disk and become available, be patient)");
} catch (error) {
console.error(error);
alert("An error occurred during import. Please check the console for details.");
}
}

export class Navsat {

constructor (){
Expand Down
53 changes: 21 additions & 32 deletions public/js/modules/tf.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ export class TF {
constructor() {
this.fixed_frame = '';

this.tf_tree = {};
this.transforms = {};
this.absoluteTransforms = {};
//this.absoluteTransformsHistory = new TimeStampedData(20);
this.frame_list = new Set();
this.frame_timestamps = {};
this.frame_headerstamps = {};

this.tf_topic = new ROSLIB.Topic({
ros: rosbridge.ros,
Expand All @@ -90,6 +90,7 @@ export class TF {
msg.transforms.forEach((pose) => {
this.frame_timestamps[pose.child_frame_id] = time_stamp;
this.frame_timestamps[pose.header.frame_id] = time_stamp;
this.updateFrameTimestamp(pose.child_frame_id,pose.header.stamp)
})

this.updateTransforms(msg.transforms, false);
Expand Down Expand Up @@ -118,11 +119,11 @@ export class TF {
const now = new Date()
let deleted_anything = false;
for (const [frame_id, time_stamp] of Object.entries(this.frame_timestamps)) {
if(now - time_stamp > 1000 * 10){
delete this.tf_tree[frame_id];
if(now - time_stamp > 1000 * 100){
delete this.frame_list[frame_id];
delete this.transforms[frame_id];
delete this.absoluteTransforms[frame_id];
delete this.frame_headerstamps[frame_id];
deleted_anything = true;
}
}
Expand All @@ -133,6 +134,19 @@ export class TF {
},5000)
}

updateFrameTimestamp(frame_id, stamp){
this.frame_headerstamps[frame_id] = stamp;

//update all child frames that were moved as well
for (const frame in this.transforms) {
if (this.transforms[frame].parent === frame_id) {
this.frame_headerstamps[frame] = stamp; //we assume that the frame we just got is newer than what we already have
this.updateFrameTimestamp(frame, stamp);
}
}
}


/* interpolateTransforms() {
if (this.lastReceivedTransforms !== null && this.previousTransforms !== null && performance.now() - this.lastReceivedTime > 15) {
const prevdelta = (this.lastReceivedTime - this.previousTime) / 1000;
Expand Down Expand Up @@ -193,34 +207,6 @@ export class TF {
}
}

addToTree(parentFrameId, childFrameId) {

if (this.tf_tree.hasOwnProperty(childFrameId)) {
delete this.tf_tree[childFrameId];
}

if (this.tf_tree.hasOwnProperty(parentFrameId)) {
this.tf_tree[parentFrameId][childFrameId] = {};
} else {
const foundParent = (node) => {
for (const key in node) {
if (key === parentFrameId) {
node[key][childFrameId] = {};
return true;
} else {
if (foundParent(node[key])) {
return true;
}
}
}
return false;
};
if (!foundParent(this.tf_tree)) {
this.tf_tree[parentFrameId] = { [childFrameId]: {} };
}
}
}

getPathToRoot(frame) {
const currentFrame = this.transforms[frame];
if (!currentFrame) {
Expand Down Expand Up @@ -264,7 +250,6 @@ export class TF {
),
parent: parentFrameId
};
this.addToTree(parentFrameId, childFrameId);
});

this.recalculateAbsoluteTransforms();
Expand Down Expand Up @@ -337,6 +322,10 @@ export class TF {
rotation: outputQuat
};
}

getTimeStampDelta(timestamp1, timestamp2) {
return timestamp2.secs - timestamp1.secs + ((timestamp2.nsecs - timestamp1.nsecs) / 1e9);
}
}

export let tf = new TF();
12 changes: 10 additions & 2 deletions public/templates/add/add_modal.html
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ <h3>Add Widgets</h3>
</div>
</div>

<div class="widget_entry" onclick="addWidget('waypoints','')" data-topic="nav_msgs/Path">
<div class="widget_entry" onclick="addWidget('waypoints','')" data-topic="nav_msgs/Path,geometry_msgs/PoseArray">
<img src="assets/waypoints.svg" alt="Waypoints" class="card_icon">
<div class="card">
<b class="card_title">Waypoint Mission</b>
<p class="card_desc">Send a list of goals [nav_msgs/Path]</p>
<p class="card_desc">Send a list of goals [nav_msgs/Path] or [geometry_msgs/PoseArray]</p>
</div>
</div>

Expand Down Expand Up @@ -137,6 +137,14 @@ <h3>Add Widgets</h3>
</div>
</div>

<div class="widget_entry" onclick="addWidget('speedometer','')">
<img src="assets/speedometer_icon.svg" alt="Speedometer" class="card_icon">
<div class="card">
<b class="card_title">Speedometer</b>
<p class="card_desc">Track the speed of a TF link.</p>
</div>
</div>

<hr>


Expand Down
22 changes: 11 additions & 11 deletions public/templates/grid/grid_script.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,6 @@ const colourpicker = document.getElementById("{uniqueID}_colorpicker");
const linethickness = document.getElementById("{uniqueID}_thickness");
const gridstep = document.getElementById("{uniqueID}_step");

linethickness.value = grid_thickness;
colourpicker.value = grid_colour;
gridstep.value = grid_size;

colourpicker.addEventListener("input", (event) =>{
grid_colour = colourpicker.value;
utilModule.setIconColor(icon, grid_colour);
drawGrid();
saveSettings();
});

if(settings.hasOwnProperty("{uniqueID}")){
const loaded_data = settings["{uniqueID}"];
grid_size = loaded_data.size;
Expand All @@ -44,6 +33,10 @@ if(settings.hasOwnProperty("{uniqueID}")){
saveSettings();
}

linethickness.value = grid_thickness;
colourpicker.value = grid_colour;
gridstep.value = grid_size;

//update the icon colour when it's loaded or when the image source changes
icon.onload = () => {
utilModule.setIconColor(icon, colourpicker.value);
Expand Down Expand Up @@ -165,6 +158,13 @@ gridstep.addEventListener("input", (event) =>{
saveSettings();
});

colourpicker.addEventListener("input", (event) =>{
grid_colour = colourpicker.value;
utilModule.setIconColor(icon, grid_colour);
drawGrid();
saveSettings();
});

resizeScreen();

console.log("Grid Widget Loaded {uniqueID}")
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ function saveSettings(){
async function drawMarkers(){

function drawCircle(size){
ctx.fillStyle = "rgba(139, 0, 0, 0.9)";
ctx.fillStyle = colourpicker.value;
ctx.beginPath();
ctx.arc(0, 0, size/2, 0, 2 * Math.PI, false);
ctx.fill();
Expand Down Expand Up @@ -282,11 +282,11 @@ async function loadTopics(){

let topiclist = "";
pose_topics.forEach(element => {
topiclist += "<option value='"+element+"'>"+element+" (PoseStamped)</option>"
topiclist += "<option value='"+element+"'>"+element+" (PoseStamped)</option>";
typedict[element] = "geometry_msgs/PoseStamped";
});
posecov_topics.forEach(element => {
topiclist += "<option value='"+element+"'>"+element+" (PoseWithCovarianceStamped)</option>"
topiclist += "<option value='"+element+"'>"+element+" (PoseWithCovarianceStamped)</option>";
typedict[element] = "geometry_msgs/PoseWithCovarianceStamped";
});
selectionbox.innerHTML = topiclist
Expand Down
Loading

0 comments on commit cb29d1b

Please sign in to comment.