-
Notifications
You must be signed in to change notification settings - Fork 20
Illustrative ex for viz #11
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
base: master
Are you sure you want to change the base?
Changes from 24 commits
06398c4
11a0059
d5f2d44
a61e602
e69d5cf
89db91f
b10d0e5
b1a923c
aa6a338
17f8f0b
5a79f75
134bf88
f769203
31e7b65
7c348e9
9c10bf6
bcbca28
f0aa71b
3c82531
8441d29
ae2a57b
e60fe75
f950c97
cb5ba46
8314218
d11bd84
5ef35c4
733f2ca
85b715e
9fcf6bb
4ea2488
0fec414
18ad2b2
cde87c8
53bddd4
896a29f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| TO Run the script, directly run illustrat0ve_example.py | ||
|
|
||
| python illustrative_example.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| #!/usr/bin/env python | ||
|
|
||
| from sympy import Dummy, lambdify | ||
| from sympy.external import import_module | ||
|
|
||
| np = import_module('numpy') | ||
|
|
||
| def numeric_right_hand_side(kane, parameters): | ||
| """Returns the right hand side of the first order ordinary differential | ||
| equations from a KanesMethod system which can be evaluated numerically. | ||
|
|
||
| This function probably only works for simple cases (no dependent speeds, | ||
| specified functions). | ||
|
|
||
| """ | ||
|
|
||
| dynamic = kane._q + kane._u | ||
| dummy_symbols = [Dummy() for i in dynamic] | ||
| dummy_dict = dict(zip(dynamic, dummy_symbols)) | ||
| kindiff_dict = kane.kindiffdict() | ||
|
|
||
| M = kane.mass_matrix_full.subs(kindiff_dict).subs(dummy_dict) | ||
| F = kane.forcing_full.subs(kindiff_dict).subs(dummy_dict) | ||
|
|
||
| M_func = lambdify(dummy_symbols + parameters, M) | ||
| F_func = lambdify(dummy_symbols + parameters, F) | ||
|
|
||
| def right_hand_side(x, t, args): | ||
| """Returns the derivatives of the states. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| x : ndarray, shape(n) | ||
| The current state vector. | ||
| t : float | ||
| The current time. | ||
| args : ndarray | ||
| The constants. | ||
|
|
||
| Returns | ||
| ------- | ||
| dx : ndarray, shape(2 * (n + 1)) | ||
| The derivative of the state. | ||
|
|
||
| """ | ||
| arguments = np.hstack((x, args)) | ||
| dx = np.array(np.linalg.solve(M_func(*arguments), | ||
| F_func(*arguments))).T[0] | ||
|
|
||
| return dx | ||
|
|
||
| return right_hand_side | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| #This file contains all the essential methods for the | ||
| #illustrative example | ||
| #It only contains the basic implementations of pydy-viz | ||
| #also it doesnot check for TypeErrors etc. | ||
| from sympy.matrices.expressions import Identity | ||
| from sympy import lambdify, Dummy | ||
| from server import create_server | ||
| from numpy import hstack, ones, zeros | ||
|
|
||
|
|
||
| class Cylinder(object): | ||
|
|
||
| def __init__(self, name, radius=1, height=1, color='grey'): | ||
| self._name = name | ||
| self._radius = radius | ||
| self._height = height | ||
| self._color = color | ||
|
|
||
| @property | ||
| def name(self): | ||
| return self._name | ||
|
|
||
| @name.setter | ||
| def name(self, new_name): | ||
| self._name = new_name | ||
|
|
||
| @property | ||
| def color(self): | ||
| return self._color | ||
|
|
||
| @color.setter | ||
| def color(self, new_color): | ||
| self._color = new_color | ||
|
|
||
| def generate_data(self): | ||
| self._data = {} | ||
| self._data['type'] = 'Cylinder' | ||
| self._data['name'] = self.name | ||
| self._data['radius'] = self._radius | ||
| self._data['height'] = self._height | ||
| self._data['color'] = self.color | ||
| return self._data | ||
|
|
||
|
|
||
| class VisualizationFrame(object): | ||
| def __init__(self, name, rigidbody, shape=None): | ||
| #It is only to be used for rigidbody here, as per the | ||
| #specific requirements of the illustrative example | ||
| self._name = name | ||
| self._reference_frame = rigidbody.get_frame() | ||
| self._origin = rigidbody.get_masscenter() | ||
| self._shape = shape | ||
| # I don't think the identity matrix is a correct default. The | ||
| # transloation portion should be all zeros. | ||
| self._transform = Identity(4).as_mutable() | ||
|
|
||
| def transform(self, reference_frame, point): | ||
| # TODO : make sure this actually works correctly | ||
|
||
| _rotation_matrix = self._reference_frame.dcm(reference_frame) | ||
|
|
||
| self._transform[0:3, 0:3] = _rotation_matrix[0:3, 0:3] | ||
|
|
||
| _point_vector = self._origin.pos_from(point).express(reference_frame) | ||
|
|
||
| self._transform[3, 0] = _point_vector.dot(reference_frame.x) | ||
| self._transform[3, 1] = _point_vector.dot(reference_frame.y) | ||
| self._transform[3, 2] = _point_vector.dot(reference_frame.z) | ||
|
|
||
| return self._transform | ||
|
|
||
| def generate_numeric_transform(self, dynamic, parameters): | ||
| """Returns a function which returns a transformation matrix given | ||
| the symbolic states and the symbolic system parameters.""" | ||
|
|
||
| dummy_symbols = [Dummy() for i in dynamic] | ||
|
||
| dummy_dict = dict(zip(dynamic, dummy_symbols)) | ||
| transform = self._transform.subs(dummy_dict) | ||
|
|
||
| self.numeric_transform = lambdify(dummy_symbols + parameters, | ||
| transform, modules="numpy") | ||
|
||
|
|
||
| def evaluate_numeric_transform(self, states, parameters): | ||
| """Returns the numerical transformation matrices for each time step. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| states : array_like, shape(m,) or shape(n, m) | ||
| The m states for each n time step. | ||
| parameters : array_like, shape(p,) | ||
| The p constant parameters of the system. | ||
|
|
||
| Returns | ||
| ------- | ||
| transform_matrix : numpy.array, shape(n, 4, 4) | ||
| A 4 x 4 transformation matrix for each time step. | ||
|
|
||
| """ | ||
|
|
||
| if len(states.shape) > 1: | ||
| n = states.shape[0] | ||
| # first create a shape(n, m + p) matrix | ||
| # states : n x m | ||
| # parameters : p | ||
| # ones : n x p | ||
| #a = ones((n, len(parameters))) | ||
| #b = a * parameters | ||
| #c = hstack((states, b)) | ||
| #d = c.T | ||
| #e = list(d) | ||
| #args = list(hstack((states, ones((n, len(parameters))) * | ||
|
||
| #parameters)).T) | ||
|
|
||
| # this is a slow way to do things. technically numeric_transform | ||
| # should take states shape(n, m) or states shape(m,) and still | ||
| # work, but there are some issues in lambdify and I'm not sure | ||
| # what the deal is. I think we need to check lambdify for sympy | ||
| # matrices but offer a numpy array output then we could evaulate | ||
| # these much faster | ||
| new = zeros((n, 4, 4)) | ||
| for i, time_instance in enumerate(states): | ||
| args = hstack((time_instance, parameters)) | ||
| new[i, :, :] = self.numeric_transform(*args) | ||
|
|
||
| else: | ||
| args = hstack((states, parameters)) | ||
| new = self.numeric_transform(*args) | ||
|
|
||
| self.simulation_matrix = new | ||
|
|
||
| def generate_simulation_dict(self): | ||
| self._data = {} | ||
| self._data['name'] = self._name | ||
| self._data['shape'] = {} | ||
| self._data['shape'] = self._shape.generate_data() # hidden method | ||
| self._data['simulation_matrix'] = self.simulation_matrix.tolist() | ||
| return self._data | ||
|
|
||
|
|
||
| class Scene(): | ||
| def __init__(self, name, reference_frame, origin, height=400, width=400): | ||
| self._name = name | ||
| self._reference_frame = reference_frame | ||
| self._origin = origin # contains point | ||
| self._child_frames = [] | ||
| self._height = height | ||
| self._width = width | ||
|
|
||
| def add_visualization_frames(self, *vframes): | ||
| for _vframe in vframes: | ||
| self._child_frames.append(_vframe) | ||
|
|
||
| def add_visualization_frame(self, vframe): | ||
| self._child_frames.append(vframe) | ||
|
|
||
| def generate_json(self, state_sym, par_sym, states, parameters): | ||
|
||
|
|
||
| self._scene_data = {} | ||
| self._scene_data['name'] = self._name | ||
| self._scene_data['height'] = self._height | ||
| self._scene_data['width'] = self._width | ||
| self._scene_data['frames'] = [] | ||
|
|
||
| for frame in self._child_frames: | ||
|
|
||
| frame.transform(self._reference_frame, self._origin) | ||
| frame.generate_numeric_transform(state_sym, par_sym) | ||
| frame.evaluate_numeric_transform(states, parameters) | ||
| self._scene_data['frames'].append(frame.generate_simulation_dict()) | ||
|
|
||
| return self._scene_data | ||
|
|
||
| def display(self): | ||
| print("Your visualization is available at http://127.0.0.1/8000 \n \ | ||
| Visit it in your favourite browser to see your visualization \ | ||
| in all its glory. \n \ | ||
| Starting Server at 8000") | ||
| create_server(port=8000) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| #Export method calls and namespace | ||
| # from three_link_pendulum example .. | ||
|
|
||
| from three_link_pendulum import I, O, link1, link2, link3, kane | ||
| from essential import Cylinder, VisualizationFrame, Scene | ||
| from simulate import params, states, param_vals | ||
| from server import create_server | ||
| import json | ||
|
|
||
| # setting some shapes for the pendulums .. | ||
| shape1 = Cylinder('shape1', radius=1.0, height=10.0, color='red') | ||
| shape2 = Cylinder('shape2', radius=1.0, height=10.0, color='blue') | ||
| shape3 = Cylinder('shape3', radius=1.0, height=10.0, color='green') | ||
|
|
||
| # setting up some vframes ... | ||
| frame1 = VisualizationFrame('frame1', link1, shape=shape1) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is there no point defintion here? Don't you need a vector to locate the VizFrame in the Scene?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The point is taken automatically from link1, which is a rigidbody.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, so why do all the links show up in the same position in the visualization? Shouldn't they be spaced out and look like a chain of cylinders? Also, add spheres for the three particles. |
||
| frame2 = VisualizationFrame('frame2', link2, shape=shape2) | ||
| frame3 = VisualizationFrame('frame3', link3, shape=shape3) | ||
|
|
||
| scene = Scene('scene1', I, O, height=800, width=800) | ||
| scene.add_visualization_frames(frame1, frame2, frame3) | ||
|
|
||
| print('Generating transform time histories.') | ||
| data = scene.generate_json(kane._q + kane._u, params, states, param_vals) | ||
| print('Done.') | ||
| f = open('js/output.json', 'w') | ||
|
|
||
| print data | ||
| print json.dumps(data, indent=4, separators=(',', ': ')) | ||
|
|
||
| f.write('var JSONObj=' + json.dumps(data, indent=4, separators=(',', ': '))) | ||
|
|
||
| f.close() | ||
|
|
||
| create_server() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| <html> | ||
| <head> | ||
| <title>My first Three.js app</title> | ||
| <style>my-canvas { width: 400px; height: 400px }</style> | ||
| <script src="js/libs/jquery.js"></script> | ||
| <script src="js/libs/three.min.js"></script> | ||
| <script src="js/libs/TrackballControls.js"></script> | ||
| <script src="js/output.json"></script> | ||
| <script src="js/canvas.js"></script> | ||
|
|
||
| </head> | ||
| <body> | ||
|
|
||
|
|
||
|
|
||
| <div id='my-canvas'><div id='canvas'></div> | ||
| sdfdf</div> | ||
|
||
|
|
||
| <script type="text/javascript"> | ||
| alert('Welcome to pydy-viz simulator, \n You can use mouse controls on the visualization '); | ||
|
|
||
| var s = new Canvas(JSONObj); | ||
| s.initialize(); | ||
| s.add_visualization_frames(); | ||
| s.visualize(); | ||
| s.run_animation(); | ||
|
|
||
|
|
||
| </script> | ||
| </body> | ||
| </html> | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we call this
state_derivatives()? From what Tarun has said before, this is not actually going to be part of the code gen module, but maybe we can get started down the path of calling itstate_derivatives.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a filler function for Tarun to use. I'm working on a code_gen module that will be robust and nice. I'll send out what I've got soon for comments. For now, don't worry about this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh okay. I look forward to seeing that!