Run the interactive online version of this notebook (takes 1-2 minutes to load): Binder badge

Welding Example #02: TCP movements and Weaving

In this example we will focus on more complex tcp movements along the workpiece and how to combine different motion shapes like weaving.

Imports

[3]:
# some python imports that will be used throughout the tutorial
import matplotlib.pyplot as plt
import networkx as nx
import numpy as np
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
from weldx import util
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

General setup

We will use the same workpiece geometry as defined in the previous example.

groove shape

[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"),
)

workpiece geometry

[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_(5, "mm")), trace)

# rasterize geometry
profile_raster_width = 2  # resolution of each profile in mm
trace_raster_width = 30  # space between profiles in mm
geometry_data_sp = geometry.rasterize(
    profile_raster_width=profile_raster_width, trace_raster_width=trace_raster_width
)

Coordinate system manager

[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,
)

# add the geometry data of the specimen
csm.assign_data(
    geometry.spatial_data(profile_raster_width, trace_raster_width),
    "specimen",
    "workpiece",
)

Movement definitions

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
../_images/tutorials_welding_example_02_weaving_16_0.svg
[10]:
def ax_setup(ax, rotate=170):
    ax.legend()
    ax.set_xlabel("x / mm")
    ax.set_ylabel("y / mm")
    ax.set_zlabel("z / mm")
    ax.view_init(30, -10)
    ax.set_ylim([-5.5, 5.5])
    ax.view_init(30, rotate)
    ax.legend()


color_dict = {
    "tcp_sine": (255, 0, 0),
    "tcp_wire_sine": (255, 0, 0),
    "tcp_wire_sine2": (255, 0, 0),
    "tcp_wire": (0, 150, 0),
    "specimen": (0, 0, 255),
}
[11]:
ax = csm.plot(
    coordinate_systems=["tcp_wire"],
    colors=color_dict,
    limits=[(0, 140), (-5, 5), (0, 12)],
    show_vectors=False,
    show_wireframe=True,
)
ax_setup(ax)
../_images/tutorials_welding_example_02_weaving_18_0.svg

add a sine wave to the TCP movement

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.

[12]:
ts_sine = util.sine(f=Q_(0.5 * 2 * np.pi, "Hz"), amp=Q_([[0, 0.75, 0]], "mm"))

Use the weldx.utility.lcs_coords_from_ts function to create the translation coordinate vectors at our specified timestamps.

[13]:
t = pd.timedelta_range(start=t_start, end=t_end, freq="10ms")
ts_sine_data = util.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
../_images/tutorials_welding_example_02_weaving_26_0.svg

Lets see the result:

[16]:
ax = csm.plot(
    coordinate_systems=["tcp_wire", "tcp_sine"],
    colors=color_dict,
    limits=[(0, 140), (-5, 5), (0, 12)],
    show_origins=False,
    show_vectors=False,
    show_wireframe=True,
)
ax_setup(ax)
../_images/tutorials_welding_example_02_weaving_28_0.svg

Here a little bit closer to see the actual sine wave:

[17]:
ax = csm.plot(
    coordinate_systems=["tcp_wire", "tcp_sine"],
    colors=color_dict,
    limits=[(0, 5), (-2, 2), (0, 12)],
    show_origins=False,
    show_vectors=False,
    show_wireframe=False,
)
ax_setup(ax)
../_images/tutorials_welding_example_02_weaving_30_0.svg

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.

[18]:
tcp_wire_sine = tcp_sine + tcp_wire

Note the difference in reference coordinate system compared to the first example.

[19]:
csm.add_cs("tcp_wire_sine", "workpiece", tcp_wire_sine)
csm
../_images/tutorials_welding_example_02_weaving_34_0.svg

We get the same result:

[20]:
ax = csm.plot(
    coordinate_systems=["tcp_wire", "tcp_wire_sine"],
    colors=color_dict,
    limits=[(0, 140), (-5, 5), (0, 12)],
    show_origins=False,
    show_vectors=False,
    show_wireframe=True,
)
ax_setup(ax)
../_images/tutorials_welding_example_02_weaving_36_0.svg
[21]:
ax = csm.plot(
    coordinate_systems=["tcp_wire", "tcp_sine"],
    colors=color_dict,
    limits=[(0, 5), (-2, 2), (0, 12)],
    show_origins=False,
    show_vectors=False,
    show_wireframe=False,
)
ax_setup(ax)
../_images/tutorials_welding_example_02_weaving_37_0.svg

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.

plot with time interpolation

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 CSM (or the coordinate systems).

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.

[22]:
t_interp = pd.timedelta_range(start="3s", end="11s", freq="1ms")
[23]:
ax = csm.interp_time(t_interp).plot(
    coordinate_systems=["tcp_wire", "tcp_wire_sine"],
    colors=color_dict,
    limits=[(0, 140), (-5, 5), (0, 12)],
    show_origins=False,
    show_vectors=False,
    show_wireframe=True,
)
ax_setup(ax)
../_images/tutorials_welding_example_02_weaving_41_0.svg

Adding a second weaving motion

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:

[24]:
ts_sine = util.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 = util.lcs_coords_from_ts(ts_sine, t)
tcp_sine2 = lcs(coordinates=ts_sine_data)
[25]:
tcp_sine2
[25]:
<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 !

[26]:
t_interp = pd.timedelta_range(
    start=tcp_wire.time[0].values, end=tcp_wire.time[-1].values, freq="20ms"
)
[27]:
tcp_wire_sine2 = (
    tcp_sine2.interp_time(t_interp) + tcp_sine.interp_time(t_interp)
) + tcp_wire
[28]:
csm.add_cs("tcp_wire_sine2", "workpiece", tcp_wire_sine2)
csm
../_images/tutorials_welding_example_02_weaving_48_0.svg
[29]:
ax = csm.plot(
    coordinate_systems=["tcp_wire", "tcp_wire_sine2"],
    colors=color_dict,
    limits=[(0, 140), (-5, 5), (0, 12)],
    show_origins=False,
    show_vectors=False,
)
ax_setup(ax, rotate=110)
../_images/tutorials_welding_example_02_weaving_49_0.svg
[30]:
ax = csm.plot(
    coordinate_systems=["tcp_wire", "tcp_wire_sine2"],
    colors=color_dict,
    limits=[(60, 100), (-2, 2), (0, 12)],
    show_origins=False,
    show_vectors=False,
)
ax_setup(ax, rotate=110)
../_images/tutorials_welding_example_02_weaving_50_0.svg

Generated by nbsphinx from a Jupyter notebook.