Run the interactive online version of this notebook (takes 1-2 minutes to load):
The goal of this small example is to introduce the main functionalities and interfaces to create and describe a simple welding application using the WelDX package.
[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.transformations import LocalCoordinateSystem as lcs from weldx.transformations import WXRotation
We start of defining our welding application example by defining the base groove shape. For this examples we assume the groove shape to be constant along the entire workpiece.
The groove shall have the following attributes:
a workpiece thickness of 5 mm
a single sided V-Groove butt weld with 50 degree groove angle
root gap and face of 1 mm
To generate the groove shape, we can use the get_groove function of the of iso_groove that implements all groove types and shapes defined in ISO 9692-1:2013. For all available groove types and options take a look at the extensive docstring of get_groove and the groove_type tutorial notebook.
get_groove
iso_groove
Be aware that we must pass along all groove parameters as Quantities with a specified unit using the default Q_ type imported above. All units are automatically converted to SI units for most mathematical operations in the background so we can specify parameters in any appropriate unit we desire.
Q_
[5]:
from weldx.welding.groove.iso_9692_1 import get_groove groove = get_groove( groove_type="VGroove", workpiece_thickness=Q_(5, "mm"), groove_angle=Q_(50, "deg"), root_face=Q_(1, "mm"), root_gap=Q_(1, "mm"), )
Using the plot function of the created groove instance gives a quick overview of the created geometry.
plot
[6]:
groove.plot(raster_width=0.2)
Once we have created our desired 2d groove shape, we can simply extend the groove shape into 3d-space to create a volumetric workpiece.
To do this, two steps are missing:
we have to decide on a weld seam length first (we will use 300 mm in this example)
create a trace object that defines the path of our element though space. (we use a simple linear trace in this example)
[7]:
# define the weld seam length in mm seam_length = Q_(300, "mm") # create a linear trace segment a the complete weld seam trace trace_segment = geo.LinearHorizontalTraceSegment(seam_length) trace = geo.Trace(trace_segment)
Once we have defined the trace object, we can create the workpiece geometry by combining the groove profile with the trace.
[8]:
# create 3d workpiece geometry from the groove profile and trace objects geometry = geo.Geometry(groove.to_profile(width_default=Q_(4, "mm")), trace)
To visualize the geometry we rasterize each profile along specific steps of the trace.
[9]:
# 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 )
Simple scatter plot of the geometry
Once we have created the 3d geometry it is now time to describe the movement of the wire during the welding process. To handle different moving coordinate systems and objects we use the CoordinateSystemManager.
Start by creating a new instance of the CSM. When setting up a CSM instance we have to supply a name that indicates the reference coordinate system which is a static Cartesian coordinate system that defines an origin.
[12]:
# crete a new coordinate system manager with default base coordinate system csm = weldx.transformations.CoordinateSystemManager("base")
The trace we created earlier to extend the groove shape into 3d has its own associated coordinate system that starts in the origin of the groove (see point (0,0) in our first plot of the groove profile) and has the x-axis running along the direction of the weld seam by convention.
We simply add the trace coordinate system to our coordinate system manager defining at as the workpiece coordinate system.
[13]:
# add the workpiece coordinate system csm.add_cs( coordinate_system_name="workpiece", reference_system_name="base", lcs=trace.coordinate_system, )
For this example, we want the tip of the wire (i.e. the robot TCP during welding) to move along the center of the groove at 2 mm from the bottom of the workpiece with a speed of 10 mm/s.
We begin by defining the start and end points relative to our workpiece coordinate system. Note that the z-axis of the workpiece coordinate system is pointing upwards (see Figure 1). Hence we use a positive offset of 2 mm in z direction from our workpiece. For the x-axis we start the weld 5 mm into the weldseam and 5 mm before reaching the end of the weldseam.
[14]:
tcp_start_point = Q_([5.0, 0.0, 2.0], "mm") tcp_end_point = Q_([-5.0, 0.0, 2.0], "mm") + np.append(seam_length, Q_([0, 0], "mm"))
To completely describe the TCP movement in space and time we need to supply time information for the start and end point. Lets say the weld starts on 2020-04-20 10:00:00. We calculate the time
[15]:
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.to_base_units()))
The two points and timestamps are enough to create the linear moving coordinate system. We can interpolate the movement with a higher resolution later.to_base_units
The orientation of the wire has the z coordinate facing downwards towards the workpiece. The workpiece z-coordinate is facing upwards. We add a constant 180 degree rotation around the x-axis to orientate the wire coordinate system correctly. Orientations can be described using the scipy Rotation objects
[16]:
rot = WXRotation.from_euler(seq="x", angles=180, degrees=True)
With the defined coordinates, the constant orientation and the associated times we can create the coordinate system for the wire tcp.
[17]:
coords = [tcp_start_point.magnitude, tcp_end_point.magnitude] tcp_wire = lcs(coordinates=coords, orientation=rot, time=[t_start, t_end])
Add the new coordinate system to the coordinate system manager relative to the workpiece.
[18]:
# add the workpiece coordinate system csm.add_cs( coordinate_system_name="tcp_wire", reference_system_name="workpiece", lcs=tcp_wire, )
Lets say The wire extends 10 mm from the contact tip. We can add the contact tip as another point using the coordinate system manager. To simplify things we now use the tcp_wire coordinate system as reference. All we need to add is the z-offset along the wire. Note that we have to provide a negative offset along the z-axis since the wire-tcp z-axis is pointing downwards.
[19]:
tcp_contact = lcs(coordinates=[0, 0, -10])
[20]:
# add the workpiece coordinate system csm.add_cs( coordinate_system_name="tcp_contact", reference_system_name="tcp_wire", lcs=tcp_contact, )
We can create a simple plot of the relations between our our coordinate systems
[21]:
csm
To examine the movement of our wire TCP and contact tip, lets create a simple plot. We only have a linear movement we don’t have to add additional timestamps to the moving coordinate systems.
[22]:
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_contact", "workpiece") data = cs.coordinates.data ax.plot(data[:, 0], data[:, 1], data[:, 2], label="tcp_contact", c="r", marker="o") ax_setup(ax)
With everything setup we can now start adding some measurements with associated points in space. We add a temperature measurements T1, T2, T3 to the surface of the weld seam.
[23]:
# add the workpiece coordinate system csm.add_cs("T1", "workpiece", lcs(coordinates=[200, 3, 5])) csm.add_cs("T2", "T1", lcs(coordinates=[0, 1, 0])) csm.add_cs("T3", "T2", lcs(coordinates=[0, 1, 0]))
[24]:
for T in ["T1", "T2", "T3"]: cs = csm.get_cs(T, "workpiece") data = cs.coordinates.data ax.scatter(data[0], data[1], data[2], label=T, c="orange", marker="o") ax.legend()
<matplotlib.legend.Legend at 0x7fbc9634c5d0>
[25]:
[26]:
tree = {"workpiece": {"groove": groove, "length": seam_length}, "CSM": csm}
[27]:
buffer = weldx.asdf.utils._write_buffer(tree)
[28]:
weldx.asdf.utils.notebook_fileprinter(buffer)
#ASDF 1.0.0 #ASDF_STANDARD 1.5.0 %YAML 1.1 %TAG ! tag:stsci.edu:asdf/ --- !core/asdf-1.1.0 asdf_library: !core/software-1.0.0 {author: Space Telescope Science Institute, homepage: 'http://github.com/spacetelescope/asdf', name: asdf, version: 2.7.1} history: extensions: - !core/extension_metadata-1.0.0 extension_class: weldx.asdf.extension.WeldxExtension software: !core/software-1.0.0 {name: weldx, version: 0.2.2} - !core/extension_metadata-1.0.0 extension_class: weldx.asdf.extension.WeldxAsdfExtension software: !core/software-1.0.0 {name: weldx, version: 0.2.2} - !core/extension_metadata-1.0.0 extension_class: asdf.extension.BuiltinExtension software: !core/software-1.0.0 {name: asdf, version: 2.7.1} CSM: !<tag:weldx.bam.de:weldx/core/transformations/coordinate_system_hierarchy-1.0.0> name: Coordinate system manager 0 root_system_name: base subsystems: [] coordinate_systems: - !<tag:weldx.bam.de:weldx/core/transformations/coordinate_transformation-1.0.0> name: workpiece reference_system: base transformation: !<tag:weldx.bam.de:weldx/core/transformations/local_coordinate_system-1.0.0> {} - !<tag:weldx.bam.de:weldx/core/transformations/coordinate_transformation-1.0.0> name: tcp_wire reference_system: workpiece transformation: !<tag:weldx.bam.de:weldx/core/transformations/local_coordinate_system-1.0.0> time: !<tag:weldx.bam.de:weldx/time/timedeltaindex-1.0.0> values: !core/ndarray-1.0.0 source: 0 datatype: int64 byteorder: little shape: [2] start: !<tag:weldx.bam.de:weldx/time/timedelta-1.0.0> {value: P0DT0H0M0S} end: !<tag:weldx.bam.de:weldx/time/timedelta-1.0.0> {value: P0DT0H0M29S} min: !<tag:weldx.bam.de:weldx/time/timedelta-1.0.0> {value: P0DT0H0M0S} max: !<tag:weldx.bam.de:weldx/time/timedelta-1.0.0> {value: P0DT0H0M29S} orientations: !<tag:weldx.bam.de:weldx/core/variable-1.0.0> name: orientations dimensions: [c, v] dtype: <f8 data: !core/ndarray-1.0.0 data: - [1.0, 0.0, 0.0] - [0.0, -1.0, -1.2246467991473532e-16] - [0.0, 1.2246467991473532e-16, -1.0] datatype: float64 shape: [3, 3] coordinates: !<tag:weldx.bam.de:weldx/core/variable-1.0.0> name: coordinates dimensions: [time, c] dtype: <f8 data: !core/ndarray-1.0.0 data: - [5.0, 0.0, 2.0] - [295.0, 0.0, 2.0] datatype: float64 shape: [2, 3] - !<tag:weldx.bam.de:weldx/core/transformations/coordinate_transformation-1.0.0> name: tcp_contact reference_system: tcp_wire transformation: !<tag:weldx.bam.de:weldx/core/transformations/local_coordinate_system-1.0.0> coordinates: !<tag:weldx.bam.de:weldx/core/variable-1.0.0> name: coordinates dimensions: [c] dtype: <f8 data: !core/ndarray-1.0.0 data: [0.0, 0.0, -10.0] datatype: float64 shape: [3] - !<tag:weldx.bam.de:weldx/core/transformations/coordinate_transformation-1.0.0> name: T1 reference_system: workpiece transformation: !<tag:weldx.bam.de:weldx/core/transformations/local_coordinate_system-1.0.0> coordinates: !<tag:weldx.bam.de:weldx/core/variable-1.0.0> name: coordinates dimensions: [c] dtype: <f8 data: !core/ndarray-1.0.0 data: [200.0, 3.0, 5.0] datatype: float64 shape: [3] - !<tag:weldx.bam.de:weldx/core/transformations/coordinate_transformation-1.0.0> name: T2 reference_system: T1 transformation: !<tag:weldx.bam.de:weldx/core/transformations/local_coordinate_system-1.0.0> coordinates: !<tag:weldx.bam.de:weldx/core/variable-1.0.0> name: coordinates dimensions: [c] dtype: <f8 data: !core/ndarray-1.0.0 data: [0.0, 1.0, 0.0] datatype: float64 shape: [3] - !<tag:weldx.bam.de:weldx/core/transformations/coordinate_transformation-1.0.0> name: T3 reference_system: T2 transformation: !<tag:weldx.bam.de:weldx/core/transformations/local_coordinate_system-1.0.0> coordinates: !<tag:weldx.bam.de:weldx/core/variable-1.0.0> name: coordinates dimensions: [c] dtype: <f8 data: !core/ndarray-1.0.0 data: [0.0, 1.0, 0.0] datatype: float64 shape: [3] subsystem_names: [] workpiece: groove: !<tag:weldx.bam.de:weldx/groove/iso_9692_1_2013_12/VGroove-1.0.0> t: !unit/quantity-1.1.0 {unit: millimeter, value: 5} alpha: !unit/quantity-1.1.0 {unit: degree, value: 50} b: !unit/quantity-1.1.0 {unit: millimeter, value: 1} c: !unit/quantity-1.1.0 {unit: millimeter, value: 1} code_number: ['1.3', '1.5'] length: !unit/quantity-1.1.0 {unit: millimeter, value: 300} ...
Generated by nbsphinx from a Jupyter notebook.