Exemple #1
0
 def programmatic_run_stop(self):
     output.console_log_bold(
         f"Running experiment run with programmatic stop.")
     dir_path = os.path.dirname(os.path.realpath(__file__))
     self.run_poll_proc = subprocess.Popen(
         f"{sys.executable} {dir_path}/Scripts/PollRunCompletion.py",
         shell=True)
 def get_value_for_key(self, key):
     try:
         value = self.data[key]
         return value
     except KeyError:
         output.console_log_bold(f"Value requested from config.json with unknown key: ['{key}']")
         sys.exit(1)
 def subprocess_check_output(command: str, name: str):
     try:
         return subprocess.check_output(command, shell=True)
     except:
         output.console_log_bold(
             f"Something went wrong checking output for command: {command} for name: {name}"
         )
         sys.exit(1)
    def roscore_start(self):
        output.console_log("Starting ROS Master (roscore)...")
        self.roscore_proc = ProcessProcedure.subprocess_spawn("roscore", "roscore_start")
        while not ProcessProcedure.process_is_running('roscore') and \
                not ProcessProcedure.process_is_running('rosmaster') and \
                not ProcessProcedure.process_is_running('rosout'):
            output.console_log_animated("Waiting to confirm roscore running...")

        output.console_log_bold("ROS Master (roscore) is running!")
        time.sleep(1)  # Give roscore some time to initiate
    def rosbag_start_recording_topics(self, topics, file_path, bag_name):
        file_path += "-ros2"
        output.console_log(f"Rosbag2 starts recording...")
        output.console_log_bold("Recording topics: ")
        # Build 'rosbag record -O filename [/topic1 /topic2 ...] __name:=bag_name' command
        command = f" ros2 bag record --output {file_path}"
        for topic in topics:
            command += f" {topic}"
            output.console_log_bold(f" * {topic}")

        ProcessProcedure.subprocess_spawn(command, "ros2bag_record")
        time.sleep(1)  # Give rosbag recording some time to initiate
Exemple #6
0
    def signal_experiment_end(self):
        output.console_log("Experiment ended, signalling end to robot...")
        dir_path = os.path.dirname(os.path.realpath(__file__))
        exp_end_proc = subprocess.Popen(
            f"{sys.executable} {dir_path}/Scripts/SignalExperimentEnd.py",
            shell=True)

        while exp_end_proc.poll() is None:
            output.console_log_animated(
                "Waiting for robot to confirm experiment end...")

        output.console_log_bold("Successfully ended experiment!")
    def subprocess_spawn(command: str, name: str):
        try:
            if ProcessProcedure.verbose:
                return subprocess.Popen(command, shell=True)

            return subprocess.Popen(command,
                                    shell=True,
                                    stdout=ProcessProcedure.block_out,
                                    stderr=ProcessProcedure.block_out)
        except:
            output.console_log_bold(
                f"Something went wrong spawning subprocess {name}")
            sys.exit(1)
    def subprocess_call(command: str, name: str):
        try:
            if ProcessProcedure.verbose:
                subprocess.call(command, shell=True)
                return

            subprocess.call(command,
                            shell=True,
                            stdout=ProcessProcedure.block_out,
                            stderr=ProcessProcedure.block_out)
        except:
            output.console_log_bold(
                f"Something went wrong calling command: {command} for name: {name}"
            )
            sys.exit(1)
    def __init__(self, config_path):
        now = datetime.now().strftime("%d_%m_%Y-%H:%M:%S")
        self.data = self.load_json(config_path)

        # ===== LOAD DEFAULT CONFIG VALUES =====
        self.use_simulator = self.get_value_for_key('use_simulator')
        self.name = self.get_value_for_key('name')

        try:
            self.ros_version = int(os.environ['ROS_VERSION'])
        except ValueError:
            output.console_log_bold(
                "Unknown value for $ROS_VERSION env variable")
            sys.exit(1)

        self.replications = self.get_value_for_key('replications')
        self.duration = self.get_value_for_key('duration')

        self.launch_file_path = Path(
            self.get_value_for_key('launch_file_path'))

        script_json = self.get_value_for_key('run_script')
        self.run_script_model = RunScriptModel(script_json['path'],
                                               script_json['args'])

        self.topics_must_be_available = self.get_value_for_key(
            'topics_must_be_available')
        self.nodes_must_be_available = self.get_value_for_key(
            'nodes_must_be_available')

        self.output_path = Path(self.get_value_for_key('output_path'))

        self.topics_to_record = self.get_value_for_key('topics_to_record')

        self.time_between_run = self.get_value_for_key('time_between_run')

        # Build experiment specific, unique path
        self.exp_dir = Path(
            str(self.output_path.absolute()) + f"/{self.name}-{now}")
        output.console_log("Experiment config successfully loaded in")
        output.console_log_tabulate(self.data)
    def do_run(self):
        self.ros.roscore_start()

        self.wait_for_necessary_topics_and_nodes()

        output.console_log_bold(
            "All necessary nodes and topics available, everything is ready for experiment!"
        )

        self.ros.rosbag_start_recording_topics(
            self.config.topics_to_record,  # Topics to record
            str(self.run_dir.absolute()) + '/topics',  # Path to record .bag to
            f"rosbag_run{self.current_run}"  # Bagname to kill after run
        )

        self.run_runscript_if_present()
        self.set_run_stop()
        self.run_start()
        self.run_wait_completed()
        self.ros.rosbag_stop_recording_topics(f"rosbag_run{self.current_run}")
        self.ros.native_shutdown()
