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.
-
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