Skip to content

Commit

Permalink
Merge pull request #633 from osrf/playback_event_recorder
Browse files Browse the repository at this point in the history
Add playback event recorder
  • Loading branch information
nkoenig authored Dec 10, 2020
2 parents 8e78d6a + bf7703b commit cacce19
Show file tree
Hide file tree
Showing 11 changed files with 2,133 additions and 114 deletions.
2 changes: 0 additions & 2 deletions subt_example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ add_executable(teleop_node src/teleop_node.cc)
add_dependencies(teleop_node ${catkin_EXPORTED_TARGETS})
target_link_libraries(teleop_node ${catkin_LIBRARIES})

# add_subdirectory(src/truth_controller)


###########
## Tests ##
Expand Down
29 changes: 29 additions & 0 deletions subt_ign/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,35 @@ install(TARGETS ${gas_emitter_detector_plugin_name}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})

# Create the libPlaybackEventRecorder.so library.
set(playback_event_recorder_name PlaybackEventRecorder)
add_library(${playback_event_recorder_name} SHARED
src/PlaybackEventRecorder.cc
src/PlaybackEventRecorder.cc
)

target_include_directories(${playback_event_recorder_name}
PRIVATE
${CATKIN_DEVEL_PREFIX}/include)
target_link_libraries(${playback_event_recorder_name}
PRIVATE
ignition-gazebo${IGN_GAZEBO_VER}::core
ignition-common3::ignition-common3
ignition-launch4::ignition-launch4
ignition-math6::ignition-math6
ignition-msgs7::ignition-msgs7
ignition-plugin1::loader
ignition-transport9::ignition-transport9
sdformat10::sdformat10
${catkin_LIBRARIES}
${YAML_CPP_LIBRARIES}
)

install(TARGETS ${playback_event_recorder_name}
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})

