Little IMU demo #1150
Replies: 5 comments 25 replies
-
Alas, the .mp4 link leads me to this:
|
Beta Was this translation helpful? Give feedback.
-
Source code is available at:
All these are work-in-progress! |
Beta Was this translation helpful? Give feedback.
-
We bought a BMI160 sensor and set this up at the Moddable office today. Good news. It works! 🎉It feels just as magical and responsive to use at it looks in your video. A few notes:
|
Beta Was this translation helpful? Give feedback.
-
I updated the BMI160 driver, broke out an AHRS library, tweaked the Fusion library, and updated the main app:
The worker performs the AHRS stuff, the main does the 3D projection and the drawing. One CPU is 98% busy the other 22%. It would probably be yet faster if the 3D calcs were moved to the worker. But I fear that's beyond my patience now 😆. I patterned the AHRS library after the Sensor class pattern but I don't like it. As it stands the information to construct the IMU device is passed in ECMA-419 style and the AHRS class constructs the device. But all it really does with it is to call (I didn't do a fresh install based on what's in the repo, please let me know if I forgot something again...) |
Beta Was this translation helpful? Give feedback.
-
I had some time to rework the Here are the sources: hack3d.d.ts// Based on https://github.com/jordoreed/home-grown-graphics/blob/main/index.html
// By Jordan Reed
declare module "hack3d" {
function randomFloat(min: number, max: number): number
function toRadians(degrees: number): number
interface Vec4 {
x: number
y: number
z: number
w: number
}
class Matrix4 {
m: Float64Array
constructor(...args: number[])
constructor(arr: Float64Array)
constructor(...args: number[] | Float64Array[])
multiply(r: Matrix4): Matrix4
multiplyVec4(v: Vec4): Vec4
static identity(): Matrix4
static perspective(l: number, r: number, b: number, t: number, n: number, f: number): Matrix4
static perspectiveAspectRatio(aspectRatio: number, fov: number, n: number, f: number): Matrix4
static translate(x: number, y: number, z: number): Matrix4
static scale(x: number, y: number, z: number): Matrix4
// pitch
static rotateX(degrees: number): Matrix4
// yaw
static rotateY(degrees: number): Matrix4
// roll
static rotateZ(degrees: number): Matrix4
}
} hack3d.js// Based on https://github.com/jordoreed/home-grown-graphics/blob/main/index.html
// By Jordan Reed
export function randomFloat(min, max) {
return Math.random() * (max - min) + min
}
export function toRadians(degrees) {
return (degrees * Math.PI) / 180
}
export class Matrix4 {
constructor() @ "xs_Matrix"
multiply(r) @ "xs_matrix_multiply"
multiplyVec4(v) @ "xs_matrix_multiplyVec4"
static identity() {
return new Matrix4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
}
static perspective(l, r, b, t, n, f) {
return new Matrix4(
(2 * n) / (r - l),
0,
(r + l) / (r - l),
0,
0,
(2 * n) / (t - b),
(t + b) / (t - b),
0,
0,
0,
-(f + n) / (f - n),
(-2 * f * n) / (f - n),
0,
0,
-1,
0
)
}
static perspectiveAspectRatio(aspectRatio, fov, n, f) {
const halfH = Math.tan(toRadians(fov * 0.5)) * n
const halfW = aspectRatio * halfH
return Matrix4.perspective(-halfW, halfW, -halfH, halfH, n, f)
}
static translate(x, y, z) {
return new Matrix4(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1)
}
static scale(x, y, z) {
return new Matrix4(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1)
}
// pitch
static rotateX(degrees) {
const radians = toRadians(degrees)
const c = Math.cos(radians)
const s = Math.sin(radians)
return new Matrix4(1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1)
}
// yaw
static rotateY(degrees) {
const radians = toRadians(degrees)
const c = Math.cos(radians)
const s = Math.sin(radians)
return new Matrix4(c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1)
}
// roll
static rotateZ(degrees) {
const radians = toRadians(degrees)
const c = Math.cos(radians)
const s = Math.sin(radians)
return new Matrix4(c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
}
} hack3d.c#include "xsmc.h"
#include "mc.xs.h" // for xsID_ values
#include "xsHost.h"
void xs_Matrix(xsMachine *the)
{
if ((1 == xsmcArgc) && xsmcTest(xsArg(0))) // instanceof Float64Array and length === 16
xsmcSet(xsThis, xsID_m, xsArg(0));
else if (16 == xsmcArgc) { // typeof first argument is number
xsNumberValue d[16], *r;
xsUnsignedValue rSize;
xsmcVars(1);
xsmcSetInteger(xsVar(0), 16);
xsmcNew(xsVar(0), xsGlobal, xsID_Float64Array, &xsVar(0), NULL);
xsmcSet(xsThis, xsID_m, xsVar(0));
for (int i = 0; i < 16; i++)
d[i] = xsmcToNumber(xsArg(i));
xsmcGet(xsVar(0), xsVar(0), xsID_buffer);
xsmcGetBufferWritable(xsVar(0), (void **)&r, &rSize);
if (128 != rSize)
xsUnknownError("unexpected");
c_memmove(r, d, rSize);
}
else
xsUnknownError("Invalid arguments");
}
void xs_matrix_multiply(xsMachine *the)
{
xsNumberValue *m, *r, *result;
xsUnsignedValue mSize, rSize, resultSize;
xsSlot n;
xsmcVars(3);
xsmcSetInteger(n, 16);
xsmcNew(xsVar(0), xsGlobal, xsID_Float64Array, &n, NULL);
xsmcNew(xsResult, xsThis, xsID_constructor, &xsVar(0), NULL);
xsmcGet(xsVar(0), xsThis, xsID_m);
xsmcGet(xsVar(0), xsVar(0), xsID_buffer);
xsmcGet(xsVar(1), xsArg(0), xsID_m);
xsmcGet(xsVar(1), xsVar(1), xsID_buffer);
xsmcGet(xsVar(2), xsResult, xsID_m);
xsmcGet(xsVar(2), xsVar(2), xsID_buffer);
xsmcGetBufferReadable(xsVar(0), (void **)&m, &mSize);
xsmcGetBufferReadable(xsVar(1), (void **)&r, &rSize);
xsmcGetBufferWritable(xsVar(2), (void **)&result, &resultSize);
if ((mSize != 128) || (rSize != 128) || (resultSize != 128))
xsUnknownError("invalid input");
result[0] = m[0] * r[0] + m[1] * r[4] + m[2] * r[8] + m[3] * r[12];
result[1] = m[0] * r[1] + m[1] * r[5] + m[2] * r[9] + m[3] * r[13];
result[2] = m[0] * r[2] + m[1] * r[6] + m[2] * r[10] + m[3] * r[14];
result[3] = m[0] * r[3] + m[1] * r[7] + m[2] * r[11] + m[3] * r[15];
result[4] = m[4] * r[0] + m[5] * r[4] + m[6] * r[8] + m[7] * r[12];
result[5] = m[4] * r[1] + m[5] * r[5] + m[6] * r[9] + m[7] * r[13];
result[6] = m[4] * r[2] + m[5] * r[6] + m[6] * r[10] + m[7] * r[14];
result[7] = m[4] * r[3] + m[5] * r[7] + m[6] * r[11] + m[7] * r[15];
result[8] = m[8] * r[0] + m[9] * r[4] + m[10] * r[8] + m[11] * r[12];
result[9] = m[8] * r[1] + m[9] * r[5] + m[10] * r[9] + m[11] * r[13];
result[10] = m[8] * r[2] + m[9] * r[6] + m[10] * r[10] + m[11] * r[14];
result[11] = m[8] * r[3] + m[9] * r[7] + m[10] * r[11] + m[11] * r[15];
result[12] = m[12] * r[0] + m[13] * r[4] + m[14] * r[8] + m[15] * r[12];
result[13] = m[12] * r[1] + m[13] * r[5] + m[14] * r[9] + m[15] * r[13];
result[14] = m[12] * r[2] + m[13] * r[6] + m[14] * r[10] + m[15] * r[14];
result[15] = m[12] * r[3] + m[13] * r[7] + m[14] * r[11] + m[15] * r[15];
}
void xs_matrix_multiplyVec4(xsMachine *the)
{
xsNumberValue wIn, xIn, yIn, zIn;
xsNumberValue wOut, xOut, yOut, zOut;
xsNumberValue *m;
xsUnsignedValue mSize;
xsSlot n;
xsmcVars(1);
xsmcGet(n, xsArg(0), xsID_w); wIn = xsmcToNumber(n);
xsmcGet(n, xsArg(0), xsID_x); xIn = xsmcToNumber(n);
xsmcGet(n, xsArg(0), xsID_y); yIn = xsmcToNumber(n);
xsmcGet(n, xsArg(0), xsID_z); zIn = xsmcToNumber(n);
xsmcGet(xsVar(0), xsThis, xsID_m);
xsmcGet(xsVar(0), xsVar(0), xsID_buffer);
xsmcGetBufferReadable(xsVar(0), (void **)&m, &mSize);
if (128 != mSize)
xsUnknownError("invalid");
xOut = m[0] * xIn + m[1] * yIn + m[2] * zIn + m[3] * wIn;
yOut = m[4] * xIn + m[5] * yIn + m[6] * zIn + m[7] * wIn;
zOut = m[8] * xIn + m[9] * yIn + m[10] * zIn + m[11] * wIn;
wOut = m[12] * xIn + m[13] * yIn + m[14] * zIn + m[15] * wIn;
xsmcSetNewObject(xsResult);
xsmcSetNumber(n, xOut); xsmcSet(xsResult, xsID_x, n);
xsmcSetNumber(n, yOut); xsmcSet(xsResult, xsID_y, n);
xsmcSetNumber(n, zOut); xsmcSet(xsResult, xsID_z, n);
xsmcSetNumber(n, wOut); xsmcSet(xsResult, xsID_w, n);
} I also tweaked function calcBounds(vertices: Vec4[]): Bounds {
let x1 = vertices[0].x, y1 = vertices[0].y, x2 = vertices[0].x, y2 = vertices[0].y;
for (let i = 0, length = vertices.length; i < length; i++) {
const v = vertices[i];
// +/-1 is due to width of stroke in Outline.stroke()
if (v.x <= x1) x1 = v.x - 1
if (v.x >= x2) x2 = v.x + 1
if (v.y <= y1) y1 = v.y - 1
if (v.y >= y2) y2 = v.y + 1
}
return {x1, x2, y1, y2}
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm working on an attitude sensor that tracks the roll & pitch of an ocean racing kayak (surfski) and in order to get a sense of the data quality I put together a little graphics demo using a moddable two. It's now showing signs of life :-).
Stuff used:
Code architecture:
Short demo video: https://tve.s3.amazonaws.com/public/imu-demo-20230610-1300.mp4
Getting 16fps rendering is pretty darn amazing, Poco rocks!
Beta Was this translation helpful? Give feedback.
All reactions