Skip to content
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
06398c4
Added a 3 link pendulum problem, with massless links. and
tarzzz Jun 18, 2013
11a0059
Added README
tarzzz Jun 18, 2013
d5f2d44
Update three_link_pendulum.py
tarzzz Jun 18, 2013
a61e602
Modified script for two dimensional joints
tarzzz Jun 19, 2013
e69d5cf
Merge branch '3-link-pendulum' of https://github.com/tarzzz/pydy_exam…
tarzzz Jun 19, 2013
89db91f
Added an illustrative example to demonstrate the workflow of
tarzzz Jun 19, 2013
b10d0e5
Updated to include code according to PEP8 style guide
tarzzz Jun 23, 2013
b1a923c
[WIP] Added some base classes for the illustrative example
Jul 9, 2013
aa6a338
[WIP] Some error in the numerical integration of the problem.
Jul 10, 2013
17f8f0b
WIP
Jul 12, 2013
5a79f75
[WIP] Python part nearly complete, some problems with json serialization
Jul 12, 2013
134bf88
WIP
Jul 12, 2013
f769203
[WIP] Completed Python side, although in a dirty way, with some hacks
Jul 13, 2013
31e7b65
WIP Added some javascript code
Jul 14, 2013
7c348e9
WIP Enabled visualizations of the shapes.
Jul 15, 2013
9c10bf6
Added server creating module
Jul 15, 2013
bcbca28
Added indents to JSON Output
Jul 15, 2013
f0aa71b
Added scene.display method in the run script
Jul 15, 2013
3c82531
Added README
Jul 15, 2013
8441d29
WIP
Jul 15, 2013
ae2a57b
Added static orientations to the shape
Jul 15, 2013
e60fe75
Fixed translation bug
Jul 18, 2013
f950c97
WIP Animation bug. I have kept output.json for ease in testing
Jul 19, 2013
cb5ba46
Working example now. Modified both python and Javascript code.
Jul 22, 2013
8314218
Changed time.
moorepants Aug 6, 2013
d11bd84
Modified according to new code for pydy_viz
Aug 12, 2013
5ef35c4
WIP
Aug 18, 2013
733f2ca
Removed white spaces
Aug 18, 2013
85b715e
Modified illustrative_example source
Sep 9, 2013
9fcf6bb
Merge branch 'illustrative-ex-for-viz' of github.com:tarzzz/pydy_exam…
moorepants Sep 9, 2013
4ea2488
Attempt to fix up the animation with correct link lengths and spheres…
moorepants Sep 9, 2013
0fec414
Removed comma.
moorepants Sep 9, 2013
18ad2b2
Removed extraneous line.
moorepants Sep 10, 2013
cde87c8
Modified README
Sep 22, 2013
53bddd4
Modified README
Sep 22, 2013
896a29f
Merge branch 'clean_conical' of https://github.com/PythonDynamics/pyd…
Sep 22, 2013
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
3 changes: 3 additions & 0 deletions illustrative_example_for_viz/README
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
52 changes: 52 additions & 0 deletions illustrative_example_for_viz/code_gen.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):
Copy link
Contributor

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

Copy link
Member

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.

Copy link
Contributor

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!

"""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
177 changes: 177 additions & 0 deletions illustrative_example_for_viz/essential.py
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote this here because I was having some trouble with evaluating the matrix with lambdify and array arguments. There may be a better way to construct this matrix, but it is probably fine for now.

_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]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the same method we did in the code_gen module. But I thought that Gilbert fixed this with his pull request. I tried the latest master and sympy and was not about to run lambdify without using these dummy symbols for the time varying stuff.

dummy_dict = dict(zip(dynamic, dummy_symbols))
transform = self._transform.subs(dummy_dict)

self.numeric_transform = lambdify(dummy_symbols + parameters,
transform, modules="numpy")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the numpy argument here to ensure that self.numeric_transform can be evaluated with array arguments.


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))) *
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should have worked if lambdify correct handled the array based arguments, but there are some issues in lambdify that need to be corrected first.

#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):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could pass in a state and parameter dictionary as two arguments. that may be cleaner.


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)
35 changes: 35 additions & 0 deletions illustrative_example_for_viz/illustrative_example.py
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)
Copy link
Member

Choose a reason for hiding this comment

The 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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point is taken automatically from link1, which is a rigidbody.

Copy link
Member

Choose a reason for hiding this comment

The 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()
31 changes: 31 additions & 0 deletions illustrative_example_for_viz/index.html
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>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this line?


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