# Create log_checker executable.
add_executable(log_checker src/LogChecker.cc)
target_link_libraries(log_checker
Expand Down
3 changes: 3 additions & 0 deletions subt_ign/launch/path_tracer.ign
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
<% elsif $worldName.include?('urban_circuit_') &&
!$worldName.include?('practice') %>
<world_file>urban_circuit/<%= worldNumber %>/<%= $worldName %>.sdf</world_file>
<% elsif $worldName.include?('cave_circuit_') &&
!$worldName.include?('practice') %>
<world_file>cave_circuit/<%= worldNumber %>/<%= $worldName %>.sdf</world_file>
<% else %>
<world_file><%= $worldName %>.sdf</world_file>
<% end %>
Expand Down
82 changes: 82 additions & 0 deletions subt_ign/scripts/playback_event_recorder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Playback Event Recorder

The playback event recorder creates videos for events that are stored in the
events.yml log file in the state log directory.

Here are the events being recorded and their associated camera mode:

* robots exiting staging area: static camera above staging area looking down at angle
* rock fall: static camera above dynamic rocks model looking directly downward
* marsupial vehicle detaching child robot: camera follows the child robot
* artifact proximity: camera follows the robot
* region of interest (decision, vertical, elevation): camera follows the robot

## Running the demo

To create event videos for a subt log, run:

```
bash record_playback_events.bash <path_to_log_dir>
```

The script launches ign gazebo in playback mode and creates videos using the
GUI camera video recording feature. For each event, it seeks playback to some
time before the event, moves the camera to the desired location (either in
follow mode or moves to a static pose), and starts recording until some time
after the event. After recording all events, ign-gazebo will exit on its own
and you can find the recorded videos in a timestamped directory inside the
directory where the bash script is run.

## Video recorder settings

By default, the video recorder plugin records videos based on real time and
in lower quality than desired. In order to produce smooth high quality videos
with accurate timing, we need to specify a few video recorder
configurations in the `gui.config` file. The config file should be located in
`$HOME/.ignition/gazebo`. Find the 3D Scene plugin and add the following
`<record_video>` settings:

```xml
<!-- 3D scene -->
<plugin filename="GzScene3D" name="3D View">
<ignition-gui>
<title>3D View</title>
<property type="bool" key="showTitleBar">false</property>
<property type="string" key="state">docked</property>
</ignition-gui>

<engine>ogre2</engine>
<scene>scene</scene>
<ambient_light>0.4 0.4 0.4</ambient_light>
<background_color>0.8 0.8 0.8</background_color>
<camera_pose>6 0 6 0 0.5 3.14</camera_pose>

<record_video>
<use_sim_time>true</use_sim_time>
<lockstep>true</lockstep>
<bitrate>8000000</bitrate>
</record_video>

</plugin>
```

This makes sure the video recording is done in lock step with simulation
state updates so that we do not miss any frames during encoding. Additionally
sim time is used as timestamp so that the generated video length is unaffected
by the speed at which log playback is running in. For example, it may take
up to several hours to playback an event in a subt log due to low RTF but the
resulting video should still have a length that matches the specified duration
of the event.

## Known issue

The video recorder configurations are set to produce higher quality videos
but the encoding process is also more expensive. Since the server and the GUI
run asynchronously in two separate processes, we usually see that the GUI start
to lag behind the server after several minutes into recording. Once the ignition
transport msg queue is full, it starts dropping state msgs, and we would
notice missing frames in the generated videos. This is currently mitigated by
using a "catch-up" recording strategy in the playback event recorder, which
basically pauses the simulation when we detect the the video recorder is lagging
behind the server above some threshold, and only resumes playing back simulation
when the lag is within a reasonable amount of time.
104 changes: 104 additions & 0 deletions subt_ign/scripts/playback_event_recorder/playback_event_recorder.sdf
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?xml version='1.0'?>
<!--
Playback event recorder.
This world is used by the record_playback_events.bash script.
Videos will be saved to a timestamped directory inside the directory
where the bash script is run.
To set whether or not the gui camera should follow the entity
during video recording, change the <camera_follow> sdf parameter in the
PlaybackEventRecorder plugin to either true or false.
Usage: bash record_playback_events.bash <path_to_log_dir>
-->

<sdf version='1.6'>

<world name='default'>
<!--
<gui fullscreen="0">
<plugin filename="GzScene3D" name="3D View">
<ignition-gui>
<title>3D View</title>
<property type="bool" key="showTitleBar">false</property>
<property type="string" key="state">docked</property>
</ignition-gui>
<engine>ogre2</engine>
<scene>scene</scene>
<ambient_light>0.4 0.4 0.4</ambient_light>
<background_color>0.8 0.8 0.8</background_color>
<camera_pose>6 0 6 0 0.5 3.14</camera_pose>
</plugin>
<plugin filename="WorldControl" name="World control">
<ignition-gui>
<title>World control</title>
<property type="bool" key="showTitleBar">false</property>
<property type="bool" key="resizable">false</property>
<property type="double" key="height">72</property>
<property type="double" key="width">121</property>
<property type="double" key="z">1</property>
<property type="string" key="state">floating</property>
<anchors target="3D View">
<line own="left" target="left"/>
<line own="bottom" target="bottom"/>
</anchors>
</ignition-gui>
<play_pause>true</play_pause>
<step>true</step>
<start_paused>true</start_paused>
</plugin>
<plugin filename="WorldStats" name="World stats">
<ignition-gui>
<title>World stats</title>
<property type="bool" key="showTitleBar">false</property>
<property type="bool" key="resizable">false</property>
<property type="double" key="height">110</property>
<property type="double" key="width">290</property>
<property type="double" key="z">1</property>
<property type="string" key="state">floating</property>
<anchors target="3D View">
<line own="right" target="right"/>
<line own="bottom" target="bottom"/>
</anchors>
</ignition-gui>
<sim_time>true</sim_time>
<real_time>true</real_time>
<real_time_factor>true</real_time_factor>
<iterations>true</iterations>
</plugin>
</gui>
-->

<plugin filename='ignition-gazebo-scene-broadcaster-system'
name='ignition::gazebo::systems::SceneBroadcaster'>
<state_hertz>25</state_hertz>
</plugin>
<plugin
filename='ignition-gazebo-log-system'
name='ignition::gazebo::systems::LogPlayback'>
<path>tmp_record</path>
</plugin>

<plugin
filename="ignition-gazebo-user-commands-system"
name="ignition::gazebo::systems::UserCommands">
</plugin>

<plugin
filename="libPlaybackEventRecorder.so"
name="subt::PlaybackEventRecorder">
<log_path>tmp_record</log_path>
<exit_on_finish>true</exit_on_finish>
<spawn_light>true</spawn_light>
</plugin>

</world>
</sdf>

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/bin/bash

# The playback event recorder creates videos for events that are stored
# in the events.yml log file in the state log directory. The script launches
# ign gazebo in playback mode and creates videos using the gui camera video
# recording feature. For each event, it seeks playback to some time before the
# event, moves the camera to the desired location, and starts recording until
# some time after the event.

echo "==================================="
echo "Staring Playback Event Recorder"
echo "==================================="

if [ -z "$1" ]; then
echo "Usage: bash ./record_playback_events.bash [path_to_log_dir]"
exit 0
fi

logDirPath=$1

if [ ! -d "$logDirPath" ]; then
echo "Directory does not exist: $logDirPath"
exit 0
fi

scriptDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
tmpDir="tmp_record"

echo "Creating tmp dir for recording: $tmpDir"

if [ -d "$tmpDir" ]; then
rm -fr $tmpDir
fi

ln -s $logDirPath $tmpDir

echo "Starting log playback and video recording"

export IGN_GAZEBO_SYSTEM_PLUGIN_PATH=$LD_LIBRARY_PATH
sdfName="playback_event_recorder"
ign gazebo -v 4 "$scriptDir/$sdfName.sdf"

echo "Video recording ended. Shutting down playback"

pgrep -f $sdfName | xargs kill -9 &> /dev/null

videoDir=$(date +%s)
echo "Moving mp4 videos to dir: $videoDir"
mkdir $videoDir
mv *.mp4 $videoDir

# remove tmp dir
if [ -d "$tmpDir" ]; then
rm -fr $tmpDir
fi
echo "Done"

Loading

0 comments on commit cacce19

Please sign in to comment.