🧼 Refactors bezier gait

This commit is contained in:
Rune Harlyk
2024-11-07 15:43:33 +01:00
committed by Rune Harlyk
parent 87fe566d0d
commit da27ba37be
+136 -104
View File
@@ -25,7 +25,16 @@ export interface ControllerCommand {
export abstract class GaitState { export abstract class GaitState {
protected abstract name: string; protected abstract name: string;
protected static body_state: body_state_t; protected dt = 0.02;
protected body_state!: body_state_t;
protected gait_state: gait_state_t = {
step_height: 0.4,
step_x: 0,
step_z: 0,
step_angle: 0,
step_velocity: 1,
step_depth: 0.002
};
public get default_feet_pos() { public get default_feet_pos() {
return [ return [
@@ -47,18 +56,23 @@ export abstract class GaitState {
console.log('Ending', this.name); console.log('Ending', this.name);
} }
step(body_state: body_state_t, command: ControllerCommand, dt: number = 0.02) { step(body_state: body_state_t, command: ControllerCommand, dt: number = 0.02) {
this.map_command(command);
this.body_state = body_state;
this.dt = dt / 1000;
return body_state; return body_state;
} }
map_command(command: ControllerCommand): gait_state_t { map_command(command: ControllerCommand) {
return { const newCommand = {
step_height: 0.4 + Math.abs(command.ry / 128), step_height: 0.4,
step_x: (Math.floor(fromInt8(command.ly, -1, 1) * 10) / 10) * 3, step_x: Math.floor(fromInt8(command.ly, -1, 1) * 10) / 10,
step_z: -(Math.floor(fromInt8(command.lx, -1, 1) * 10) / 10) * 3, step_z: -(Math.floor(fromInt8(command.lx, -1, 1) * 10) / 10),
step_velocity: command.s / 128 + 1, step_velocity: command.s / 128 + 1,
step_angle: 0, step_angle: command.rx / 128,
step_depth: 0.2 step_depth: 0.002
}; };
this.gait_state = newCommand;
} }
} }
@@ -121,14 +135,8 @@ abstract class PhaseGaitState extends GaitState {
protected contact_phases!: number[][]; protected contact_phases!: number[][];
protected shifts!: number[][]; protected shifts!: number[][];
protected body_state!: body_state_t;
protected gait_state!: gait_state_t;
protected dt = 0.02;
step(body_state: body_state_t, command: ControllerCommand, dt: number = 0.02) { step(body_state: body_state_t, command: ControllerCommand, dt: number = 0.02) {
this.body_state = body_state; super.step(body_state, command, dt);
this.gait_state = this.map_command(command);
this.dt = dt / 1000;
this.update_phase(); this.update_phase();
this.update_body_position(); this.update_body_position();
this.update_feet_positions(); this.update_feet_positions();
@@ -260,7 +268,6 @@ export class BezierState extends GaitState {
protected name = 'Bezier'; protected name = 'Bezier';
protected phase = 0; protected phase = 0;
protected phase_num = 0; protected phase_num = 0;
protected dt = 0.02;
protected contact_phases = [ protected contact_phases = [
[1, 0], [1, 0],
[0, 1], [0, 1],
@@ -268,8 +275,6 @@ export class BezierState extends GaitState {
[1, 0] [1, 0]
]; ];
protected step_length: number = 0; protected step_length: number = 0;
protected body_state!: body_state_t;
protected gait_state!: gait_state_t;
begin() { begin() {
super.begin(); super.begin();
@@ -280,9 +285,7 @@ export class BezierState extends GaitState {
} }
step(body_state: body_state_t, command: ControllerCommand, dt: number = 0.02) { step(body_state: body_state_t, command: ControllerCommand, dt: number = 0.02) {
this.body_state = body_state; super.step(body_state, command, dt);
this.gait_state = this.map_command(command);
this.dt = dt / 1000;
this.step_length = Math.sqrt(this.gait_state.step_x ** 2 + this.gait_state.step_z ** 2); this.step_length = Math.sqrt(this.gait_state.step_x ** 2 + this.gait_state.step_z ** 2);
if (this.gait_state.step_x < 0) { if (this.gait_state.step_x < 0) {
this.step_length = -this.step_length; this.step_length = -this.step_length;
@@ -313,107 +316,136 @@ export class BezierState extends GaitState {
this.body_state.feet[index][0] = this.default_feet_pos[index][0]; this.body_state.feet[index][0] = this.default_feet_pos[index][0];
this.body_state.feet[index][1] = this.default_feet_pos[index][1]; this.body_state.feet[index][1] = this.default_feet_pos[index][1];
this.body_state.feet[index][2] = this.default_feet_pos[index][2]; this.body_state.feet[index][2] = this.default_feet_pos[index][2];
return contact ? this.swing(index) : this.stance(index); return contact ? this.swing_controller(index) : this.stand_controller(index);
} }
swing(index: number): number[] { stand_controller(index: number) {
const control_points = this.get_control_points(); let depth = this.gait_state.step_depth;
const t = this.phase; return this.controller(index, stance_curve, depth);
const n = control_points.length - 1; }
const point = [0, 0, 0]; swing_controller(index: number) {
for (let i = 0; i <= n; i++) { let height = this.gait_state.step_height;
const bernstein_poly = this.comb(n, i) * Math.pow(t, i) * Math.pow(1 - t, n - i); return this.controller(index, bezier_curve, height);
point[0] += bernstein_poly * control_points[i][0];
point[2] += bernstein_poly * control_points[i][1];
point[1] += bernstein_poly * control_points[i][2];
} }
this.body_state.feet[index][0] += point[0];
if (point[0] !== 0 || point[2] !== 0) { controller(
this.body_state.feet[index][1] += point[1]; index: number,
} controller: (length: number, angle: number, ...args: number[]) => number[],
this.body_state.feet[index][2] += point[2]; ...args: number[]
) {
let length = this.step_length / 2;
let angle = (this.gait_state.step_z * Math.PI) / 2;
const delta_pos = controller(length, angle, ...args, this.phase);
length = this.gait_state.step_angle * 2;
angle = yawArc(this.default_feet_pos[index], this.body_state.feet[index]);
const delta_rot = controller(length, angle, ...args, this.phase);
this.body_state.feet[index][0] += delta_pos[0] + delta_rot[0] * 0.2;
this.body_state.feet[index][2] += delta_pos[2] + delta_rot[2] * 0.2;
if (this.gait_state.step_x || this.gait_state.step_z || this.gait_state.step_angle)
this.body_state.feet[index][1] += delta_pos[1] + delta_rot[1] * 0.2;
return this.body_state.feet[index]; return this.body_state.feet[index];
} }
}
stance(index: number): number[] { const stance_curve = (length: number, angle: number, depth: number, phase: number): number[] => {
const t = this.phase; const X_POLAR = Math.cos(angle);
const L = this.step_length / 2; const Y_POLAR = Math.sin(angle);
const X_POLAR = Math.cos((this.gait_state.step_z * Math.PI) / 2); const step = length * (1 - 2 * phase);
const Y_POLAR = Math.sin((this.gait_state.step_z * Math.PI) / 2);
const step = L * (1 - 2 * t);
const X = step * X_POLAR; const X = step * X_POLAR;
const Y = step * Y_POLAR; const Y = step * Y_POLAR;
let Z = 0; let Z = 0;
if (L !== 0) { if (length !== 0) {
Z = -this.gait_state.step_depth * Math.cos((Math.PI * (X + Y)) / (2 * L)); Z = -depth * Math.cos((Math.PI * (X + Y)) / (2 * length));
}
return [X, Z, Y];
};
const yawArc = (default_foot_pos: number[], current_foot_pos: number[]): number => {
const foot_mag = Math.sqrt(default_foot_pos[0] ** 2 + default_foot_pos[2] ** 2);
const foot_dir = Math.atan2(default_foot_pos[2], default_foot_pos[0]);
const offsets = [
current_foot_pos[0] - default_foot_pos[0],
current_foot_pos[2] - default_foot_pos[2],
current_foot_pos[1] - default_foot_pos[1]
];
const offset_mag = Math.sqrt(offsets[0] ** 2 + offsets[2] ** 2);
const offset_mod = Math.atan2(offset_mag, foot_mag);
return Math.PI / 2.0 + foot_dir + offset_mod;
};
const bezier_curve = (length: number, angle: number, height: number, phase: number): number[] => {
const control_points = get_control_points(length, angle, height);
const n = control_points.length - 1;
const point = [0, 0, 0];
for (let i = 0; i <= n; i++) {
const bernstein_poly = comb(n, i) * Math.pow(phase, i) * Math.pow(1 - phase, n - i);
point[0] += bernstein_poly * control_points[i][0];
point[1] += bernstein_poly * control_points[i][1];
point[2] += bernstein_poly * control_points[i][2];
}
return point;
};
const get_control_points = (length: number, angle: number, height: number): number[][] => {
const X_POLAR = Math.cos(angle);
const Z_POLAR = Math.sin(angle);
const STEP = [
-length,
-length * 1.4,
-length * 1.5,
-length * 1.5,
-length * 1.5,
0.0,
0.0,
0.0,
length * 1.5,
length * 1.5,
length * 1.4,
length
];
const Y = [
0.0,
0.0,
height * 0.9,
height * 0.9,
height * 0.9,
height * 0.9,
height * 0.9,
height * 1.1,
height * 1.1,
height * 1.1,
0.0,
0.0
];
const control_points: number[][] = [];
for (let i = 0; i < STEP.length; i++) {
const X = STEP[i] * X_POLAR;
const Z = STEP[i] * Z_POLAR;
control_points.push([X, Y[i], Z]);
} }
this.body_state.feet[index][0] += X; return control_points;
this.body_state.feet[index][2] += Y; };
this.body_state.feet[index][1] += Z;
return this.body_state.feet[index]; const comb = (n: number, k: number): number => {
} if (k < 0 || k > n) return 0;
if (k === 0 || k === n) return 1;
comb(n: number, k: number): number {
if (k < 0 || k > n) {
return 0;
}
if (k === 0 || k === n) {
return 1;
}
k = Math.min(k, n - k); k = Math.min(k, n - k);
let c = 1; let c = 1;
for (let i = 0; i < k; i++) { for (let i = 0; i < k; i++) {
c = (c * (n - i)) / (i + 1); c = (c * (n - i)) / (i + 1);
} }
return c; return c;
} };
get_control_points(): number[][] {
const L = this.step_length / 2;
const CH = this.gait_state.step_height;
const STEP = [
-L,
-L * 1.4,
-L * 1.5,
-L * 1.5,
-L * 1.5,
0.0,
0.0,
0.0,
L * 1.5,
L * 1.5,
L * 1.4,
L
];
const X_POLAR = Math.cos((this.gait_state.step_z * Math.PI) / 2);
const Y_POLAR = Math.sin((this.gait_state.step_z * Math.PI) / 2);
const control_points: number[][] = [];
for (let i = 0; i < STEP.length; i++) {
const X = STEP[i] * X_POLAR;
const Y = STEP[i] * Y_POLAR;
let Z = 0.0;
if (i === 0 || i === 1 || i === 10 || i === 11) {
Z = 0.0;
} else if (i >= 2 && i <= 6) {
Z = CH * 0.9;
} else if (i >= 7 && i <= 9) {
Z = CH * 1.1;
}
control_points.push([X, Y, Z]);
}
return control_points;
}
}