aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md16
-rw-r--r--data_recorder.c16
-rw-r--r--src/survive_playback.c11
-rw-r--r--tools/viz/README.md13
-rw-r--r--tools/viz/index.html10
-rw-r--r--tools/viz/survive_viewer.js341
-rw-r--r--useful_files/viz_screenshot.pngbin0 -> 191721 bytes
7 files changed, 218 insertions, 189 deletions
diff --git a/README.md b/README.md
index a4fd656..4dce4f9 100644
--- a/README.md
+++ b/README.md
@@ -280,6 +280,22 @@ To actually replay it, put that directory path in the 'PlaybackFile' configurati
There is also a config variable -- `PlaybackFactor` -- which adjusts the speed at which playback happens. A value of 1 emulates the same time the events file took to create, a value of 0 streams the data in as fast as possible.
+# Visualization
+
+- Download and install: http://websocketd.com/
+- Build the repo
+- Run `data_recorder` through `websocketd` like so:
+
+``` websocketd --port=8080 ./data_recorder```
+
+- Navigate to the `/tools/viz/index.html` page in chrome.
+
+Nothing will happen until you connect to that page. When you do, the app lifetime will be bound to that session -- reloading the page will reload data_recorder.
+
+The arrow keys will move you to the left / right / up / down and the UI response to orbital mouse controls.
+
+![Visuzliation Screenshot](https://raw.githubusercontent.com/cnlohr/libsurvive/master/useful_files/viz_screenshot.jpg)
+
## Notes about coordinate frames.
BELOW IS NOT FINALIZED!!!!
diff --git a/data_recorder.c b/data_recorder.c
index e406387..1392bed 100644
--- a/data_recorder.c
+++ b/data_recorder.c
@@ -85,6 +85,13 @@ void my_raw_pose_process(SurviveObject *so, uint8_t lighthouse, SurvivePose *pos
pose->Pos[2], pose->Rot[0], pose->Rot[1], pose->Rot[2], pose->Rot[3]);
}
+void my_info_process(SurviveContext *ctx, const char *fault) { write_to_output("INFO LOG %s\n", fault); }
+void my_angle_process(struct SurviveObject *so, int sensor_id, int acode, uint32_t timecode, FLT length, FLT angle,
+ uint32_t lh) {
+ survive_default_angle_process(so, sensor_id, acode, timecode, length, angle, lh);
+ write_to_output("%s A %d %d %u %0.6f %0.6f %u\n", so->codename, sensor_id, acode, timecode, length, angle, lh);
+}
+
void my_light_process(struct SurviveObject *so, int sensor_id, int acode,
int timeinsweep, uint32_t timecode, uint32_t length,
uint32_t lh) {
@@ -92,7 +99,7 @@ void my_light_process(struct SurviveObject *so, int sensor_id, int acode,
length, lh);
if (acode == -1 || sensor_id < 0) {
- write_to_output("%s A %d %d %d %u %u %u\n", so->codename, sensor_id, acode, timeinsweep, timecode, length, lh);
+ write_to_output("%s S %d %d %d %u %u %u\n", so->codename, sensor_id, acode, timeinsweep, timecode, length, lh);
return;
}
@@ -133,8 +140,8 @@ void my_light_process(struct SurviveObject *so, int sensor_id, int acode,
break;
}
- write_to_output("%s %s %s %u %d %d %d %u %u\n", so->codename, LH_ID, LH_Axis, timecode, sensor_id, acode,
- timeinsweep, length, lh);
+ write_to_output("%s %s %s %d %d %d %u %u %u\n", so->codename, LH_ID, LH_Axis, sensor_id, acode, timeinsweep,
+ timecode, length, lh);
buffertimeto[jumpoffset] = 0;
}
@@ -192,7 +199,8 @@ void *SurviveThread(void *junk) {
survive_install_imu_fn(ctx, my_imu_process);
survive_install_lighthouse_pose_fn(ctx, my_lighthouse_process);
survive_install_raw_pose_fn(ctx, my_raw_pose_process);
-
+ survive_install_angle_fn(ctx, my_angle_process);
+ survive_install_info_fn(ctx, my_info_process);
survive_cal_install(ctx);
if (!ctx) {
fprintf(stderr, "Fatal. Could not start\n");
diff --git a/src/survive_playback.c b/src/survive_playback.c
index cd7906e..df9fcaa 100644
--- a/src/survive_playback.c
+++ b/src/survive_playback.c
@@ -70,14 +70,14 @@ static int parse_and_run_lightcode(const char *line,
char axn[10];
char dev[10];
uint32_t timecode = 0;
- int sensor = 0;
+ int sensor_id = 0;
int acode = 0;
int timeinsweep = 0;
- uint32_t pulselength = 0;
+ uint32_t length = 0;
uint32_t lh = 0;
- int rr = sscanf(line, "%8s %8s %8s %u %d %d %d %u %u\n", dev, lhn, axn, &timecode, &sensor, &acode, &timeinsweep,
- &pulselength, &lh);
+ int rr = sscanf(line, "%8s %8s %8s %u %d %d %d %u %u\n", dev, lhn, axn, &sensor_id, &acode, &timeinsweep, &timecode,
+ &length, &lh);
if (rr != 9) {
fprintf(stderr, "Warning: On line %d, only %d values read: '%s'\n",
@@ -97,8 +97,7 @@ static int parse_and_run_lightcode(const char *line,
return -1;
}
- driver->ctx->lightproc(so, sensor, acode, timeinsweep, timecode,
- pulselength, lh);
+ driver->ctx->lightproc(so, sensor_id, acode, timeinsweep, timecode, length, lh);
return 0;
}
diff --git a/tools/viz/README.md b/tools/viz/README.md
deleted file mode 100644
index 6afbd5c..0000000
--- a/tools/viz/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# How to use
-
-- Download and install: http://websocketd.com/
-- Build the repo
-- Run data_recorder through websocketd like so:
-
-``` websocketd --port=8080 ./data_recorder```
-
-- Navigate to the `index.html` page in this directory on chrome.
-
-When lighthouses, poses, or angle information is found, it should add it the scene.
-
-
diff --git a/tools/viz/index.html b/tools/viz/index.html
index 5085faf..b146b5d 100644
--- a/tools/viz/index.html
+++ b/tools/viz/index.html
@@ -19,5 +19,15 @@
<canvas width=800 height=800 id="camcanvas"></canvas>
</div>
</div>
+ <div id="console" style="width: 500px;
+ height: 200px;
+ border: 1px solid white;
+ position: absolute;
+ bottom: 20px;
+ overflow: auto;
+ background-color: rgba(0,200,200, .25);
+ z-index: 3;">
+
+ </div>
</body>
</html>
diff --git a/tools/viz/survive_viewer.js b/tools/viz/survive_viewer.js
index f7c6339..3aa2cf7 100644
--- a/tools/viz/survive_viewer.js
+++ b/tools/viz/survive_viewer.js
@@ -1,4 +1,12 @@
-var sphere, axes;
+var objs = {};
+var visible_tolerance = 48000000 / 15;
+var downAxes = {};
+var angles = {};
+var ctx;
+var canvas;
+var oldDrawTime = 0;
+
+$(function() { $("#toggleBtn").click(function() { $("#cam").toggle(); }); });
function add_lighthouse(idx, p, q) {
var group = new THREE.Group();
@@ -37,14 +45,48 @@ function add_lighthouse(idx, p, q) {
scene.add(group);
// DrawCoordinateSystem(p[0], p[1], p[2], q[0], q[1], q[2], q[3]);
}
-var downAxes = {};
-var angles = {};
-var ctx;
-var canvas;
-var oldDrawTime = 0;
-var lastWhen = {};
-$(function() { $("#toggleBtn").click(function() { $("#cam").toggle(); }); });
+function recolorTrackers(when) {
+ for (var key in angles) {
+ var colors = [];
+
+ for (var lh = 0; lh < 2; lh++) {
+ var bvalue = {"WW0" : "FF", "TR0" : "00"};
+ ctx.strokeStyle = (lh === 0 ? "#FF00" : "#00FF") + bvalue[key];
+
+ if (angles[key][lh])
+
+ for (var id in angles[key][lh]) {
+ var ang = angles[key][lh][id];
+
+ colors[id] = colors[id] || 0;
+
+ if (ang[0] === undefined || ang[1] === undefined)
+ continue;
+
+ for (var acode = 0; acode < 2; acode++) {
+ if (ang[acode][1] < when[key] - visible_tolerance)
+ continue;
+
+ var augment = 0xf;
+ if (lh)
+ augment = augment << 8;
+ if (acode)
+ augment = augment << 4;
+
+ colors[id] = colors[id] | augment;
+ }
+ }
+ }
+
+ for (var id in colors) {
+ if (objs[key]) {
+ var material = objs[key].sensors[id];
+ material.color.setHex(colors[id]);
+ }
+ }
+ }
+ }
function redrawCanvas(when) {
oldDrawTime = new Date().getTime();
@@ -95,8 +137,8 @@ function redrawCanvas(when) {
for (var id in angles[key][lh]) {
var ang = angles[key][lh][id];
- if (ang[0] === undefined || ang[1] === undefined || ang[1][1] < when[key] - 48000000 ||
- ang[0][1] < when[key] - 48000000)
+ if (ang[0] === undefined || ang[1] === undefined || ang[1][1] < when[key] - visible_tolerance ||
+ ang[0][1] < when[key] - visible_tolerance)
continue;
var half_fov = 1.0472 * 2;
@@ -115,14 +157,10 @@ function redrawCanvas(when) {
}
}
-var objs = {};
-var sensorGeometry = new THREE.SphereGeometry(.01, 32, 16);
-// use a "lambert" material rather than "basic" for realistic lighting.
-// (don't forget to add (at least one) light!)
-
function create_object(info) {
+ var sensorGeometry = new THREE.SphereGeometry(.01, 32, 16);
var group = new THREE.Group();
- group.colors = [];
+ group.sensors = [];
if (info.config && info.config.lighthouse_config) {
for (var idx in info.config.lighthouse_config.modelPoints) {
var p = info.config.lighthouse_config.modelPoints[idx];
@@ -131,11 +169,11 @@ function create_object(info) {
color = 0x00ff00;
if (idx === 12)
color = 0x0000ff;
- var sensorMaterial = new THREE.MeshLambertMaterial({color : color});
+ var sensorMaterial = new THREE.MeshBasicMaterial({color : color});
var newSensor = new THREE.Mesh(sensorGeometry, sensorMaterial);
newSensor.position.set(p[0], p[1], p[2]);
- group.colors[idx] = sensorMaterial;
+ group.sensors[idx] = sensorMaterial;
group.add(newSensor);
}
}
@@ -147,112 +185,136 @@ function create_object(info) {
}
var timecode = {};
-$(function() {
-
- function parseLine(msg) {
- var s = msg.split(' ');
-
- var command_mappings = {
- "LH_POSE" : function(v) {
- return {
- type : "lighthouse_pose",
- lighthouse : parseInt(v[1]),
- position : [ parseFloat(v[3]), parseFloat(v[4]), parseFloat(v[5]) ],
- quat : [ parseFloat(v[6]), parseFloat(v[7]), parseFloat(v[8]), parseFloat(v[9]) ]
- };
- },
- "POSE" : function(v) {
- return {
- type: "pose", tracker: v[1], position: [ parseFloat(v[3]), parseFloat(v[4]), parseFloat(v[5]) ],
- quat: [ parseFloat(v[6]), parseFloat(v[7]), parseFloat(v[8]), parseFloat(v[9]) ]
- }
- },
- "CONFIG" : function(v) {
- var configStr = s.slice(3).join(' ');
- var config = JSON.parse(configStr);
-
- return { type: "htc_config", config: config }
+function parseLine(msg) {
+ var s = msg.split(' ');
+
+ var command_mappings = {
+ "LH_POSE" : function(v) {
+ return {
+ type : "lighthouse_pose",
+ lighthouse : parseInt(v[1]),
+ position : [ parseFloat(v[3]), parseFloat(v[4]), parseFloat(v[5]) ],
+ quat : [ parseFloat(v[6]), parseFloat(v[7]), parseFloat(v[8]), parseFloat(v[9]) ]
+ };
+ },
+ "POSE" : function(v) {
+ return {
+ type: "pose", position: [ parseFloat(v[3]), parseFloat(v[4]), parseFloat(v[5]) ],
+ quat: [ parseFloat(v[6]), parseFloat(v[7]), parseFloat(v[8]), parseFloat(v[9]) ]
}
- };
- if (command_mappings[s[2]]) {
- var rtn = command_mappings[s[2]](s);
- rtn.time = parseFloat(s[0]);
- rtn.tracker = s[1];
- return rtn;
+ },
+ "CONFIG" : function(v) {
+ var configStr = s.slice(3).join(' ');
+ var config = JSON.parse(configStr);
+
+ return { type: "htc_config", config: config }
+
+ },
+ 'A' : function(v) {
+ return {
+ type: 'angle', sensor_id: parseInt(v[3]), acode: parseInt(v[4]), timecode: parseInt(v[5]),
+ length: parseFloat(v[6]), angle: parseFloat(v[7]), lighthouse: parseInt(v[8])
}
- return {};
+ },
+ 'LOG' : function(v) {
+ return { type: "info", msg: s.slice(3).join(' ') }
+ },
+ "I" : function(v) {
+ return {
+ type : "imu",
+ mask : parseInt(v[3]),
+ timecode : parseInt(v[4]),
+ accelgyro : [
+ parseFloat(v[5]), parseFloat(v[6]), parseFloat(v[7]), parseFloat(v[8]), parseFloat(v[9]),
+ parseFloat(v[10])
+ ]
+
+ };
}
- var ws;
- if (window.location.protocol === "file:") {
- ws = new WebSocket("ws://localhost:8080/ws");
- } else {
- ws = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host +
- "/ws");
- }
-
- ws.onopen = function(evt) {
- // ws.send("!");
};
- ws.onmessage = function(evt) {
- var msg = evt.data;
- var obj;
- if (msg[0] == "{")
- obj = JSON.parse(msg);
- else
- obj = parseLine(msg);
-
- // console.log(obj);
- if (obj.type === "pose") {
- if (objs[obj.tracker]) {
- objs[obj.tracker].position.set(obj.position[0], obj.position[1], obj.position[2]);
- objs[obj.tracker].quaternion.set(obj.quat[1], obj.quat[2], obj.quat[3], obj.quat[0]);
- }
- } else if (obj.type === "lighthouse_pose") {
- add_lighthouse(obj.lighthouse, obj.position, obj.quat);
- } else if (obj.type === "htc_config") {
- create_object(obj);
- } else if (obj.type === "imu") {
- if (objs[obj.tracker]) {
- if (!downAxes[obj.tracker]) {
- downAxes[obj.tracker] = new THREE.Geometry();
- downAxes[obj.tracker].vertices.push(
- new THREE.Vector3(0, 0, 0),
- new THREE.Vector3(obj.accelgyro[0], obj.accelgyro[1], obj.accelgyro[2]));
-
- var line = new THREE.Line(downAxes[obj.tracker], new THREE.LineBasicMaterial({color : 0xffffff}));
- objs[obj.tracker].add(line);
- } else {
- var q = obj.accelgyro;
- downAxes[obj.tracker].vertices[1].fromArray(q);
- downAxes[obj.tracker].verticesNeedUpdate = true;
+ if (command_mappings[s[2]]) {
+ var rtn = command_mappings[s[2]](s);
+ rtn.time = parseFloat(s[0]);
+ rtn.tracker = s[1];
+ return rtn;
+ }
+ return {};
+}
+
+$(function() {
+ setTimeout(function() {
+ var ws;
+
+ if (window.location.protocol === "file:") {
+ ws = new WebSocket("ws://localhost:8080/ws");
+ } else {
+ ws = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host +
+ "/ws");
+ }
+
+ ws.onopen = function(evt) {
+ // ws.send("!");
+ };
+ ws.onmessage = function(evt) {
+ var msg = evt.data;
+ var obj;
+ if (msg[0] == "{")
+ obj = JSON.parse(msg);
+ else
+ obj = parseLine(msg);
+
+ // console.log(obj);
+ if (obj.type === "pose") {
+ if (objs[obj.tracker]) {
+ objs[obj.tracker].position.set(obj.position[0], obj.position[1], obj.position[2]);
+ objs[obj.tracker].quaternion.set(obj.quat[1], obj.quat[2], obj.quat[3], obj.quat[0]);
+ }
+ } else if (obj.type === "info") {
+ var consoleDiv = $("#console");
+ consoleDiv.append(obj.msg + "</br>");
+ consoleDiv[0].scrollTop = consoleDiv[0].scrollHeight;
+ } else if (obj.type === "lighthouse_pose") {
+ add_lighthouse(obj.lighthouse, obj.position, obj.quat);
+ } else if (obj.type === "htc_config") {
+ create_object(obj);
+ } else if (obj.type === "imu") {
+ if (objs[obj.tracker]) {
+ if (!downAxes[obj.tracker]) {
+ downAxes[obj.tracker] = new THREE.Geometry();
+ downAxes[obj.tracker].vertices.push(
+ new THREE.Vector3(0, 0, 0),
+ new THREE.Vector3(obj.accelgyro[0], obj.accelgyro[1], obj.accelgyro[2]));
+
+ var line =
+ new THREE.Line(downAxes[obj.tracker], new THREE.LineBasicMaterial({color : 0xffffff}));
+ objs[obj.tracker].add(line);
+ } else {
+ var q = obj.accelgyro;
+ downAxes[obj.tracker].vertices[1].fromArray(q);
+ downAxes[obj.tracker].verticesNeedUpdate = true;
+ }
}
- }
- } else if (obj.type === "angle") {
- angles[obj.tracker] = angles[obj.tracker] || {};
- angles[obj.tracker][obj.lighthouse] = angles[obj.tracker][obj.lighthouse] || {};
- angles[obj.tracker][obj.lighthouse][obj.sensor_id] =
- angles[obj.tracker][obj.lighthouse][obj.sensor_id] || {};
+ } else if (obj.type === "angle") {
+ angles[obj.tracker] = angles[obj.tracker] || {};
+ angles[obj.tracker][obj.lighthouse] = angles[obj.tracker][obj.lighthouse] || {};
+ angles[obj.tracker][obj.lighthouse][obj.sensor_id] =
+ angles[obj.tracker][obj.lighthouse][obj.sensor_id] || {};
- angles[obj.tracker][obj.lighthouse][obj.sensor_id][obj.acode] = [ obj.angle, obj.timecode ];
- timecode[obj.tracker] = obj.timecode;
- }
+ angles[obj.tracker][obj.lighthouse][obj.sensor_id][obj.acode & 1] = [ obj.angle, obj.timecode ];
+ timecode[obj.tracker] = obj.timecode;
+ }
- // ws.send("!");
- };
+ // ws.send("!");
+ };
+ }, 60); // Hacky, but this gives the server time to restart on CTRL+R
});
-//////////
-// MAIN //
-//////////
-
// standard global variables
-var container, scene, camera, renderer, controls, stats;
-var clock = new THREE.Clock();
+var container, scene, camera, renderer, controls;
// custom global variables
-var cube;
$(function() {
// initialization
init();
@@ -272,23 +334,16 @@ init() {
///////////
scene = new THREE.Scene();
- ////////////
- // CAMERA //
- ////////////
-
- // set the view size in pixels (custom or according to window size)
- // var SCREEN_WIDTH = 400, SCREEN_HEIGHT = 300;
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
// camera attributes
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.01, FAR = 200;
+
// set up camera
camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
camera.up = new THREE.Vector3(0, 0, 1);
+
// add the camera to the scene
scene.add(camera);
- // the camera defaults to position (0,0,0)
- // so pull it back (z = 400) and up (y = 100) and set the angle towards the
- // scene origin
camera.position.set(5, 2, 5.00);
camera.lookAt(scene.position);
@@ -297,52 +352,24 @@ init() {
//////////////
renderer = new THREE.WebGLRenderer({antialias : true});
-
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
// attach div element to variable to contain the renderer
container = document.getElementById('ThreeJS');
- // alternatively: to create the div at runtime, use:
- // container = document.createElement( 'div' );
- // document.body.appendChild( container );
// attach renderer to the container div
container.appendChild(renderer.domElement);
- ////////////
- // EVENTS //
- ////////////
-
- /*
- // automatically resize renderer
- THREEx.WindowResize(renderer, camera);
- // toggle full-screen on given key press
- THREEx.FullScreen.bindKey({ charCode : 'm'.charCodeAt(0) });
-*/
- //////////////
- // CONTROLS //
- //////////////
-
// move mouse and: left click to rotate,
// middle click to zoom,
// right click to pan
controls = new THREE.OrbitControls(camera, renderer.domElement);
- ///////////
- // LIGHT //
- ///////////
-
// create a light
var light = new THREE.PointLight(0xffffff);
light.position.set(0, 5, 0);
scene.add(light);
- var ambientLight = new THREE.AmbientLight(0x111111);
- // scene.add(ambientLight);
- var floorTexture = new THREE.ImageUtils.loadTexture('images/checkerboard.jpg');
- floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
- floorTexture.repeat.set(10, 10);
- // DoubleSide: render texture on both sides of mesh
var floorMaterial =
new THREE.MeshBasicMaterial({color : 0x000000, opacity : 0.15, transparent : true, side : THREE.FrontSide});
var floorGeometry = new THREE.PlaneGeometry(10, 10);
@@ -351,35 +378,17 @@ init() {
scene.add(floor);
- /////////
- // SKY //
- /////////
-
- // recommend either a skybox or fog effect (can't use both at the same time)
- // without one of these, the scene's background color is determined by
- // webpage background
-
var skyBoxGeometry = new THREE.CubeGeometry(50, 50, 50);
var skyBoxMaterial = new THREE.MeshBasicMaterial({color : 0x888888, side : THREE.BackSide});
var skyBox = new THREE.Mesh(skyBoxGeometry, skyBoxMaterial);
scene.add(skyBox);
-
- // fog must be added to scene before first render
- // scene.fog = new THREE.FogExp2(0xffffff, 0.025);
}
function animate() {
requestAnimationFrame(animate);
+ recolorTrackers(timecode);
render();
- update();
redrawCanvas(timecode);
}
-function update() {
- // delta = change in time since last call (in seconds)
- var delta = clock.getDelta();
-
- // controls.update();
- }
-
function render() { renderer.render(scene, camera); }
diff --git a/useful_files/viz_screenshot.png b/useful_files/viz_screenshot.png
new file mode 100644
index 0000000..0853630
--- /dev/null
+++ b/useful_files/viz_screenshot.png
Binary files differ