from sympy import *
from sympy.physics.mechanics import dynamicsymbols, ReferenceFrame, Point
#
# I would like to develop the model for the below picture...
#
# There is an 'arm' and a linear 'actuator'.
# - the a_pt of the arm is connected to the ground
# - the y_pt of the actuator is connected to the ground
# - the k_pt is on the arm and the actuator is connected to it
#
# The desire is to solve the relationship between the length of the actuator (a dynamic symbol)
# and the angle from vector AY to AB, as well as the magnitude of the Y-B vector
#
# Since a closed path triangle is created between A, K, and Y, we should be able to 'automagically'
# orient the frames with respect to each other, but I don't know how to do this without introducing
# a bunch of dummy dynamic symbols to represent the orientations between the frames.
#
# O <-- b_pt
# //
# //
# ---> //
# / //
# Arm //
# / O <-- k_pt
# ---> // \
# // \
# // \ <-- Actuator (extends/retracts)
# // \
# // \
# a_pt --> O============O <-- y_pt
# / / / /
# Ground
#
# Symbols for the Ground Points
ground_coord_a = symbols(('ground_coord_a_x', 'ground_coord_a_y'))
ground_coord_y = symbols(('ground_coord_y_x', 'ground_coord_y_y'))
# Symbols for the Arm Points
arm_coord_a = symbols(('arm_coord_a_x', 'arm_coord_a_y'))
arm_coord_k = symbols(('arm_coord_k_x', 'arm_coord_k_y'))
arm_coord_b = symbols(('arm_coord_b_x', 'arm_coord_b_y'))
# Symbol for the Actuator Cylinder Length
actuator_len = dynamicsymbols('actuator_len')
# Create the reference frame for each member
ground_frame = ReferenceFrame('ground_frame')
ground_frame_origin_pt = Point('ground_frame_origin_pt')
arm_frame = ReferenceFrame('arm_frame')
arm_frame_origin_pt = Point('arm_frame_origin_pt')
actuator_frame = ReferenceFrame('actuator_frame')
# Define all of the Points on the Linkage
a_pt = Point('a_pt')
b_pt = Point('b_pt')
k_pt = Point('k_pt')
y_pt = Point('y_pt')
# Place the points on the Ground
a_pt.set_pos(ground_frame_origin_pt, ground_coord_a[0] * ground_frame.x + ground_coord_a[1] * ground_frame.y)
y_pt.set_pos(ground_frame_origin_pt, ground_coord_y[0] * ground_frame.x + ground_coord_y[1] * ground_frame.y)
# Place the points on the Arm
a_pt.set_pos(arm_frame_origin_pt, arm_coord_a[0] * arm_frame.x + arm_coord_a[1] * arm_frame.y)
b_pt.set_pos(arm_frame_origin_pt, arm_coord_b[0] * arm_frame.x + arm_coord_b[1] * arm_frame.y)
k_pt.set_pos(arm_frame_origin_pt, arm_coord_k[0] * arm_frame.x + arm_coord_k[1] * arm_frame.y)
# Place the points on the Actuator
k_pt.set_pos(y_pt, actuator_len * actuator_frame.x + 0.0 * actuator_frame.y)
# Of course things work within the same frame
length_ab = b_pt.pos_from(a_pt).magnitude()
print(length_ab)
# How about length Y to K?
length_yk = k_pt.pos_from(y_pt).magnitude()
print(length_yk)
# But not Y to B?
try:
length_yb = b_pt.pos_from(y_pt).magnitude()
print(length_yb)
except ValueError as e:
print(e)
# Ok, I can add a redundant symbol to orient the ground frame to the arm frame...
# Dynamic Symbols (time variant)
angle_ground_to_arm = dynamicsymbols('angle_ground_to_arm')
arm_frame.orient(ground_frame, 'Axis', (angle_ground_to_arm, ground_frame.z))
# Now can I get Y to B? still no
try:
length_yb = b_pt.pos_from(y_pt).magnitude()
print(length_yb)
except ValueError as e:
print(e)
# Ok, do I need to orient the actuator to the ground as well?
angle_ground_to_actuator = dynamicsymbols('angle_ground_to_actuator')
actuator_frame.orient(ground_frame, 'Axis', (angle_ground_to_actuator, ground_frame.z))
# Now can I get Y to B?
# Yes, but now I have an expression that involves 'angle_ground_to_actuator(t)' as well as 'actuator_len(t)'
# which is redundant. I don't actually have to degrees of freedom or actuators.
try:
length_yb = b_pt.pos_from(y_pt).magnitude()
print(length_yb)
except ValueError as e:
print(e)
# How do I make sympy know about the closed path so that it can 'infer'
# the frame orientations based on that closed path? (Without adding redundant dummy dynamic symbols)--
You received this message because you are subscribed to the Google Groups "sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sympy+unsubscribe@googlegroups.com.
To post to this group, send email to sy...@googlegroups.com.
Visit this group at https://groups.google.com/group/sympy.
To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/639fdd0f-a35c-44ee-b57a-405f622bc205%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
# Build the kinematic loop constraint (Law of Cosines)
ak_vec = k_pt.pos_from(a_pt)
ak_len = ak_vec.magnitude()
ay_vec = y_pt.pos_from(a_pt)
ay_len = ay_vec.magnitude()
kay_angle = acos((ak_len**2 + ay_len**2 - actuator_len**2)/(2*ak_len*ay_len))
# Orient the arm frame to the ground frame
arm_frame.orient(ground_frame, 'Axis', (kay_angle, ground_frame.z))
length_yb = b_pt.pos_from(y_pt).magnitude()
To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.
def _pdict_lists(self, other, num):
"""Creates a list of lists from self to other using _pos_dict. """
outlist = [[self]]
oldlist = [[]]
while outlist != oldlist:
oldlist = outlist[:]
for i, v in enumerate(outlist):
templist = v[-1]._pdlist[num].keys()
for i2, v2 in enumerate(templist):
if not v.__contains__(v2):
littletemplist = v + [v2]
if not outlist.__contains__(littletemplist):
outlist.append(littletemplist)
for i, v in enumerate(oldlist):
if v[-1] != other:
outlist.remove(v)
outlist.sort(key=len)
if len(outlist) != 0:
return outlist
raise ValueError('No Connecting Path found between ' + other.name +
' and ' + self.name)
def _pdict_list(self, other, num):
"""Creates a list from self to other using _pos_dict. """
return self._pdict_lists(other, num)[0]
def pos_from(self, otherpoint, singleframe=False, frame=None, variables=False):
"""Returns a Vector distance between this Point and the other Point.
Parameters
==========
otherpoint : Point
The otherpoint we are locating this one relative to
singleframe : boolean
Expresses the resulting vector in a single frame
frame : ReferenceFrame
Expresses the resulting vector in this frame
variables : boolean
If True, the coordinate symbols(if present) in the resulting Vector
are re-expressed in terms the resulting frame (if singleframe is True
or frame is given)
Examples
========
>>> from sympy.physics.vector import Point, ReferenceFrame
>>> N = ReferenceFrame('N')
>>> p1 = Point('p1')
>>> p2 = Point('p2')
>>> p1.set_pos(p2, 10 * N.x)
>>> p1.pos_from(p2)
10*N.x
"""
if frame is not None:
_check_frame(frame)
last_error = None
plists = self._pdict_lists(otherpoint, 0)
for plist in plists:
outvec = Vector(0)
for i in range(len(plist) - 1):
outvec += plist[i]._pos_dict[plist[i + 1]]
# 0 Vector
if len(outvec.args) == 0:
return outvec
try:
if frame is not None:
# Express in the given frame
outvec = outvec.express(frame, variables=variables)
elif singleframe:
# Express in a single frame
outvec = outvec.express(outvec.args[0][1], variables=variables)
return outvec
except ValueError as e:
last_error = e
continue
raise last_error