Run the interactive online version of this notebook (takes 1-2 minutes to load):
In this example we will focus on more complex tcp movements along the workpiece and how to combine different motion shapes like weaving.
[3]:
# some python imports that will be used throughout the tutorial import numpy as np import matplotlib.pyplot as plt import networkx as nx import pandas as pd import pint import xarray as xr from mpl_toolkits.mplot3d import Axes3D
[4]:
# importing the weldx package with prevalent default abbreviations import weldx import weldx.geometry as geo import weldx.transformations as tf import weldx.utility as ut import weldx.visualization as vis from weldx import Q_ from weldx.core import MathematicalExpression, TimeSeries from weldx.transformations import LocalCoordinateSystem as lcs from weldx.transformations import WXRotation
We will use the same workpiece geometry as defined in the previous example.
[5]:
from weldx.welding.groove.iso_9692_1 import get_groove groove = get_groove( groove_type="VGroove", workpiece_thickness=Q_(0.5, "cm"), groove_angle=Q_(50, "deg"), root_face=Q_(1, "mm"), root_gap=Q_(1, "mm"), )
[6]:
# define the weld seam length in mm seam_length = 150 # create a linear trace segment a the complete weld seam trace trace_segment = geo.LinearHorizontalTraceSegment(seam_length) trace = geo.Trace(trace_segment) # create 3d workpiece geometry from the groove profile and trace objects geometry = geo.Geometry(groove.to_profile(width_default=Q_(4, "mm")), trace) # rasterize geometry profile_raster_width = 0.5 # resolution of each profile in mm trace_raster_width = 15 # space between profiles in mm geometry_data_sp = geometry.rasterize( profile_raster_width=profile_raster_width, trace_raster_width=trace_raster_width )
[7]:
# crete a new coordinate system manager with default base coordinate system csm = weldx.transformations.CoordinateSystemManager("base") # add the workpiece coordinate system csm.add_cs(coordinate_system_name="workpiece", reference_system_name="base", lcs=trace.coordinate_system)
Like in the previous example we start by defining the general linear movement along the weld seam with a constant welding speed.
[8]:
tcp_start_point = Q_([5.0, 0.0, 2.0], "mm") tcp_end_point = Q_([seam_length - 5.0, 0.0, 2.0], "mm") v_weld = Q_(10, "mm/s") s_weld = (tcp_end_point - tcp_start_point)[0] # length of the weld t_weld = s_weld / v_weld t_start = pd.Timedelta("0s") t_end = pd.Timedelta(str(t_weld)) rot = WXRotation.from_euler("x", 180, degrees=True) coords = [tcp_start_point.magnitude, tcp_end_point.magnitude] tcp_wire = lcs( coordinates=coords, orientation=rot, time=[t_start, t_end] )
Let’s add the linear movement to the coordinate system manager and see a simple plot:
[9]:
csm.add_cs(coordinate_system_name="tcp_wire", reference_system_name="workpiece", lcs=tcp_wire) csm
[10]:
def ax_setup(ax): ax.legend() ax.set_xlabel("x / mm") ax.set_ylabel("y / mm") ax.set_zlabel("z / mm")
[11]:
fig = plt.figure() ax = fig.add_subplot(111, projection="3d", proj_type="ortho") ax.scatter( geometry_data_sp[0, :], geometry_data_sp[1, :], geometry_data_sp[2, :], marker=".", c="b", label="groove", ) cs = cs = csm.get_cs("tcp_wire", "workpiece") data = cs.coordinates.data ax.plot(data[:, 0], data[:, 1], data[:, 2], label="tcp_wire", c="g", marker="o") ax_setup(ax)
We now want to add a weaving motion along the y-axis (horizontal plane) of our TCP motion. We can define a general weaving motion using the weldx.utility.sine function that creates TimeSeries class.
weldx.utility.sine
TimeSeries
[12]:
ts_sine = ut.sine(f = Q_(1.5 * 2 * np.pi, "Hz"), amp = Q_([[0, 0.75, 0]], "mm"))
/home/docs/checkouts/readthedocs.org/user_builds/weldx/conda/0.2.2/lib/python3.7/site-packages/sympy/utilities/lambdify.py:811: SymPyDeprecationWarning: The list of arguments is a `set`. This leads to unpredictable results has been deprecated since SymPy 1.6.3. Use : Convert set into list or tuple instead. See https://github.com/sympy/sympy/issues/20013 for more info. deprecated_since_version="1.6.3"
Use the weldx.utility.lcs_coords_from_ts function to create the translation coordinate vectors at our specified timestamps.
weldx.utility.lcs_coords_from_ts
[13]:
t = pd.timedelta_range(start=t_start, end=t_end, freq="10ms") ts_sine_data = ut.lcs_coords_from_ts(ts_sine,t)
We now define a simple coordinate system that contains only the weaving motion.
[14]:
tcp_sine = lcs(coordinates=ts_sine_data)
One approach to combine the weaving motion with the existing linear tcp_wire movement is to use the coordinate system manager. We can add the tcp_sine coordinate system relative to the tcp_wire system:
[15]:
csm.add_cs(coordinate_system_name="tcp_sine", reference_system_name="tcp_wire", lcs=tcp_sine) csm
Lets see the result:
[16]:
fig = plt.figure() ax = fig.add_subplot(111, projection="3d", proj_type="ortho") ax.scatter( geometry_data_sp[0, :], geometry_data_sp[1, :], geometry_data_sp[2, :], marker=".", c="b", label="groove", ) cs = csm.get_cs("tcp_wire", "workpiece") data = cs.coordinates.data ax.plot(data[:, 0], data[:, 1], data[:, 2], label="tcp_wire", c="g", marker="o") cs = csm.get_cs("tcp_sine", "workpiece") data = cs.coordinates.data ax.plot(data[:, 0], data[:, 1], data[:, 2], label="tcp_contact", c="r") ax_setup(ax)
Another approach would be to combine both systems before adding them to the coordinate system manager. We can combine both coordinate systems using the + operator to generate the superimposed weaving coordinate system.
[17]:
tcp_wire_sine = tcp_sine + tcp_wire
Note the difference in reference coordinate system compared to the first example.
[18]:
csm.add_cs("tcp_wire_sine", "workpiece", tcp_wire_sine) csm
We get the same result:
[19]:
fig = plt.figure() ax = fig.add_subplot(111, projection="3d", proj_type="ortho") ax.scatter( geometry_data_sp[0, :], geometry_data_sp[1, :], geometry_data_sp[2, :], marker=".", c="b", label="groove", ) cs = csm.get_cs("tcp_wire", "workpiece") data = cs.coordinates.data ax.plot(data[:, 0], data[:, 1], data[:, 2], label="tcp_wire", c="g", marker="o") cs = csm.get_cs("tcp_wire_sine", "workpiece") data = cs.coordinates.data ax.plot(data[:, 0], data[:, 1], data[:, 2], label="tcp_contact", c="r") ax_setup(ax)
Adding every single superposition step in the coordinate system manager can be more flexible and explicit, but will clutter the CSM instance for complex movements.
Sometimes we might only be interested in a specific time range of the experiment or we want to change the time resolution. For this we can use the time interpolation methods of the coordinate systems (or the CSM).
Let’s say we want to weave only 8 seconds of our experiment (starting from 2020-04-20 10:03:00) but interpolate steps of 1 ms.
[20]:
t_interp = pd.timedelta_range(start="0s", end="11s", freq="1ms")
[21]:
fig = plt.figure() ax = fig.add_subplot(111, projection="3d", proj_type="ortho") ax.scatter( geometry_data_sp[0, :], geometry_data_sp[1, :], geometry_data_sp[2, :], marker=".", c="b", label="groove", ) cs = csm.get_cs("tcp_wire", "workpiece").interp_time(t_interp) data = cs.coordinates.data ax.plot(data[:, 0], data[:, 1], data[:, 2], label="tcp_wire", c="g") cs = csm.get_cs("tcp_wire_sine", "workpiece").interp_time(t_interp) data = cs.coordinates.data ax.plot(data[:, 0], data[:, 1], data[:, 2], label="tcp_wire_sine", c="r") ax_setup(ax)
We now want to add a second weaving motion along the z-axis that only exists for a limited time. Lets generate the motion first:
[22]:
ts_sine = ut.sine(f=Q_(1 / 8 * 2 * np.pi, "Hz"), amp=Q_([[0, 0, 1]], "mm")) t = pd.timedelta_range(start="0s", end="8s", freq="25ms") ts_sine_data = ut.lcs_coords_from_ts(ts_sine,t) tcp_sine2 = lcs(coordinates=ts_sine_data)
[23]:
tcp_sine2
<LocalCoordinateSystem> Dimensions: (c: 3, time: 321, v: 3) Coordinates: * time (time) timedelta64[ns] 00:00:00 00:00:00.025000 ... 00:00:08 * c (c) <U1 'x' 'y' 'z' * v (v) int64 0 1 2 Data variables: coordinates (time, c) float64 0.0 0.0 0.0 0.0 0.0 ... 0.9964 0.0 0.0 0.9783 orientation (v, c) float64 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0
adding all the movements together. We have to be careful with the time-axis in this case !
[24]:
t_interp = pd.timedelta_range(start=tcp_wire.time[0].values, end=tcp_wire.time[-1].values, freq="20ms")
[25]:
tcp_wire_sine2 = ( tcp_sine2.interp_time(t_interp) + tcp_sine.interp_time(t_interp) ) + tcp_wire
[26]:
csm.add_cs("tcp_wire_sine2", "workpiece", tcp_wire_sine2) csm
[27]:
fig = plt.figure() ax = fig.add_subplot(111, projection="3d", proj_type="ortho") ax.scatter( geometry_data_sp[0, :], geometry_data_sp[1, :], geometry_data_sp[2, :], marker=".", c="b", label="groove", ) cs = csm.get_cs("tcp_wire_sine2", "workpiece") # cs = tcp_wire_sine2 data = cs.coordinates.data ax.plot(data[:, 0], data[:, 1], data[:, 2], label="tcp_wire_sine2", c="r") ax_setup(ax)
Generated by nbsphinx from a Jupyter notebook.