Notebook: Lukas Winiwarter, 2022
In this demo, we demonstrate how a scanner with multiple scanlines, such as the Velodyne® VLP-16, can be configured in HELIOS++. The demo contains two surveys, one for a static simulation (scanner at a single location) and one for a dynamic simulation (scanner moving between waypoints).
import sys, os
from pathlib import Path
from IPython.display import Code
current_folder = globals()["_dh"][0]
helios_path = str(Path(current_folder).parent)
sys.path.append(helios_path) # add helios-plusplus directory to PATH
import pyhelios
from pyhelios.util.xmldisplayer import display_xml, find_playback_dir
As the scanner is the main component in this demo, we investigate the scanner XML file tls_scanners.xml
. Here, we find a predefined Velodyne VLP-16. Other scanners, such as the Velodyne Puck LITE, or the Ouster OS2 can be implemented in similar ways.
os.chdir(helios_path)
Code(display_xml('data/scanners_tls.xml', 'vlp16'))
<scanner id="vlp16" accuracy_m="0.03" beamDivergence_rad="0.0007" name="Velodyne VLP-16" optics="rotating" pulseFreqs_Hz="18750" pulseLength_ns="4" rangeMin_m="0.0100" rangeMax_m="100" scanAngleMax_deg="1" scanAngleEffectiveMax_deg="1" scanFreqMin_Hz="0" scanFreqMax_Hz="0" wavelength_nm="532" headRotatePerSecMax_deg="7200">
<FWFSettings beamSampleQuality="1" /> <!-- set to one for fast simulations -->
<channels>
<channel id="0">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="-15" />
</beamOrigin>
</channel>
<channel id="1">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="1" />
</beamOrigin>
</channel>
<channel id="2">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="-13" />
</beamOrigin>
</channel>
<channel id="3">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="3" />
</beamOrigin>
</channel>
<channel id="4">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="-11" />
</beamOrigin>
</channel>
<channel id="5">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="5" />
</beamOrigin>
</channel>
<channel id="6">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="-9" />
</beamOrigin>
</channel>
<channel id="7">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="7" />
</beamOrigin>
</channel>
<channel id="8">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="-7" />
</beamOrigin>
</channel>
<channel id="9">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="9" />
</beamOrigin>
</channel>
<channel id="10">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="-5" />
</beamOrigin>
</channel>
<channel id="11">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="11" />
</beamOrigin>
</channel>
<channel id="12">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="-3" />
</beamOrigin>
</channel>
<channel id="13">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="13" />
</beamOrigin>
</channel>
<channel id="14">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="-1" />
</beamOrigin>
</channel>
<channel id="15">
<beamOrigin x="0" y="0" z="0">
<rot axis="x" angle_deg="15" />
</beamOrigin>
</channel>
</channels>
</scanner>
The scanner is defined with rotating
optics, but the values for scanFreqMin_Hz
and scanFreqMax_Hz
(both "0"
) show that this feature is not used in this implementation. Additionaly, the scanAngleMax_deg
is set to a value of 1
. Subsequently, 16 channel
s are defined, each with their individual rotations. As the scan plane is not used (default would be the y/z-Plane, see the wiki) and only a single direction per pulse is given, a simple rotation upwards or downwards about the x
axis is sufficient. The values for the angles are taken from the user manual of the VLP-16 (pages 54-55).
The pulseFreq_hz
in the <scannerSettings >
is coming from the max. measurement rate of the VLP-16 (300,000 pts/sec). The headRotatePerSecMax_deg
value corresponds to what Velodyne refers to as scan frequency - this is not to be confused with the within-scan line scanFreq_hz
we use for e.g. RIEGL-type TLS sensors. The user manual gives a value of 1200 rpm
as a maximum rotation speed of the motor, equivalent to 20 rotations per seconds (20 Hz scan frequency), or a rotation speed headRotatePerSecMax_deg
of 7200
(20 * 360deg).
Let us now use a simple scene (just containing a cube with 100 m side length, centered around the origin) to carry out two surveys:
Code(display_xml('data/surveys/demo/box_survey_static_puck.xml'))
<document>
<scannerSettings id="scaset" active="true" pulseFreq_hz="18750" scanFreq_hz="0" />
<survey name="box_puck_static" scene="data/scenes/demo/box_scene.xml#box_scene" platform="data/platforms.xml#tripod" scanner="data/scanners_tls.xml#vlp16">
<leg>
<platformSettings x="0" y="0" z="0" />
<scannerSettings template="scaset" headRotatePerSec_deg="3600" headRotateStart_deg="0" headRotateStop_deg="3600" /> <!-- 1 second integration time -->
</leg>
</survey>
</document>
Here, we note two things:
the value of headRotatePerSec_deg
, which here corresponds to 10 rotations per second, or 600 rotations per minute. The user manual explains that values between 300 and 1200 rpm, in increments of 60 rpm, are permissible.
the range between headRotateStart_deg
and headRotateStop_deg
. Combined with the rotation speed, this gives the sensor's integration time. In this example, 10 full rotations (10 * 360 deg) are carried out, which takes (at a rotation speed of 10 rotations per second or 3600 deg per second) one second. We are now ready to
!"run/helios" data/surveys/demo/box_survey_static_puck.xml -q
Now let's find the output files and display a 3D plot for all points recorded in the first 1/10th second (one rotation). You can see how the 'zero' location of the scanner is towards the positive Y-axis.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
output_path = find_playback_dir("data/surveys/demo/box_survey_static_puck.xml")
print("Loading points from", Path(output_path).relative_to(helios_path).as_posix())
SP1 = pd.read_csv(Path(output_path) / 'leg000_points.xyz',
names="X Y Z intensity echoWidth returnNumber numberOfReturns fullwaveIndex hitObjectId class gpsTime".split(' '),
delimiter=' ')
SP_filtered = SP1[SP1['gpsTime'] <= min(SP1['gpsTime']) + 0.1] # select all points recorded in the first 1/10 second
fig = plt.figure(figsize=(15,10))
ax = fig.add_subplot(projection='3d')
ax.scatter(SP_filtered['X'], SP_filtered['Y'], SP_filtered['Z'], s=0.1, c=SP_filtered['gpsTime'])
ax.scatter([0], [0], [0], s=50, c='red')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.tick_params(labelsize=16)
plt.show()
Loading points from output/box_puck_static/2023-02-27_09-20-29
We now want to simulate a moving scanner (e.g. a driving car). We use the same scene as before, but move the scanner from (-40, 0, 0)
to (40, 0, 0)
over a course of 10 seconds (8 m/s
). Note how we have to adapt the headRotateStop_deg
to 36000
to allow for 10 seconds of operation (at a rotation of 10
Hz) before the survey exits.
Code(display_xml('data/surveys/demo/box_survey_moving_puck.xml'))
<document>
<scannerSettings id="scaset" active="true" pulseFreq_hz="18750" scanFreq_hz="0" />
<survey name="box_puck_moving" scene="data/scenes/demo/box_scene.xml#box_scene" platform="data/platforms.xml#simple_linearpath" scanner="data/scanners_tls.xml#vlp16">
<leg>
<platformSettings x="-40" y="0" z="0" movePerSec_m="8" /> <!-- with 8 m/s, we make it to +40 in 10 seconds -->
<scannerSettings template="scaset" trajectoryTimeInterval_s="0.01" headRotatePerSec_deg="3600" headRotateStart_deg="0" headRotateStop_deg="36000" /> <!-- the rotation will also take 10 seconds -->
</leg>
<leg>
<platformSettings x="40" y="0" z="0" />
<scannerSettings active="false" />
</leg>
</survey>
</document>
!"run/helios" data/surveys/demo/box_survey_moving_puck.xml
HELIOS++ VERSION 1.2.0 CWD: "H:\helios4pyhelios\helios" seed: AUTO surveyPath: "data/surveys/demo/box_survey_moving_puck.xml" assetsPath: "assets/" outputPath: "output/" writeWaveform: 0 calcEchowidth: 0 fullWaveNoise: 0 splitByChannel: 0 parallelization: 1 njobs: 0 chunkSize: 32 warehouseFactor: 4 platformNoiseDisabled: 0 legNoiseDisabled: 0 rebuildScene: 0 lasOutput: 0 las10: 0 fixedIncidenceAngle: 0 gpsStartTime: kdtType: 4 kdtJobs: 0 kdtGeomJobs: 0 sahLossNodes: 32 xmlDocFilename: box_survey_moving_puck.xml xmlDocFilePath: data/surveys/demo xmlDocFilename: scanners_tls.xml xmlDocFilePath: data Using default value for attribute 'averagePower_w' : 4 Using default value for attribute 'beamQualityFactor' : 1 Using default value for attribute 'opticalEfficiency' : 0.99 Using default value for attribute 'receiverDiameter_m' : 0.15 Using default value for attribute 'atmosphericVisibility_km' : 23 Using default value for attribute 'binSize_ns' : 0.25 Using default value for attribute 'winSize_ns' : 1 Using default value for attribute 'maxFullwaveRange_ns' : 0 Number of subsampling rays (0): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (1): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (2): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (3): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (4): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (5): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (6): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (7): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (8): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (9): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (10): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (11): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (12): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (13): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (14): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 Number of subsampling rays (15): 1 Using default value for attribute 'scanFreqMin_Hz' : 0 Using default value for attribute 'scanFreqMax_Hz' : 0 Using default value for attribute 'scanAngleEffectiveMax_deg' : 1 Using default value for attribute 'accuracy_m' : 0.03 Using default value for attribute 'rangeMin_m' : 0.01 Using default value for attribute 'rangeMax_m' : 100 Using default value for attribute 'headRotatePerSecMax_deg' : 7200 Using default value for attribute 'beamDivergence_rad' : 0.0007 Using default value for attribute 'pulseLength_ns' : 4 Using default value for attribute 'maxNOR' : 0 xmlDocFilename: platforms.xml xmlDocFilePath: data Number of subsampling rays (0): 1 Using default value for attribute 'numRuns' : 1 Using default value for attribute 'simSpeed' : 1 Using default value for attribute 'stripId' : NULL_STRIP_ID Using platform default value for attribute 'onGround' : 0 Using platform default value for attribute 'stopAndTurn' : 1 Using platform default value for attribute 'smoothTurn' : 0 Using platform default value for attribute 'slowdownEnabled' : 1 Using scanner default value for attribute 'beamDivergence_rad' : 0.003 Using scanner default value for attribute 'trajectoryTimeInterval_s' : 0 Using default value for attribute 'name' : Unnamed scannerSettings asset Using scanner default value for attribute 'active' : 1 Using scanner default value for attribute 'pulseFreq_hz' : 18750 Using scanner default value for attribute 'scanFreq_hz' : 0 Using scanner default value for attribute 'beamDivergence_rad' : 0.003 Using default value for attribute 'stripId' : NULL_STRIP_ID Using platform default value for attribute 'onGround' : 0 Using platform default value for attribute 'stopAndTurn' : 1 Using platform default value for attribute 'smoothTurn' : 0 Using platform default value for attribute 'slowdownEnabled' : 1 Using platform default value for attribute 'movePerSec_m' : 70 Using scanner default value for attribute 'pulseFreq_hz' : 0 Using scanner default value for attribute 'scanFreq_hz' : 0 Using scanner default value for attribute 'beamDivergence_rad' : 0.003 Using scanner default value for attribute 'trajectoryTimeInterval_s' : 0 Loading Scene... Reading serial scene wrapper object from data/scenes/demo/box_scene.scene ... Building KD-Grove... KDTree (num. primitives 12) : Max. # primitives in leaf: 6 Min. # primitives in leaf: 4 Max. depth reached: 14 KDTree axis-aligned surface area: 60000 Interior nodes: 80 Leaf nodes: 81 Total tree cost: 9.03226 KDGrove stats: Number of trees: 1 Number of static trees: 1 Number of dynamic trees: 0 Statistics (min, max, total, mean, stdev): Building time: (0.0190, 0.0190, 0.0190, 0.0190, 0.0000) Tree primitives: (12, 12, 12, 12.0000, 0.0000) Max primitives in leaf: (6, 6, 6, 6.0000, 0.0000) Min primitives in leaf: (4, 4, 4, 4.0000, 0.0000) Maximum depth: (14, 14, 14, 14.0000, 0.0000) Axis-aligned surface area: (60000.0000, 60000.0000, 60000.0000, 60000.0000, 0.0000) Number of interior nodes: (80, 80, 80, 80.0000, 0.0000) Number of leaf nodes: (81, 81, 81, 81.0000, 0.0000) Tree cost: (9.0323, 9.0323, 9.0323, 9.0323, 0.0000) KDG built in 0.019s Scene loaded in 0.021s Reading Spectral Library... Using default value for attribute 'seed' : AUTO Output directory: "output/\box_puck_moving\2023-02-27_09-20-34\" Simulation: Scanner changed! Starting leg 0 Pulse frequency set to 18750 Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Iterative mode was used for manual leg initialization because default one failed for MovingPlatform Leg0 waypoints: Origin: (10, 50, 50) Target: (90, 50, 50) Next: (90, 50, 50) Running simulation... Clearing point cloud: "output/\box_puck_moving\2023-02-27_09-20-34\leg000_points.xyz" Survey 1.00% Elapsed 00 00:00:00 Remaining 00 00:00:12 Leg1/1 1.00% Elapsed 00 00:00:00 Remaining 00 00:00:12 Survey 2.00% Elapsed 00 00:00:00 Remaining 00 00:00:17 Leg1/1 2.00% Elapsed 00 00:00:00 Remaining 00 00:00:17 Survey 3.00% Elapsed 00 00:00:00 Remaining 00 00:00:17 Leg1/1 3.00% Elapsed 00 00:00:00 Remaining 00 00:00:17 Survey 4.00% Elapsed 00 00:00:00 Remaining 00 00:00:17 Leg1/1 4.00% Elapsed 00 00:00:00 Remaining 00 00:00:17 Survey 5.00% Elapsed 00 00:00:00 Remaining 00 00:00:17 Leg1/1 5.00% Elapsed 00 00:00:00 Remaining 00 00:00:17 Survey 6.00% Elapsed 00 00:00:01 Remaining 00 00:00:18 Leg1/1 6.00% Elapsed 00 00:00:01 Remaining 00 00:00:18 Survey 7.00% Elapsed 00 00:00:01 Remaining 00 00:00:17 Leg1/1 7.00% Elapsed 00 00:00:01 Remaining 00 00:00:17 Survey 8.00% Elapsed 00 00:00:01 Remaining 00 00:00:17 Leg1/1 8.00% Elapsed 00 00:00:01 Remaining 00 00:00:17 Survey 9.00% Elapsed 00 00:00:01 Remaining 00 00:00:17 Leg1/1 9.00% Elapsed 00 00:00:01 Remaining 00 00:00:17 Survey 10.00% Elapsed 00 00:00:01 Remaining 00 00:00:17 Leg1/1 10.00% Elapsed 00 00:00:01 Remaining 00 00:00:17 Survey 11.00% Elapsed 00 00:00:02 Remaining 00 00:00:17 Leg1/1 11.00% Elapsed 00 00:00:02 Remaining 00 00:00:17 Survey 12.00% Elapsed 00 00:00:02 Remaining 00 00:00:17 Leg1/1 12.00% Elapsed 00 00:00:02 Remaining 00 00:00:17 Survey 13.00% Elapsed 00 00:00:02 Remaining 00 00:00:17 Leg1/1 13.00% Elapsed 00 00:00:02 Remaining 00 00:00:17 Survey 14.00% Elapsed 00 00:00:02 Remaining 00 00:00:17 Leg1/1 14.00% Elapsed 00 00:00:02 Remaining 00 00:00:17 Survey 15.00% Elapsed 00 00:00:02 Remaining 00 00:00:16 Leg1/1 15.00% Elapsed 00 00:00:02 Remaining 00 00:00:16 Survey 16.00% Elapsed 00 00:00:03 Remaining 00 00:00:16 Leg1/1 16.00% Elapsed 00 00:00:03 Remaining 00 00:00:16 Survey 17.00% Elapsed 00 00:00:03 Remaining 00 00:00:16 Leg1/1 17.00% Elapsed 00 00:00:03 Remaining 00 00:00:16 Survey 18.00% Elapsed 00 00:00:03 Remaining 00 00:00:16 Leg1/1 18.00% Elapsed 00 00:00:03 Remaining 00 00:00:16 Survey 19.00% Elapsed 00 00:00:03 Remaining 00 00:00:16 Leg1/1 19.00% Elapsed 00 00:00:03 Remaining 00 00:00:16 Survey 20.00% Elapsed 00 00:00:04 Remaining 00 00:00:16 Leg1/1 20.00% Elapsed 00 00:00:04 Remaining 00 00:00:16 Survey 21.00% Elapsed 00 00:00:04 Remaining 00 00:00:15 Leg1/1 21.00% Elapsed 00 00:00:04 Remaining 00 00:00:15 Survey 22.00% Elapsed 00 00:00:04 Remaining 00 00:00:15 Leg1/1 22.00% Elapsed 00 00:00:04 Remaining 00 00:00:15 Survey 23.00% Elapsed 00 00:00:04 Remaining 00 00:00:15 Leg1/1 23.00% Elapsed 00 00:00:04 Remaining 00 00:00:15 Survey 24.00% Elapsed 00 00:00:04 Remaining 00 00:00:15 Leg1/1 24.00% Elapsed 00 00:00:04 Remaining 00 00:00:15 Survey 25.00% Elapsed 00 00:00:05 Remaining 00 00:00:15 Leg1/1 25.00% Elapsed 00 00:00:05 Remaining 00 00:00:15 Survey 26.00% Elapsed 00 00:00:05 Remaining 00 00:00:14 Leg1/1 26.00% Elapsed 00 00:00:05 Remaining 00 00:00:14 Survey 27.00% Elapsed 00 00:00:05 Remaining 00 00:00:14 Leg1/1 27.00% Elapsed 00 00:00:05 Remaining 00 00:00:14 Survey 28.00% Elapsed 00 00:00:05 Remaining 00 00:00:14 Leg1/1 28.00% Elapsed 00 00:00:05 Remaining 00 00:00:14 Survey 29.00% Elapsed 00 00:00:05 Remaining 00 00:00:14 Leg1/1 29.00% Elapsed 00 00:00:05 Remaining 00 00:00:14 Survey 30.00% Elapsed 00 00:00:06 Remaining 00 00:00:14 Leg1/1 30.00% Elapsed 00 00:00:06 Remaining 00 00:00:14 Survey 31.00% Elapsed 00 00:00:06 Remaining 00 00:00:13 Leg1/1 31.00% Elapsed 00 00:00:06 Remaining 00 00:00:13 Survey 32.00% Elapsed 00 00:00:06 Remaining 00 00:00:13 Leg1/1 32.00% Elapsed 00 00:00:06 Remaining 00 00:00:13 Survey 33.00% Elapsed 00 00:00:06 Remaining 00 00:00:13 Leg1/1 33.00% Elapsed 00 00:00:06 Remaining 00 00:00:13 Survey 34.00% Elapsed 00 00:00:06 Remaining 00 00:00:13 Leg1/1 34.00% Elapsed 00 00:00:06 Remaining 00 00:00:13 Survey 35.00% Elapsed 00 00:00:07 Remaining 00 00:00:13 Leg1/1 35.00% Elapsed 00 00:00:07 Remaining 00 00:00:13 Survey 36.00% Elapsed 00 00:00:07 Remaining 00 00:00:12 Leg1/1 36.00% Elapsed 00 00:00:07 Remaining 00 00:00:12 Survey 37.00% Elapsed 00 00:00:07 Remaining 00 00:00:12 Leg1/1 37.00% Elapsed 00 00:00:07 Remaining 00 00:00:12 Survey 38.00% Elapsed 00 00:00:07 Remaining 00 00:00:12 Leg1/1 38.00% Elapsed 00 00:00:07 Remaining 00 00:00:12 Survey 39.00% Elapsed 00 00:00:07 Remaining 00 00:00:12 Leg1/1 39.00% Elapsed 00 00:00:07 Remaining 00 00:00:12 Survey 40.00% Elapsed 00 00:00:08 Remaining 00 00:00:12 Leg1/1 40.00% Elapsed 00 00:00:08 Remaining 00 00:00:12 Survey 41.00% Elapsed 00 00:00:08 Remaining 00 00:00:11 Leg1/1 41.00% Elapsed 00 00:00:08 Remaining 00 00:00:11 Survey 42.00% Elapsed 00 00:00:08 Remaining 00 00:00:11 Leg1/1 42.00% Elapsed 00 00:00:08 Remaining 00 00:00:11 Survey 43.00% Elapsed 00 00:00:08 Remaining 00 00:00:11 Leg1/1 43.00% Elapsed 00 00:00:08 Remaining 00 00:00:11 Survey 44.00% Elapsed 00 00:00:08 Remaining 00 00:00:11 Leg1/1 44.00% Elapsed 00 00:00:08 Remaining 00 00:00:11 Survey 45.00% Elapsed 00 00:00:09 Remaining 00 00:00:11 Leg1/1 45.00% Elapsed 00 00:00:09 Remaining 00 00:00:11 Survey 46.00% Elapsed 00 00:00:09 Remaining 00 00:00:11 Leg1/1 46.00% Elapsed 00 00:00:09 Remaining 00 00:00:11 Survey 47.00% Elapsed 00 00:00:09 Remaining 00 00:00:10 Leg1/1 47.00% Elapsed 00 00:00:09 Remaining 00 00:00:10 Survey 48.00% Elapsed 00 00:00:09 Remaining 00 00:00:10 Leg1/1 48.00% Elapsed 00 00:00:09 Remaining 00 00:00:10 Survey 49.00% Elapsed 00 00:00:09 Remaining 00 00:00:10 Leg1/1 49.00% Elapsed 00 00:00:09 Remaining 00 00:00:10 Survey 50.00% Elapsed 00 00:00:10 Remaining 00 00:00:10 Leg1/1 50.00% Elapsed 00 00:00:10 Remaining 00 00:00:10 Survey 51.00% Elapsed 00 00:00:10 Remaining 00 00:00:09 Leg1/1 51.00% Elapsed 00 00:00:10 Remaining 00 00:00:09 Survey 52.00% Elapsed 00 00:00:10 Remaining 00 00:00:09 Leg1/1 52.00% Elapsed 00 00:00:10 Remaining 00 00:00:09 Survey 53.00% Elapsed 00 00:00:10 Remaining 00 00:00:09 Leg1/1 53.00% Elapsed 00 00:00:10 Remaining 00 00:00:09 Survey 54.00% Elapsed 00 00:00:10 Remaining 00 00:00:09 Leg1/1 54.00% Elapsed 00 00:00:10 Remaining 00 00:00:09 Survey 55.00% Elapsed 00 00:00:11 Remaining 00 00:00:09 Leg1/1 55.00% Elapsed 00 00:00:11 Remaining 00 00:00:09 Survey 56.00% Elapsed 00 00:00:11 Remaining 00 00:00:08 Leg1/1 56.00% Elapsed 00 00:00:11 Remaining 00 00:00:08 Survey 57.00% Elapsed 00 00:00:11 Remaining 00 00:00:08 Leg1/1 57.00% Elapsed 00 00:00:11 Remaining 00 00:00:08 Survey 58.00% Elapsed 00 00:00:11 Remaining 00 00:00:08 Leg1/1 58.00% Elapsed 00 00:00:11 Remaining 00 00:00:08 Survey 59.00% Elapsed 00 00:00:11 Remaining 00 00:00:08 Leg1/1 59.00% Elapsed 00 00:00:11 Remaining 00 00:00:08 Survey 60.00% Elapsed 00 00:00:12 Remaining 00 00:00:08 Leg1/1 60.00% Elapsed 00 00:00:12 Remaining 00 00:00:08 Survey 61.00% Elapsed 00 00:00:12 Remaining 00 00:00:07 Leg1/1 61.00% Elapsed 00 00:00:12 Remaining 00 00:00:07 Survey 62.00% Elapsed 00 00:00:12 Remaining 00 00:00:07 Leg1/1 62.00% Elapsed 00 00:00:12 Remaining 00 00:00:07 Survey 63.00% Elapsed 00 00:00:12 Remaining 00 00:00:07 Leg1/1 63.00% Elapsed 00 00:00:12 Remaining 00 00:00:07 Survey 64.00% Elapsed 00 00:00:13 Remaining 00 00:00:07 Leg1/1 64.00% Elapsed 00 00:00:13 Remaining 00 00:00:07 Survey 65.00% Elapsed 00 00:00:13 Remaining 00 00:00:07 Leg1/1 65.00% Elapsed 00 00:00:13 Remaining 00 00:00:07 Survey 66.00% Elapsed 00 00:00:13 Remaining 00 00:00:06 Leg1/1 66.00% Elapsed 00 00:00:13 Remaining 00 00:00:06 Survey 67.00% Elapsed 00 00:00:13 Remaining 00 00:00:06 Leg1/1 67.00% Elapsed 00 00:00:13 Remaining 00 00:00:06 Survey 68.00% Elapsed 00 00:00:13 Remaining 00 00:00:06 Leg1/1 68.00% Elapsed 00 00:00:13 Remaining 00 00:00:06 Survey 69.00% Elapsed 00 00:00:14 Remaining 00 00:00:06 Leg1/1 69.00% Elapsed 00 00:00:14 Remaining 00 00:00:06 Survey 70.00% Elapsed 00 00:00:14 Remaining 00 00:00:06 Leg1/1 70.00% Elapsed 00 00:00:14 Remaining 00 00:00:06 Survey 71.00% Elapsed 00 00:00:14 Remaining 00 00:00:05 Leg1/1 71.00% Elapsed 00 00:00:14 Remaining 00 00:00:05 Survey 72.00% Elapsed 00 00:00:14 Remaining 00 00:00:05 Leg1/1 72.00% Elapsed 00 00:00:14 Remaining 00 00:00:05 Survey 73.00% Elapsed 00 00:00:14 Remaining 00 00:00:05 Leg1/1 73.00% Elapsed 00 00:00:14 Remaining 00 00:00:05 Survey 74.00% Elapsed 00 00:00:15 Remaining 00 00:00:05 Leg1/1 74.00% Elapsed 00 00:00:15 Remaining 00 00:00:05 Survey 75.00% Elapsed 00 00:00:15 Remaining 00 00:00:05 Leg1/1 75.00% Elapsed 00 00:00:15 Remaining 00 00:00:05 Survey 76.00% Elapsed 00 00:00:15 Remaining 00 00:00:04 Leg1/1 76.00% Elapsed 00 00:00:15 Remaining 00 00:00:04 Survey 77.00% Elapsed 00 00:00:15 Remaining 00 00:00:04 Leg1/1 77.00% Elapsed 00 00:00:15 Remaining 00 00:00:04 Survey 78.00% Elapsed 00 00:00:15 Remaining 00 00:00:04 Leg1/1 78.00% Elapsed 00 00:00:15 Remaining 00 00:00:04 Survey 79.00% Elapsed 00 00:00:16 Remaining 00 00:00:04 Leg1/1 79.00% Elapsed 00 00:00:16 Remaining 00 00:00:04 Survey 80.00% Elapsed 00 00:00:16 Remaining 00 00:00:04 Leg1/1 80.00% Elapsed 00 00:00:16 Remaining 00 00:00:04 Survey 81.00% Elapsed 00 00:00:16 Remaining 00 00:00:03 Leg1/1 81.00% Elapsed 00 00:00:16 Remaining 00 00:00:03 Survey 82.00% Elapsed 00 00:00:16 Remaining 00 00:00:03 Leg1/1 82.00% Elapsed 00 00:00:16 Remaining 00 00:00:03 Survey 83.00% Elapsed 00 00:00:16 Remaining 00 00:00:03 Leg1/1 83.00% Elapsed 00 00:00:16 Remaining 00 00:00:03 Survey 84.00% Elapsed 00 00:00:17 Remaining 00 00:00:03 Leg1/1 84.00% Elapsed 00 00:00:17 Remaining 00 00:00:03 Survey 85.00% Elapsed 00 00:00:17 Remaining 00 00:00:03 Leg1/1 85.00% Elapsed 00 00:00:17 Remaining 00 00:00:03 Survey 86.00% Elapsed 00 00:00:17 Remaining 00 00:00:02 Leg1/1 86.00% Elapsed 00 00:00:17 Remaining 00 00:00:02 Survey 87.00% Elapsed 00 00:00:17 Remaining 00 00:00:02 Leg1/1 87.00% Elapsed 00 00:00:17 Remaining 00 00:00:02 Survey 88.00% Elapsed 00 00:00:17 Remaining 00 00:00:02 Leg1/1 88.00% Elapsed 00 00:00:17 Remaining 00 00:00:02 Survey 89.00% Elapsed 00 00:00:18 Remaining 00 00:00:02 Leg1/1 89.00% Elapsed 00 00:00:18 Remaining 00 00:00:02 Survey 90.00% Elapsed 00 00:00:18 Remaining 00 00:00:02 Leg1/1 90.00% Elapsed 00 00:00:18 Remaining 00 00:00:02 Survey 91.00% Elapsed 00 00:00:18 Remaining 00 00:00:01 Leg1/1 91.00% Elapsed 00 00:00:18 Remaining 00 00:00:01 Survey 92.00% Elapsed 00 00:00:18 Remaining 00 00:00:01 Leg1/1 92.00% Elapsed 00 00:00:18 Remaining 00 00:00:01 Survey 93.00% Elapsed 00 00:00:18 Remaining 00 00:00:01 Leg1/1 93.00% Elapsed 00 00:00:18 Remaining 00 00:00:01 Survey 94.00% Elapsed 00 00:00:19 Remaining 00 00:00:01 Leg1/1 94.00% Elapsed 00 00:00:19 Remaining 00 00:00:01 Survey 95.00% Elapsed 00 00:00:19 Remaining 00 00:00:01 Leg1/1 95.00% Elapsed 00 00:00:19 Remaining 00 00:00:01 Survey 96.00% Elapsed 00 00:00:19 Remaining 00 00:00:00 Leg1/1 96.00% Elapsed 00 00:00:19 Remaining 00 00:00:00 Survey 97.00% Elapsed 00 00:00:19 Remaining 00 00:00:00 Leg1/1 97.00% Elapsed 00 00:00:19 Remaining 00 00:00:00 Survey 98.00% Elapsed 00 00:00:20 Remaining 00 00:00:00 Leg1/1 98.00% Elapsed 00 00:00:20 Remaining 00 00:00:00 Survey 99.00% Elapsed 00 00:00:20 Remaining 00 00:00:00 Leg1/1 99.00% Elapsed 00 00:00:20 Remaining 00 00:00:00 Survey 100.00% Elapsed 00 00:00:20 Remaining 00 00:00:00 Leg1/1 100.00% Elapsed 00 00:00:20 Remaining 00 00:00:00 Waypoint reached! Starting leg 1 Pulse frequency set to 18750 Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Scan angle set to 1 Applying settings for PolygonMirrorBeamDeflector... Vertical angle min/max -nan(ind)/-nan(ind) -- verticalAngleMin not set, using the value of -1 degrees -- verticalAngleMax not set, using the value of 1 degrees Waypoint reached! Elapsed simulation steps = 187503 Elapsed virtual time = 10.0002 sec. Main thread simulation loop finished in 20.4581 sec. Waiting for completion of pulse computation tasks... Pulse computation tasks finished in 20.4584 sec. Total simulation time: 0:00:20
Now let's find the output files and display a 3D plot for all points recorded in the first 1/10th second (one rotation). In a second plot, we plot the points recorded in the last 1/10th second (last rotation).
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
output_path = find_playback_dir(r"data/surveys/demo/box_survey_moving_puck.xml")
print("Loading points from", Path(output_path).relative_to(helios_path).as_posix())
SP1 = pd.read_csv(Path(output_path) / 'leg000_points.xyz',
names="X Y Z intensity echoWidth returnNumber numberOfReturns fullwaveIndex hitObjectId class gpsTime".split(' '),
delimiter=' ')
for fun in (min, max):
SP_filtered = SP1[abs(SP1['gpsTime']- fun(SP1['gpsTime'])) <= 0.1] # select all points recorded in the first/last 1/10 second
fig = plt.figure(figsize=(15,10))
ax = fig.add_subplot(projection='3d')
ax.scatter(SP_filtered['X'], SP_filtered['Y'], SP_filtered['Z'], s=0.1, c=SP_filtered['gpsTime'])
ax.scatter([-40 if fun is min else 40], [0], [0], s=50, c='red')
ax.tick_params(labelsize=16)
plt.title("Points recorded in the "+
("first " if fun is min else "last ")+
"full rotation")
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
Loading points from output/box_puck_moving/2023-02-27_09-20-34
In contrast to the static case, the 'zero' point now appears towards the positive x-Axis! What happened? The linearpath
platform oriented the sensor such that the default axis (which is y
for the scanners) is pointing forward in the direction of movement. As the platform (simple_linearpath
) does not provide any additional rotations (e.g. in contrast to the sr22
airborne platform), the scanner faces towards the direction of movement at the beginning of the scan.
The gaps in the 'far' corners are due to the maximum range of the scanner, given as 100 m.