Files
metacar/src/control_motion_engine.ts
T
2018-06-25 09:38:11 +01:00

191 lines
5.7 KiB
TypeScript

import { MotionEngine, actionSpaceDescription } from "./motion_engine";
import {Level} from "./level";
import {
MAP, ROADSIZE
} from "./global";
import * as U from "./utils";
export class ControlMotionEngine extends MotionEngine {
private actions: (string|number)[];
private maxSpeed: number = 2.0;
constructor(level: Level) {
/*
@level (Level class)
@options (Object) Option to build the motion engine
@rotation_step: Between 0 and 2. (rotation_step*Pi)
@actions: List of possible actions (Left, Right, Up, Down, Wait)
*/
super(level);
this.level = level;
this.actions = ["SteeringAngle", "Throttle"]
}
setUp(car: any, lidar: any){
/*
Setup the motion engine
@car: (Vehicle Object)
@lidar: (Lidar Object)
*/
this.car = car;
this.lidar = lidar;
// Init the lidar state
this.state = [];
for (let y = 0; y < lidar.pts; y++) {
let line = [];
for (let x = 0; x < lidar.pts; x++) {
line.push(MAP.DEFAULT);
}
this.state.push(line);
}
// Set up keyboard interaction
this.setUpKeyboard();
// Setup up velocity to 0
this.car.v = 0;
this.car.a = 0; // Acceleration
this.car.yaw_rate = 0;
this.detectInteractions();
}
setUpKeyboard(){
/*
Setup possible keyboard interactions
*/
let left = U.keyboard(37);
let up = U.keyboard(38);
let right = U.keyboard(39);
let down = U.keyboard(40);
left.press = () => {
this.turn(-0.7);
};
left.release = () => {
this.turn(0);
};
right.press = () => {
this.turn(0.7);
};
right.release = () => {
this.turn(0);
};
// Move forward
up.press = () => { this.move(1); };
up.release = () => {
this.car.a = 0;
};
// Move backward
down.press = () => { this.move(-1);};
down.release = () => {
this.car.a = 0;
};
}
turn(value: number){
/*
Turn
@value: yaw_rate value Between -1 and 1
*/
this.car.yaw_rate = value;
}
move(throttle: number){
/*
Move forward
@throttle throttle value Between -1 and 1
*/
this.car.a = throttle;
}
actionStep(delta: number, actions: number[]){
/*
Step into the environement with one action
@delta (Float) time since the last update
@action: (Array of Float) The throttle and the steering angle
*/
this.car.a = Math.min(Math.max(actions[0], -1), 1);
this.car.yaw_rate = Math.min(Math.max(actions[1], -1), 1);
let {agentCollisions, onRoad} = this.step(delta);
this.car.a = 0;
this.car.yaw_rate = 0;
return {agentCollisions, onRoad};
}
/**
* Return a description of the action space.
*/
public actionSpace(): actionSpaceDescription {
return {
type: "Continous",
size: 2,
range: [[0., 1.], [-1., 1.]]
}
}
step(delta: number){
/*
Step into the environement
@delta (Float) time since the last update
*/
this.car.last_a = this.car.a;
this.car.last_yaw_rate = this.car.yaw_rate;
// The car lose speed over time
if (this.car.v > 0 && this.car.a == 0)
this.car.v = Math.max(0, this.car.v - 0.01);
else if (this.car.v < 0 && this.car.a == 0)
this.car.v = Math.min(0, this.car.v + 0.01);
if (this.car.a > 0 && this.car.v >= 0)
this.car.v = Math.min(this.maxSpeed, this.car.v + this.car.a*0.005);
else if (this.car.a > 0 && this.car.v < 0){
this.car.v = Math.min(this.maxSpeed, this.car.v + this.car.a*0.03);
}
if (this.car.a < 0 && this.car.v <= 0)
this.car.v = Math.max(-this.maxSpeed, this.car.v + this.car.a*0.005);
else if (this.car.a < 0 && this.car.v > 0){
this.car.v = Math.max(-this.maxSpeed, this.car.v + this.car.a*0.03);
}
if (this.car.yaw_rate == 0){
this.car.x += this.car.v * Math.cos(this.car.rotation)*delta;
this.car.y += this.car.v * Math.sin(this.car.rotation)*delta;
}
else{
// Rewrite the yaw rate
let yr = this.car.yaw_rate*0.01*(this.car.v+0.001)*Math.PI;
this.car.x += (this.car.v/yr)*(Math.sin(this.car.rotation+(yr*delta)) - Math.sin(this.car.rotation));
this.car.y += (this.car.v/yr)*(Math.cos(this.car.rotation) - Math.cos(this.car.rotation+(yr*delta)));
this.car.rotation += yr*delta;
}
// Update the x and x position according to the map
this.car.mx = Math.floor(this.car.x / ROADSIZE);
this.car.my = Math.floor(this.car.y / ROADSIZE);
// Set the new road of the car (if changed)
this.car.checkAndsetNewRoad();
// Be sure to keep the lidar position at the same position than the car
this.lidar.x = this.car.x;
this.lidar.y = this.car.y;
this.lidar.rotation = this.car.rotation;
// Detection the new collision with the environement
let {agentCollisions, onRoad} = this.detectInteractions(true, true);
if (agentCollisions.length > 0){ // Stop the vehicle if a collision is detected
this.car.v = 0;
this.car.vy = 0;
}
return {agentCollisions, onRoad};
}
}