Closed juanma9613 closed 4 years ago
Pyslvs has an expression phase and a backend calculator. Use calculator will be more efficient instead of building expression.
A four-bar linkage can be formed as
The calculation functions:
from math import radians
from pyslvs import plap, pllp, Coordinate
# p0x, p0y, p4x, p4y, input_theta, len0, len1, len2, len3 and gamma are known,
# where gamma is between len1 and len3
# All angles are in radians
p0 = Coordinate(p0x, p0y)
p4 = Coordinate(p4x, p4y)
p3_path = []
for i in range(360):
input_theta = radians(i)
p1 = plap(p0, len0, input_theta)
p2 = pllp(p1, len1, len2, p4)
p3 = plap(p1, len3, gamma, p2)
p3_path.append((p3.x, p3.y))
Pyslvs 20.07.0 will generate a script when selected "Export as Python script".
# Generate by Pyslvs 20.07.0.dev0
# Project "Crank rocker"
from pyslvs import parse_vpoints, t_config, data_collecting, expr_solving
if __name__ == '__main__':
vpoints = parse_vpoints(
"M["
"J[R, color[Green], P[0, 0], L[ground, L1]], "
"J[R, color[Green], P[12.92, 32.53], L[L1, L2]], "
"J[R, color[Green], P[73.28, 67.97], L[L2, L3]], "
"J[R, color[Green], P[33.3, 66.95], L[L2]], "
"J[R, color[Green], P[90, 0], L[ground, L3]], "
"]")
exprs = t_config(vpoints, ((0, 1),))
mapping = {n: f'P{n}' for n in range(len(vpoints))}
data_dict, dof = data_collecting(exprs, mapping, vpoints)
pos = expr_solving(exprs, mapping, vpoints, [0.])
print(data_dict)
print(f"DOF:{dof}")
print(pos)
###
from pyslvs import plap, pllp
# a0, i0, l0, l1, l2, l3, p0, p4 are known
if __name__ == '__main__':
p1 = plap(p0, l0, i0)
p2 = pllp(p1, l1, l2, p4)
p3 = plap(p1, l3, a0, p2)
Thank you for your quick reply! In the code I wrote based on this I'm facing the problem that when two bars are aligned (a singularity) the mechanism "jumps" to a different solution. That's why I was asking for a solver for trajectory specifically. Don't you have this problem when solving for different inputs angles whitout taking into account the current trajectory?
The PLLP function has two solutions which are the intersections between two circles. ("inverse" argument can switch them) I'm recommend to use PLAP function to fix this problem with an angular constrain. (counter-clockwise is default)
That's why the target point 3 in previous case is solved by PLAP instead of PLLP function.
p3 = plap(p1, l3, a0, p2) # CCW
p3 = plap(p1, l3, a0, p2, inverse=True) # CW
# has two solutions (same as changing the order of p1 & p2)
p3 = pllp(p1, l3, l4, p2, inverse=False)
p3 = pllp(p1, l3, l4, p2, inverse=True)
Thank you for all your help! I will change the way I'm defining my mechanisms to be compatible with pyslvs (pllp and plap) and I will let you know the results.
Hi Yuan, at the end I decided to use the expr_solving() in order to get automatically the plap and pllp operations. But I am facing the same problem, some bars jump to other configuration:
Below is the code I used to generate the animation, if you had any idea how to avoid this behavior I would really appreciate it.
from matplotlib import pyplot as plt
import numpy as np
from collections import defaultdict
from pyslvs import example_list, parse_vpoints, t_config, expr_solving
expr = "M[J[R, color[Green], P[0.0, 0.0], L[ground, L1, L3]],\
J[R, color[Green], P[-0.30901699437494734, 0.9510565162951536], L[L1, L2, L4]],\
J[R, color[Green], P[0.5656740963008081, 1.4357450529687716], L[L2, L8, L12, L14]],\
J[R, color[Green], P[1.0, 0.0], L[ground, L5, L6, L10, L11]],\
J[R, color[Green], P[2.2185821011191758, 1.1521984301835777], L[L5, L7, L9]],\
J[R, color[Green], P[2.7614894807431654, -0.6424828860273869], L[L6, L7]],\
J[R, color[Green], P[1.675674721495186, 2.946879746394542], L[L4, L8, L9]],\
J[R, color[Green], P[-0.6529080048183675, 0.28354662278519394], L[L3, L11, L13, L15]],\
J[R, color[Green], P[-1.1958153844423574, 2.0782279389961587], L[L12, L13]],\
J[R, color[Green], P[1.108581475924798, -0.35893626324219297], L[L10, L14, L15]],]"
inputs = ((0, 1),)
vpoints = parse_vpoints(expr)
exprs = t_config(vpoints, inputs)
mapping = {n: f'P{n}' for n in range(len(vpoints))}
results =[]
for i in np.linspace(0,360, 360, endpoint = False):
try:
results.append(expr_solving(exprs, mapping, vpoints, angles =[i]))
except:
pass
trajectory = np.array(results)
bars = defaultdict(list)
for idx, links in enumerate(vpoints):
for link in links.links:
bars[link].append(idx)
fig=plt.figure()
ax = fig.add_subplot(111)
ax.axis('equal')
ax.set_xlim([-10, 10])
ax.set_ylim([-10, 10])
for i in range(0,trajectory.shape[0], 4):
ax.clear()
x = trajectory[i,:,:]
for k,v in list(bars.items())[::-1]:
if k != 'ground':
n1 = v[0]
n2 = v[1]
plt.plot(x[[n1, n2],0], x[[n1, n2],1])
plt.axis('equal')
ax.axis('equal')
plt.xlim([-10, 10])
plt.ylim([-10, 10])
ax.set_title(str(i))
fig.canvas.draw()
plt.pause(0.001)
plt.pause(0.3)
The above case can be simplified as following expression:
M[
J[R, color[Green], P[0, 0], L[ground, L1]],
J[R, color[Green], P[-30.9017, 95.1057], L[L1, L2]],
J[R, color[Green], P[56.5674, 143.5745], L[L2, L3, L4]],
J[R, color[Green], P[100, 0], L[ground, L5]],
J[R, color[Green], P[221.8582, 115.2198], L[L5, L6]],
J[R, color[Green], P[276.1489, -64.2483], L[L5]],
J[R, color[Green], P[167.5675, 294.688], L[L6, L2]],
J[R, color[Green], P[-65.2908, 28.3547], L[L7, ground]],
J[R, color[Green], P[-119.5815, 207.8228], L[L3, L7]],
J[R, color[Green], P[110.8581, -35.8936], L[L4, ground]]
]
The problematic loop is represented as following expression:
(with 3->0
input link)
M[
J[R, color[Green], P[56.5674, 143.5745], L[L3, L4]],
J[R, color[Green], P[-65.2908, 28.3547], L[L7, ground]],
J[R, color[Green], P[-119.5815, 207.8228], L[L3, L7]],
J[R, color[Green], P[110.8581, -35.8936], L[L4, ground]]
]
Well, that truly is a bug of Pyslvs for handling parallel linkage. I'm forward this to #36.
@juanma9613 Parallel linkage is a special case of the simulation. If your link lengths are not variables, please use direct function to solve. If not (just like dimensional synthesis), try to avoid this case.
(in nightly version) https://pyslvs-ui.readthedocs.io/en/latest/pyslvs-api/#ppp Here is the source code: https://github.com/KmolYuan/pyslvs/blob/master/pyslvs/tinycadlib.pyx#L38
Thanks! I have one last question.
By direct function you mean that I can't use expr_solving, if that's the case how can I solve the position for different mechanism automatically?
What I do is to generate a lot of mechanisms "randomly" from a script in python, which gives me the bar lengths and the initial configurations for each mechanism, and after that I want to use your library just to simulate their trajectories.
@KmolYuan Thank you for all the help.
The develop version functions can support this feature. (in pyslvs master
branch)
It includes a length condition to add the special solution.
Hi! First of all I would like to say that this system is amazing, it works great!
I would like to use this in my thesis with Reinforcement learning in which I am creating mechanism (1-DOF, derived from a fourbar linkage) from python and I need to get the trajectories of those mechanism as fast as possible (3trajectories /second). Is there any way of defining the mechanism in a script and get the trajectories there without using the GUI interface ?
This is how I define the linkages in python currently
Thanks in advance for your help!