Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Part 2 robot simulator #309

Merged
Merged
Show file tree
Hide file tree
Changes from 88 commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
1fb2d07
Initial commit
JoelChanZhiYang Aug 17, 2023
5e462fb
Add some permissions thing
JoelChanZhiYang Aug 17, 2023
fc7669f
Get the templating done for the modal up and down
JoelChanZhiYang Aug 17, 2023
b2f6fb9
Add permisisons to all
JoelChanZhiYang Aug 18, 2023
717b244
Add the first edition of rapier-three controller
JoelChanZhiYang Sep 19, 2023
dc92ae5
Initialization of my module
JoelChanZhiYang Sep 29, 2023
a650095
Make a cube
JoelChanZhiYang Sep 29, 2023
e22aa25
Add ambient light
JoelChanZhiYang Sep 29, 2023
03aeaff
Added the suspension forced
JoelChanZhiYang Sep 30, 2023
b44aa92
Remove car from init_meshes
JoelChanZhiYang Sep 30, 2023
08b90b5
Try to init
JoelChanZhiYang Sep 30, 2023
e8c0801
Change init
JoelChanZhiYang Sep 30, 2023
8e1cd5b
Added the iterator
JoelChanZhiYang Oct 7, 2023
81b1640
Add realistic dimensions and weight to the car
JoelChanZhiYang Oct 9, 2023
573be08
Massive changes
JoelChanZhiYang Oct 27, 2023
ff86553
Massive changes again
JoelChanZhiYang Nov 7, 2023
e7789c1
motor done
JoelChanZhiYang Nov 11, 2023
a28a949
changed
JoelChanZhiYang Nov 12, 2023
f3ae8fa
fix type
JoelChanZhiYang Nov 12, 2023
5fb4005
Clean up code
JoelChanZhiYang Nov 13, 2023
cd792e5
Formatting
JoelChanZhiYang Nov 15, 2023
d9a85d5
Move buffer
JoelChanZhiYang Nov 18, 2023
771dfd8
Change the wheel
JoelChanZhiYang Nov 21, 2023
f12cbec
Add the interception
JoelChanZhiYang Nov 21, 2023
aad793d
MAssive push
JoelChanZhiYang Jan 21, 2024
2543145
Added color sensor
JoelChanZhiYang Jan 22, 2024
d221978
Change folder name
JoelChanZhiYang Jan 25, 2024
adc4116
Remove console.log for impulse
JoelChanZhiYang Jan 25, 2024
56d0dcc
Add ultrasonic sensor
JoelChanZhiYang Jan 26, 2024
5fbf829
Minor changes to ultrasonic sensor
JoelChanZhiYang Jan 26, 2024
96a552c
Achieved determinism
JoelChanZhiYang Jan 29, 2024
be35a0c
Add ultrasonic motor function
JoelChanZhiYang Feb 4, 2024
893ae07
Add new event handler and event console
JoelChanZhiYang Feb 28, 2024
142b49b
Merge branch 'master' into robot-simulator__rapier-master
JoelChanZhiYang Feb 28, 2024
97a1946
Remove unneeded files
JoelChanZhiYang Feb 28, 2024
25a52a5
Minor modifications so that js-slang/context is not imported
JoelChanZhiYang Feb 28, 2024
74f8837
Add @types/three
JoelChanZhiYang Feb 29, 2024
78759a0
Update threejs
JoelChanZhiYang Feb 29, 2024
9faf350
Change mesh to without wheels
JoelChanZhiYang Feb 29, 2024
2975a6e
Add console
JoelChanZhiYang Feb 29, 2024
df94dab
Add wheel mesh logic
JoelChanZhiYang Mar 1, 2024
aef9f24
Add a bunch of test
JoelChanZhiYang Mar 1, 2024
1483717
Did partial tuning of the motor
JoelChanZhiYang Mar 1, 2024
972b4d4
Change the way the timing is done
JoelChanZhiYang Mar 1, 2024
405313b
Make CallbackHandler deterministic
JoelChanZhiYang Mar 2, 2024
6fe3315
Make wall yellow
JoelChanZhiYang Mar 2, 2024
5dbf490
Fix the program identifier bug and callback controller determinism
JoelChanZhiYang Mar 4, 2024
39e85dc
Fix controller bug and add test
JoelChanZhiYang Mar 4, 2024
9fc7ac4
Make Three implement SimpleVector and MeshFactory tests
JoelChanZhiYang Mar 4, 2024
b8d7212
Add a comment in jest polyfills
JoelChanZhiYang Mar 7, 2024
e5d247d
Function clean ups
JoelChanZhiYang Mar 10, 2024
ed0a5d2
Change the paths in the tests
JoelChanZhiYang Mar 10, 2024
31f9ade
Make the lighting nicer
JoelChanZhiYang Mar 11, 2024
3ef42ef
Add Paper and DebugArrow
JoelChanZhiYang Mar 11, 2024
a4a0624
Massive refactor
JoelChanZhiYang Mar 11, 2024
c7610cf
Fix Mesh Factory test
JoelChanZhiYang Mar 11, 2024
d219432
Update tests
JoelChanZhiYang Mar 12, 2024
5d0dabf
Add docs for ev3_functions
JoelChanZhiYang Mar 12, 2024
0b79cf4
Add documentation for ev3_pause
JoelChanZhiYang Mar 18, 2024
a67f22c
Merge branch 'master' into robot-simulator__rapier-master
JoelChanZhiYang Mar 18, 2024
9d80574
Change the version of three
JoelChanZhiYang Mar 23, 2024
5283469
Merge branch 'master' into robot-simulator__rapier-master
JoelChanZhiYang Mar 27, 2024
51b20c4
Change the quotes from double to single
JoelChanZhiYang Mar 27, 2024
5f43378
Remove part 2 from robot simulator
JoelChanZhiYang Mar 27, 2024
dfc2bf3
Remove unused libraries in package.json
JoelChanZhiYang Mar 27, 2024
20d9107
Fix eslint errors
JoelChanZhiYang Mar 27, 2024
45af6f8
Fix more eslint errors
JoelChanZhiYang Mar 27, 2024
64dbf7d
Fix more eslint errors
JoelChanZhiYang Mar 27, 2024
9b594b3
More linting errors
JoelChanZhiYang Mar 27, 2024
097e45d
update yarn.lock
JoelChanZhiYang Mar 27, 2024
51210f2
Change the react components to React.FC
JoelChanZhiYang Mar 27, 2024
25f1208
Remove the empty file
JoelChanZhiYang Mar 27, 2024
3820da0
More formatting changes
JoelChanZhiYang Mar 27, 2024
ace2317
Change RecursivePartial to DeepPartial
JoelChanZhiYang Mar 28, 2024
bbf6f52
Revert "Remove part 2 from robot simulator"
JoelChanZhiYang Apr 1, 2024
0559705
Add configuation to Program controller
JoelChanZhiYang Apr 1, 2024
ec9e594
Documentation for the functions
JoelChanZhiYang Apr 12, 2024
97eb970
Add tests
JoelChanZhiYang Apr 13, 2024
1d7003c
Minor changes to tests
JoelChanZhiYang Apr 13, 2024
3443ebb
Fix up the tabs
JoelChanZhiYang Apr 13, 2024
989d6ff
Add some ev3 functions
JoelChanZhiYang Apr 13, 2024
746ddb7
Add category
JoelChanZhiYang Apr 13, 2024
2836ac0
Merge branch 'master' into part_2_robot_simulator
JoelChanZhiYang Apr 15, 2024
53869e0
Minor change to ultrasonic sense()
JoelChanZhiYang Apr 15, 2024
5f4930f
Uncomment test in Program
JoelChanZhiYang Apr 15, 2024
af11020
Make paper position movable
JoelChanZhiYang Apr 16, 2024
67d7c38
Make some changes to colorSensor
JoelChanZhiYang Apr 16, 2024
a288331
Add better docs
JoelChanZhiYang Apr 16, 2024
492af2b
Add configuration to the wall function
JoelChanZhiYang Apr 20, 2024
3f25173
Fix lockfile
JoelChanZhiYang Apr 22, 2024
94739f1
Linting in evaluate
JoelChanZhiYang Apr 22, 2024
2d4e454
React FC added and fixed spelling
JoelChanZhiYang Apr 22, 2024
4d5b9f4
Fix lint
JoelChanZhiYang Apr 22, 2024
6ce6ed3
Add residual factor to the simulation
JoelChanZhiYang Apr 22, 2024
82c67f1
Change physics test
JoelChanZhiYang Apr 22, 2024
da83ed1
Update mesh logic
JoelChanZhiYang Apr 22, 2024
eec2e39
Remove unused ESLint disable directive
RichDom2185 Apr 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/__mocks__/emptyModule.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import * as THREE from 'three';
import { Physics, Renderer, EntityFactory , MeshFactory } from '../../../../engine';