Exemple #11
0
    def __init__(self, config_path, verbose=False):
        self.verbose = verbose
        self.data = self.load_json(config_path)
        self.launch_command = self.get_value_for_key('launch_command')
        self.launch_file_path = self.get_value_for_key('launch_file_path')
        dir_path = os.path.dirname(os.path.realpath(__file__))

        while True:
            while ros_version == 1 and not self.is_roscore_ready():
                output.console_log_animated("Waiting for ROS Master...")

            output.console_log_bold("ROS Master ready!", empty_line=True)

            self.exp_end_proc = subprocess.Popen(f"{sys.executable} {dir_path}/Scripts/PollExperimentEnd.py",
                                                 shell=True)
            output.console_log_bold("Grace period for poll_experiment_end")
            time.sleep(5)

            if self.exp_end_proc.poll() is None:
                self.do_run()
            else:
                sys.exit(0)
    def do_run(self):
        # Check if a launch file is given, if so then run that as the experiment definition.
        # Otherwise, run a run_script if present. If not; throw error: no experiment definition available.
        if self.config.launch_file_path != "":
            self.ros.roslaunch_launch_file(
                launch_file=self.config.launch_file_path)
        else:
            if self.config.run_script_model.path == "" or self.config.run_script_model.path is None:
                output.console_log_bold(
                    "ERROR! No launch file or run script present... No experiment definition available!"
                )
                sys.exit(1)

            self.run_runscript_if_present()

        self.wait_for_simulation()  # Wait until Gazebo simulator is running
        self.wait_for_necessary_topics_and_nodes()

        output.console_log("Performing run...")

        # Simulation running, start recording topics
        self.ros.rosbag_start_recording_topics(
            self.config.topics_to_record,  # Topics to record
            str(self.run_dir.absolute()) + '/topics',  # Path to record .bag to
            f"rosbag_run{self.current_run}"  # Bagname to kill after run
        )

        if self.config.launch_file_path != "":
            # If the user set a script to be run while running an experiment run, run it.
            self.run_runscript_if_present()

        # Set run stop, timed or programmatic
        self.set_run_stop()
        self.run_start()

        self.run_wait_completed()

        self.ros.rosbag_stop_recording_topics(f"rosbag_run{self.current_run}")
        self.ros.sim_shutdown()
Exemple #13
0
    def do_experiment(self):
        self.config.exp_dir.mkdir(parents=True, exist_ok=True)

        current_run: int = 1
        while current_run <= self.config.replications:
            run_controller = None
            if self.config.use_simulator:
                run_controller = SimRunContoller(self.config, current_run)
            else:
                run_controller = NativeRunController(self.config, current_run)

            run_controller.do_run()

            current_run += 1

            time_btwn_runs = self.config.time_between_run
            if time_btwn_runs > 0 and time_btwn_runs is not None:
                output.console_log_bold(
                    f"Run fully ended, waiting for: {time_btwn_runs}ms == {time_btwn_runs / 1000}s"
                )
                time.sleep(time_btwn_runs / 1000)

        if not self.config.use_simulator:
            self.signal_experiment_end()
Exemple #14
0
                return json.load(config_file)
        except FileNotFoundError:
            output.console_log("File not found, make sure file exists or path is correct...")
            sys.exit(0)
        except ValueError:
            output.console_log("Decoding JSON has failed, please check validity of config file...")
            sys.exit(0)

    def get_value_for_key(self, key):
        try:
            value = self.data[key]
            return value
        except KeyError:
            output.console_log_bold(f"Value requested from config.json with unknown key: ['{key}']")
            sys.exit(1)


if __name__ == "__main__":
    argv_count = len(sys.argv)
    if argv_count == 2 and sys.argv[1] == "--help":  # Help CLI
        output.console_log("usage: python3 %s [PATH_TO_CONFIG.JSON]" % __file__)
        output.console_log_bold("optional: python3 %s --verbose [PATH_TO_CONFIG.JSON]" % __file__)
        sys.exit(0)
    elif argv_count == 2:  # Correct usage, continue to program
        RobotClient(sys.argv[1])
    elif argv_count == 3 and sys.argv[1] == '--verbose':
        RobotClient(sys.argv[2], verbose=True)
    else:  # Incorrect usage, display error and exit
        output.console_log("Incorrect usage, please run with --help to view possible arguments")
        sys.exit(0)
Exemple #15
0
 def signal_handler(sig, frame):
     output.console_log_bold("SIGINT, Terminating Robot Runner\n",
                             empty_line=True)
     sys.exit(0)
import os
import sys
import subprocess
from pathlib import Path
from abc import ABC, abstractmethod
from Procedures.OutputProcedure import OutputProcedure as output

try:
    ros_version = int(os.environ['ROS_VERSION'])
except ValueError:
    output.console_log_bold("Unknown value for $ROS_VERSION env variable")
    sys.exit(1)


###     =========================================================
###     |                                                       |
###     |                     IROSController                    |
###     |       - Provide abstract, implementation specific     |
###     |         methods for ROS1 or ROS2 to implement         |
###     |                                                       |
###     |       - Provide default, generic functions for both   |
###     |         ROS versions like get_available_topics()      |
###     |                                                       |
###     |       * Any function which is implementation          |
###     |         specific (ROS1 or ROS2) should be declared    |
###     |         here as an abstract function                  |
###     |                                                       |
###     |       * Any generic functionality between the two     |
###     |         ROS types should be declared here             |
###     |         as a function                                 |
###     |                                                       |
Exemple #17
0
 def timed_run_stop(self):
     output.console_log_bold(
         f"Running experiment run for: {self.config.duration}ms == {self.config.duration / 1000}s"
     )
     self.timed_stop = True