import { ChassisWrapper } from '../../../ev3/components/Chassis';

jest.mock('../../../../engine', () => ({
Physics: jest.fn(),
Renderer: jest.fn(),
EntityFactory: { addCuboid: jest.fn() },
MeshFactory: { addCuboid: jest.fn() }
}));
jest.mock('../../../../engine/Entity/EntityFactory');

jest.mock('three', () => {
const three = jest.requireActual('three');
return {
...three,
Mesh: jest.fn().mockImplementation(() => ({
position: { copy: jest.fn() },
quaternion: { copy: jest.fn() },
visible: false,
})),
Color: jest.fn()
};
});

const mockedMeshFactory = MeshFactory as jest.Mocked<typeof MeshFactory>;
const mockedEntityFactory = EntityFactory as jest.Mocked<typeof EntityFactory>;

describe('ChassisWrapper', () => {
let physicsMock;
let rendererMock;
let chassisWrapper;
let config;

beforeEach(() => {
physicsMock = jest.fn() as unknown as Physics;
rendererMock = {add:jest.fn()} as unknown as Renderer;
config = {
dimension: { width: 1, height: 1, depth: 1 },
orientation: { x: 0, y: 0, z: 0, w: 1 },
debug: true
};

mockedMeshFactory.addCuboid.mockReturnValue(new THREE.Mesh());
chassisWrapper = new ChassisWrapper(physicsMock, rendererMock, config);

});

it('should initialize with a debug mesh if debug is true', () => {
expect(MeshFactory.addCuboid).toHaveBeenCalledWith({
orientation: config.orientation,
dimension: config.dimension,
color: expect.any(THREE.Color),
debug: true
});
expect(rendererMock.add).toBeCalled();
expect(chassisWrapper.debugMesh.visible).toBe(true);
});

it('should throw if getEntity is called before chassis is initialized', () => {
expect(chassisWrapper.chassis).toBe(null);
expect(() => chassisWrapper.getEntity()).toThrow('Chassis not initialized');
});

it('should correctly initialize the chassis entity on start', async () => {
const mockEntity = { getTranslation: jest.fn(), getRotation: jest.fn() };
mockedEntityFactory.addCuboid.mockReturnValue(mockEntity as any);
await chassisWrapper.start();

expect(chassisWrapper.chassis).toBe(mockEntity);
expect(EntityFactory.addCuboid).toHaveBeenCalledWith(physicsMock, config);
});

it('should update the position and orientation of the debug mesh to match the chassis entity', () => {
const mockEntity = {
getTranslation: jest.fn().mockReturnValue(new THREE.Vector3()),
getRotation: jest.fn().mockReturnValue(new THREE.Quaternion())
};
mockedEntityFactory.addCuboid.mockReturnValue(mockEntity as any);
chassisWrapper.chassis = mockEntity;

chassisWrapper.update();

expect(chassisWrapper.debugMesh.position.copy).toHaveBeenCalledWith(mockEntity.getTranslation());
expect(chassisWrapper.debugMesh.quaternion.copy).toHaveBeenCalledWith(mockEntity.getRotation());
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import * as THREE from 'three';
import { Renderer } from '../../../../engine';
import { loadGLTF } from '../../../../engine/Render/helpers/GLTF';
import { ChassisWrapper } from '../../../ev3/components/Chassis';
import { Mesh } from '../../../ev3/components/Mesh';

jest.mock('three', () => {
const three = jest.requireActual('three');
return {
...three,
GLTF: jest.fn().mockImplementation(() => ({
scene: {},
})),
};
});

jest.mock('../../../../engine/Render/helpers/GLTF', () => ({
loadGLTF: jest.fn().mockResolvedValue({
scene: {
position: {
copy: jest.fn(),
},
quaternion: {
copy: jest.fn(),
},
},
}),
}));

jest.mock('../../../ev3/components/Chassis', () => ({
ChassisWrapper: jest.fn().mockImplementation(() => ({
getEntity: jest.fn().mockReturnValue({
getTranslation: jest.fn().mockReturnValue(new THREE.Vector3()),
getRotation: jest.fn().mockReturnValue(new THREE.Quaternion()),
}),
})),
}));

jest.mock('../../../../engine', () => ({
Renderer: jest.fn().mockImplementation(() => ({
add: jest.fn(),
})),
}));

describe('Mesh', () => {
let mesh;
let mockChassisWrapper;
let mockRenderer;
let mockConfig;

beforeEach(() => {
mockRenderer = { add: jest.fn() } as unknown as Renderer;
mockChassisWrapper = {
getEntity: jest.fn().mockReturnValue({
getTranslation: jest.fn().mockReturnValue(new THREE.Vector3()),
getRotation: jest.fn().mockReturnValue(new THREE.Quaternion()),
}),
} as unknown as ChassisWrapper;
mockConfig = {
url: 'path/to/mesh',
dimension: { width: 1, height: 2, depth: 3 },
offset: { x: 0.5, y: 0.5, z: 0.5 },
};

// mockLoadGLTF.mockResolvedValue({
// scene: new THREE.GLTF().scene
// } as any);

mesh = new Mesh(mockChassisWrapper, mockRenderer, mockConfig);
});

it('should initialize correctly with given configurations', () => {
expect(mesh.config.url).toBe(mockConfig.url);
expect(mesh.offset.x).toBe(0.5);
});

it('should load the mesh and add it to the renderer on start', async () => {
await mesh.start();
expect(loadGLTF).toHaveBeenCalledWith(mockConfig.url, mockConfig.dimension);
expect(mockRenderer.add).toHaveBeenCalledWith(expect.any(Object)); // Checks if mesh scene is added to renderer
});

it('should update mesh position and orientation according to chassis', async () => {
await mesh.start();
mesh.update();

const chassisEntity = mockChassisWrapper.getEntity();
expect(chassisEntity.getTranslation).toHaveBeenCalled();
expect(chassisEntity.getRotation).toHaveBeenCalled();
expect(mesh.mesh.scene.position.copy).toHaveBeenCalled();
expect(mesh.mesh.scene.quaternion.copy).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import * as THREE from 'three';
import { Renderer, Physics } from '../../../../engine';
import { loadGLTF } from '../../../../engine/Render/helpers/GLTF';
import { ChassisWrapper } from '../../../ev3/components/Chassis';
import { Motor } from '../../../ev3/components/Motor';
import { ev3Config } from '../../../ev3/ev3/default/config';

jest.mock('three', () => {
const originalModule = jest.requireActual('three');
return {
...originalModule,
};
});

jest.mock('../../../../engine/Render/helpers/GLTF', () => ({
loadGLTF: jest.fn().mockResolvedValue({
scene: {
position: {
copy: jest.fn(),
},
quaternion: {
copy: jest.fn(),
},
rotateX: jest.fn(),
rotateZ: jest.fn()
}
}),
}));

jest.mock('../../../../engine', () => ({
Physics: jest.fn(),
Renderer: jest.fn().mockImplementation(() => ({
add: jest.fn(),
})),
}));

jest.mock('../../../ev3/components/Chassis', () => ({
ChassisWrapper: jest.fn().mockImplementation(() => ({
getEntity: jest.fn().mockReturnValue({
transformDirection: jest.fn().mockImplementation((v) => v),
worldVelocity: jest.fn().mockReturnValue(new THREE.Vector3()),
worldTranslation: jest.fn().mockReturnValue(new THREE.Vector3()),
applyImpulse: jest.fn(),
getMass: jest.fn().mockReturnValue(1),
getRotation: jest.fn(),
}),
})),
}));

describe('Motor', () => {
let motor;
let mockChassisWrapper;
let mockPhysics;
let mockRenderer;
let mockConfig;

beforeEach(() => {
mockPhysics = {
applyImpulse: jest.fn(),
} as unknown as Physics;
mockRenderer = { add: jest.fn() } as unknown as Renderer;
mockConfig = {
displacement: { x: 1, y: 0, z: 0 },
pid: {
proportionalGain: 1,
integralGain: 0.1,
derivativeGain: 0.01,
},
mesh: {
url: 'path/to/mesh',
dimension: { height: 1, width: 1, depth: 1 },
},
};
const config = ev3Config.motors[0];
mockChassisWrapper = new ChassisWrapper(mockPhysics, mockRenderer, config);
motor = new Motor(
mockChassisWrapper,
mockPhysics,
mockRenderer,
mockConfig
);
});

it('should initialize correctly and load the mesh', async () => {
await motor.start();
expect(loadGLTF).toHaveBeenCalledWith(
mockConfig.mesh.url,
mockConfig.mesh.dimension
);
expect(mockRenderer.add).toHaveBeenCalled();
});

it('sets motor velocity and schedules stop with distance', () => {
motor.setSpeedDistance(10, 100);
expect(motor.motorVelocity).toBe(10);
});

it('updates the motor velocity and applies impulse', () => {
motor.fixedUpdate({ deltaTime: 1 });
expect(mockChassisWrapper.getEntity().applyImpulse).toHaveBeenCalled();
});

it('updates mesh', async () => {
await motor.start();
motor.update({frameDuration: 1});

expect(motor.mesh.scene.position.copy).toBeCalled();
expect(motor.mesh.scene.quaternion.copy).toBeCalled();
});

it('rotates the mesh if on the left side', async () => {
motor.wheelSide = 'left';
await motor.start();
motor.update({frameDuration: 1});

expect(motor.mesh.scene.rotateZ).toBeCalled();
});
});
Loading
Loading