Exemple #1
0
def run_image_on_duckiebot(image_name, duckiebot_name, env=None, volumes=None):
    duckiebot_ip = get_duckiebot_ip(duckiebot_name)
    duckiebot_client = get_remote_client(duckiebot_ip)
    env_vars = default_env(duckiebot_name, duckiebot_ip)

    if env is not None:
        env_vars.update(env)

    dtslogger.info("Running %s with environment: %s" % (image_name, env_vars))

    params = {
        'image': image_name,
        'remove': True,
        'network_mode': 'host',
        'privileged': True,
        'detach': True,
        'environment': env_vars
    }

    if volumes is not None:
        params['volumes'] = volumes

    # Make sure we are not already running the same image
    if all(elem.image != image_name
           for elem in duckiebot_client.containers.list()):
        return duckiebot_client.containers.run(**params)
    else:
        dtslogger.warn(
            'Container with image %s is already running on %s, skipping...' %
            (image_name, duckiebot_name))
Exemple #2
0
def start_gui_tools(duckiebot_name):
    duckiebot_ip = get_duckiebot_ip(duckiebot_name)
    local_client = check_docker_environment()
    operating_system = platform.system()

    local_client.images.pull(RPI_GUI_TOOLS)

    env_vars = default_env(duckiebot_name, duckiebot_ip)
    env_vars['DISPLAY'] = True

    container_name = 'gui-tools-interactive'

    if operating_system == 'Linux':
        subprocess.call(["xhost", "+"])
        local_client.containers.run(image=RPI_GUI_TOOLS,
                                    network_mode='host',
                                    privileged=True,
                                    tty=True,
                                    name=container_name,
                                    environment=env_vars)
    elif operating_system == 'Darwin':
        IP = subprocess.check_output([
            '/bin/sh', '-c',
            'ifconfig en0 | grep inet | awk \'$1=="inet" {print $2}\''
        ])
        env_vars['IP'] = IP
        subprocess.call(["xhost", "+IP"])
        local_client.containers.run(image=RPI_GUI_TOOLS,
                                    network_mode='host',
                                    privileged=True,
                                    tty=True,
                                    name=container_name,
                                    environment=env_vars)

    attach_terminal(container_name)
Exemple #3
0
def start_slimremote_duckiebot_container(duckiebot_name, max_vel):
    duckiebot_ip = get_duckiebot_ip(duckiebot_name)
    duckiebot_client = get_remote_client(duckiebot_ip)

    container_name = 'evaluator'
    try:
        container = duckiebot_client.containers.get(container_name)
        dtslogger.info("slim remote already running on %s, restarting..." %
                       duckiebot_name)
        stop_container(container)
        remove_container(container)
    except Exception as e:
        dtslogger.info("Starting slim remote on %s" % duckiebot_name)

    parameters = {
        'image': SLIMREMOTE_IMAGE,
        'remove': True,
        'privileged': True,
        'detach': True,
        'environment': {
            "DUCKIETOWN_MAXSPEED": max_vel
        },
        'name': container_name,
        'ports': {
            '5558': '5558',
            '8902': '8902'
        },
    }

    return duckiebot_client.containers.run(**parameters)
Exemple #4
0
def attach_terminal(container_name, hostname=None):
    if hostname is not None:
        duckiebot_ip = get_duckiebot_ip(hostname)
        docker_attach_command = 'docker -H %s:2375 attach %s' % (
            duckiebot_ip, container_name)
    else:
        docker_attach_command = 'docker attach %s' % container_name
    return start_command_in_subprocess(docker_attach_command, os.environ)
Exemple #5
0
def run_gui_controller(hostname, image):
    client = check_docker_environment()
    container_name = "joystick_gui_%s" % hostname
    remove_if_running(client, container_name)
    duckiebot_ip = get_duckiebot_ip(hostname)
    env = {
        'HOSTNAME': hostname,
        'ROS_MASTER': hostname,
        'DUCKIEBOT_NAME': hostname,
        'ROS_MASTER_URI': 'http://%s:11311' % duckiebot_ip
    }

    env['QT_X11_NO_MITSHM'] = 1

    volumes = {}

    subprocess.call(["xhost", "+"])

    p = platform.system().lower()
    if 'darwin' in p:
        dtslogger.warn(
            "We can try but running the joystick gui on MacOSx is not expected to work..."
        )
        env['DISPLAY'] = 'host.docker.internal:0'
        volumes = {'/tmp/.X11-unix': {'bind': '/tmp/.X11-unix', 'mode': 'rw'}}
    else:
        env['DISPLAY'] = os.environ['DISPLAY']

    dtslogger.info("Running %s on localhost with environment vars: %s" %
                   (container_name, env))

    if 'master19' in image:
        image = "duckietown/rpi-duckiebot-base:master19-no-arm"
        cmd = "python misc/virtualJoy/virtualJoy.py %s" % hostname
    elif 'daffy' in image:
        image = "duckietown/dt-core:daffy-amd64"
        cmd = "roslaunch virtual_joystick virtual_joystick_gui.launch veh:=%s" % hostname

    params = {
        'image': image,
        'name': container_name,
        'network_mode': 'host',
        'environment': env,
        'privileged': True,
        'stdin_open': True,
        'tty': True,
        'command': cmd,
        'detach': True,
        'volumes': volumes
    }

    container = client.containers.run(**params)
    cmd = 'docker attach %s' % container_name
    start_command_in_subprocess(cmd)
Exemple #6
0
def run_cli_controller(hostname, image):
    duckiebot_ip = get_duckiebot_ip(hostname)
    duckiebot_client = docker.DockerClient('tcp://' + duckiebot_ip + ':2375')
    container_name = "joystick_cli_%s" % hostname
    remove_if_running(duckiebot_client, container_name)
    duckiebot_ip = get_duckiebot_ip(hostname)
    env = {
        'HOSTNAME': hostname,
        'ROS_MASTER': hostname,
        'DUCKIEBOT_NAME': hostname,
        'ROS_MASTER_URI': 'http://%s:11311' % duckiebot_ip
    }

    dtslogger.info("Running %s on localhost with environment vars: %s" %
                   (container_name, env))

    if 'master19' in image:
        image = "duckietown/rpi-duckiebot-base:master19"  # run on robot
        cmd = "python misc/virtualJoy/joy_cli.py %s" % hostname
    elif 'daffy' in image:
        image = "duckietown/dt-core:daffy"
        cmd = "roslaunch virtual_joystick virtual_joystick_cli.launch veh:=%s" % hostname

    params = {
        'image': image,
        'name': container_name,
        'network_mode': 'host',
        'environment': env,
        'privileged': True,
        'stdin_open': True,
        'tty': True,
        'command': cmd,
        'detach': True
    }

    container = duckiebot_client.containers.run(**params)

    cmd = 'docker -H %s.local attach %s' % (hostname, container_name)
    start_command_in_subprocess(cmd)
Exemple #7
0
def start_picamera(duckiebot_name):
    duckiebot_ip = get_duckiebot_ip(duckiebot_name)
    duckiebot_client = get_remote_client(duckiebot_ip)
    duckiebot_client.images.pull(RPI_DUCKIEBOT_ROS_PICAM)
    env_vars = default_env(duckiebot_name, duckiebot_ip)

    dtslogger.info("Running %s on %s with environment vars: %s" %
                   (RPI_DUCKIEBOT_ROS_PICAM, duckiebot_name, env_vars))

    return duckiebot_client.containers.run(image=RPI_DUCKIEBOT_ROS_PICAM,
                                           remove=True,
                                           network_mode='host',
                                           devices=['/dev/vchiq'],
                                           detach=True,
                                           environment=env_vars)
    def command(shell, args):
        prog = 'dts duckiebot keyboard_control DUCKIEBOT_NAME'
        usage = """
Keyboard control: 

    %(prog)s
"""

        parser = argparse.ArgumentParser(prog=prog, usage=usage)
        parser.add_argument('hostname',
                            default=None,
                            help='Name of the Duckiebot to calibrate')
        parser.add_argument(
            '--cli',
            dest='cli',
            default=False,
            action='store_true',
            help='A flag, if set will run with CLI instead of with GUI')
        parser.add_argument('--network',
                            default='host',
                            help='Name of the network which to connect')
        parser.add_argument('--sim',
                            action='store_true',
                            default=False,
                            help='are we running in simulator?')
        parser.add_argument(
            '--base_image',
            dest='image',
            default="duckietown/rpi-duckiebot-base:master19-no-arm",
            help="The base image, probably don't change the default")
        parsed_args = parser.parse_args(args)

        if parsed_args.sim:
            duckiebot_ip = "sim"
        else:
            duckiebot_ip = get_duckiebot_ip(
                duckiebot_name=parsed_args.hostname)

        network_mode = parsed_args.network

        if not parsed_args.cli:
            run_gui_controller(parsed_args.hostname, parsed_args.image,
                               duckiebot_ip, network_mode)
        else:
            run_cli_controller(parsed_args.hostname, parsed_args.image,
                               duckiebot_ip, network_mode, parsed_args.sim)
Exemple #9
0
def record_bag(duckiebot_name, duration):
    duckiebot_ip = get_duckiebot_ip(duckiebot_name)
    local_client = check_docker_environment()
    dtslogger.info("Starting bag recording...")
    parameters = {
        'image': RPI_DUCKIEBOT_BASE,
        'remove': True,
        'network_mode': 'host',
        'privileged': True,
        'detach': True,
        'environment': default_env(duckiebot_name, duckiebot_ip),
        'command':
        'bash -c "cd /data && rosbag record --duration %s -a"' % duration,
        'volumes': bind_local_data_dir()
    }

    # Mac Docker has ARM support directly in the Docker environment, so we don't need to run qemu...
    if platform.system() != 'Darwin':
        parameters['entrypoint'] = 'qemu3-arm-static'

    return local_client.containers.run(**parameters)
Exemple #10
0
def run_image_on_localhost(image_name,
                           duckiebot_name,
                           container_name,
                           env=None,
                           volumes=None):
    duckiebot_ip = get_duckiebot_ip(duckiebot_name)
    local_client = check_docker_environment()

    env_vars = default_env(duckiebot_name, duckiebot_ip)

    if env is not None:
        env_vars.update(env)

    try:
        container = local_client.containers.get(container_name)
        dtslogger.info("an image already on localhost - stopping it first..")
        stop_container(container)
        remove_container(container)
    except Exception as e:
        dtslogger.warn("coulgn't remove existing container: %s" % e)

    dtslogger.info("Running %s on localhost with environment vars: %s" %
                   (image_name, env_vars))

    params = {
        'image': image_name,
        'remove': True,
        'network_mode': 'host',
        'privileged': True,
        'detach': True,
        'tty': True,
        'name': container_name,
        'environment': env_vars
    }

    if volumes is not None:
        params['volumes'] = volumes

    new_local_container = local_client.containers.run(**params)
    return new_local_container
Exemple #11
0
def start_rqt_image_view(duckiebot_name=None):
    dtslogger.info(
        """{}\nOpening a camera feed by running xhost+ and running rqt_image_view..."""
        .format('*' * 20))
    local_client = check_docker_environment()

    local_client.images.pull(RPI_GUI_TOOLS)
    env_vars = {'QT_X11_NO_MITSHM': 1}

    if duckiebot_name is not None:
        duckiebot_ip = get_duckiebot_ip(duckiebot_name)
        env_vars.update(default_env(duckiebot_name, duckiebot_ip))

    operating_system = platform.system()
    if operating_system == 'Linux':
        subprocess.call(["xhost", "+"])
        env_vars['DISPLAY'] = ':0'
    elif operating_system == 'Darwin':
        IP = subprocess.check_output([
            '/bin/sh', '-c',
            'ifconfig en0 | grep inet | awk \'$1=="inet" {print $2}\''
        ])
        env_vars['IP'] = IP
        subprocess.call(["xhost", "+IP"])

    dtslogger.info("Running %s on localhost with environment vars: %s" %
                   (RPI_GUI_TOOLS, env_vars))

    return local_client.containers.run(
        image=RPI_GUI_TOOLS,
        remove=True,
        privileged=True,
        detach=True,
        network_mode='host',
        environment=env_vars,
        command=
        'bash -c "source /home/software/docker/env.sh && rqt_image_view"')
Exemple #12
0
    def command(shell, args):

        prog = 'dts duckiebot calibrate_extrinsics DUCKIEBOT_NAME'
        usage = """
Calibrate: 

    %(prog)s
"""

        parser = argparse.ArgumentParser(prog=prog, usage=usage)
        parser.add_argument('hostname',
                            default=None,
                            help='Name of the Duckiebot to calibrate')
        parser.add_argument('--base_image',
                            dest='image',
                            default="duckietown/rpi-duckiebot-base:master19")
        parser.add_argument(
            '--no_verification',
            action='store_true',
            default=False,
            help="If you don't have a lane you can skip the verificaiton step")

        parsed_args = parser.parse_args(args)
        hostname = parsed_args.hostname
        duckiebot_ip = get_duckiebot_ip(hostname)
        duckiebot_client = get_remote_client(duckiebot_ip)

        calibration_container_name = "extrinsic_calibration"
        validation_container_name = "extrinsic_calibration_validation"
        remove_if_running(duckiebot_client, calibration_container_name)
        remove_if_running(duckiebot_client, validation_container_name)

        # need to temporarily pause the image streaming from the robot
        try:
            duckiebot_containers = duckiebot_client.containers.list()
            interface_container_found = False
            for c in duckiebot_containers:
                if 'duckiebot-interface' in c.name:
                    interface_container_found = True
                    interface_container = c
                    dtslogger.info("Temporarily stopping image streaming...")
                    interface_container.stop()
        except Exception as e:
            dtslogger.warn(
                "Not sure if the duckiebot-interface is running because we got and exception when trying: %s"
                % e)

        image = parsed_args.image

        timestamp = datetime.date.today().strftime('%Y%m%d%H%M%S')

        raw_input(
            "{}\nPlace the Duckiebot on the calibration patterns and press ENTER."
            .format('*' * 20))
        log_file = 'out-calibrate-extrinsics-%s-%s' % (hostname, timestamp)
        rosrun_params = '-o /data/{0} > /data/{0}.log'.format(log_file)
        ros_pkg = 'complete_image_pipeline calibrate_extrinsics'
        start_command = 'rosrun {0} {1}'.format(ros_pkg, rosrun_params)
        dtslogger.info('Running command: {}'.format(start_command))

        env = default_env(hostname, duckiebot_ip)

        duckiebot_client.containers.run(image=image,
                                        name=calibration_container_name,
                                        privileged=True,
                                        network_mode='host',
                                        volumes=bind_duckiebot_data_dir(),
                                        command="/bin/bash -c '%s'" %
                                        start_command,
                                        environment=env)

        if not parsed_args.no_verification:
            raw_input(
                "{}\nPlace the Duckiebot in a lane and press ENTER.".format(
                    '*' * 20))
            log_file = 'out-pipeline-%s-%s' % (hostname, timestamp)
            rosrun_params = '-o /data/{0} > /data/{0}.log'.format(log_file)
            ros_pkg = 'complete_image_pipeline single_image_pipeline'
            start_command = 'rosrun {0} {1}'.format(ros_pkg, rosrun_params)
            dtslogger.info('Running command: {}'.format(start_command))

            duckiebot_client.containers.run(image=image,
                                            name=validation_container_name,
                                            privileged=True,
                                            network_mode='host',
                                            volumes=bind_duckiebot_data_dir(),
                                            command="/bin/bash -c '%s'" %
                                            start_command,
                                            environment=env)

        # restart the camera streaming
        try:
            all_duckiebot_containers = duckiebot_client.containers.list(
                all=True)
            found = False
            for c in all_duckiebot_containers:
                if 'duckiebot-interface' in c.name:
                    found = True
                    dtslogger.info("Restarting image streaming...")
                    c.start()
        except Exception as e:
            dtslogger.warn(
                "Not sure if the duckiebot-interface is running because we got and exception when trying: %s"
                % e)
    def command(shell, args):
        prog = 'dts duckiebot demo'
        parser = argparse.ArgumentParser(prog=prog, usage=usage)

        parser.add_argument('--demo_name',
                            dest="demo_name",
                            default=None,
                            help="Name of the demo to run")

        parser.add_argument(
            '--duckiebot_name',
            dest="duckiebot_name",
            default=None,
            help="Name of the Duckiebot on which to run the demo")

        parser.add_argument(
            '--package_name',
            dest="package_name",
            default="duckietown",
            help=
            "You can specify the package that you want to use to look for launch files"
        )

        parser.add_argument(
            '--image',
            dest="image_to_run",
            default="duckietown/rpi-duckiebot-base:master19",
            help="Docker image to use, you probably don't need to change ",
        )

        parser.add_argument('--debug',
                            action='store_true',
                            default=False,
                            help="will enter you into the running container")

        parsed = parser.parse_args(args)

        check_docker_environment()
        demo_name = parsed.demo_name
        if demo_name is None:
            msg = 'You must specify a demo_name'
            raise InvalidUserInput(msg)

        duckiebot_name = parsed.duckiebot_name
        if duckiebot_name is None:
            msg = 'You must specify a duckiebot_name'
            raise InvalidUserInput(msg)

        package_name = parsed.package_name
        dtslogger.info("Using package %s" % package_name)

        duckiebot_ip = get_duckiebot_ip(duckiebot_name)
        duckiebot_client = docker.DockerClient('tcp://' + duckiebot_ip +
                                               ':2375')

        container_name = 'demo_%s' % demo_name
        remove_if_running(duckiebot_client, container_name)
        image_base = parsed.image_to_run
        env_vars = default_env(duckiebot_name, duckiebot_ip)
        env_vars.update({'VEHICLE_NAME': duckiebot_name})

        if demo_name == 'base':
            cmd = '/bin/bash'
        else:
            cmd = 'roslaunch %s %s.launch veh:=%s' % (package_name, demo_name,
                                                      duckiebot_name)

        dtslogger.info("Running command %s" % cmd)
        demo_container = duckiebot_client.containers.run(
            image=image_base,
            command=cmd,
            network_mode='host',
            volumes=bind_duckiebot_data_dir(),
            privileged=True,
            name=container_name,
            mem_limit='800m',
            memswap_limit='2800m',
            stdin_open=True,
            tty=True,
            detach=True,
            environment=env_vars)

        if demo_name == 'base' or parsed.debug:
            attach_cmd = 'docker -H %s.local attach %s' % (duckiebot_name,
                                                           container_name)
            start_command_in_subprocess(attach_cmd)
Exemple #14
0
    def command(shell, args):

        prog = 'dts duckiebot calibrate_intrinsics DUCKIEBOT_NAME'
        usage = """
Calibrate: 

    %(prog)s
"""

        parser = argparse.ArgumentParser(prog=prog, usage=usage)
        parser.add_argument('hostname', default=None, help='Name of the Duckiebot to calibrate')
        parser.add_argument('--base_image', dest='image',
                            default="duckietown/rpi-duckiebot-base:master19-no-arm")
        parser.add_argument('--debug', action='store_true', default=False,
                            help="will enter you into the running container")


        parsed_args = parser.parse_args(args)
        hostname = parsed_args.hostname
        duckiebot_ip = get_duckiebot_ip(hostname)
        duckiebot_client = get_remote_client(duckiebot_ip)

        # is the interface running?
        try:
            duckiebot_containers = duckiebot_client.containers.list()
            interface_container_found = False
            for c in duckiebot_containers:
                if 'duckiebot-interface' in c.name:
                    interface_container_found = True
            if not interface_container_found:
                dtslogger.error("The  duckiebot-interface is not running on the duckiebot")
                exit()
        except Exception as e:
            dtslogger.warn(
                "Not sure if the duckiebot-interface is running because we got and exception when trying: %s" % e)

        # is the raw imagery being published?
        try:
            duckiebot_containers = duckiebot_client.containers.list()
            raw_imagery_found = False
            for c in duckiebot_containers:
                if 'demo_camera' in c.name:
                    raw_imagery_found = True
            if not raw_imagery_found:
                dtslogger.error("The  demo_camera is not running on the duckiebot - please run `dts duckiebot demo --demo_name camera --duckiebot_name %s" % hostname)
                exit()

        except Exception as e:
            dtslogger.warn("%s" % e)


        image = parsed_args.image


        client = check_docker_environment()
        container_name = "intrinsic_calibration_%s" % hostname
        remove_if_running(client,container_name)
        env = {'HOSTNAME': hostname,
               'ROS_MASTER': hostname,
               'DUCKIEBOT_NAME': hostname,
               'ROS_MASTER_URI': 'http://%s:11311' % duckiebot_ip,
               'QT_X11_NO_MITSHM': 1}

        volumes = {}
        subprocess.call(["xhost", "+"])

        p = platform.system().lower()
        if 'darwin' in p:
            env['DISPLAY'] = 'host.docker.internal:0' 
            volumes = {
                '/tmp/.X11-unix': {'bind': '/tmp/.X11-unix', 'mode': 'rw'}
            }
        else:
            env['DISPLAY'] = os.environ['DISPLAY']

        dtslogger.info("Running %s on localhost with environment vars: %s" %
                       (container_name, env))

        dtslogger.info("When the window opens you will need to move the checkerboard around in front of the Duckiebot camera")
        cmd = "roslaunch pi_camera intrinsic_calibration.launch veh:=%s" % hostname

        params = {'image': image,
                  'name': container_name,
                  'network_mode': 'host',
                  'environment': env,
                  'privileged': True,
                  'stdin_open': True,
                  'tty': True,
                  'detach': True,
                  'command': cmd,
                  'volumes': volumes
                  }

        container = client.containers.run(**params)

        if parsed_args.debug:
            attach_cmd = 'docker attach %s' % (container_name)
            start_command_in_subprocess(attach_cmd)
    def command(shell, args):
        prog = 'dts duckiebot evaluate'
        parser = argparse.ArgumentParser(prog=prog, usage=usage)
        group = parser.add_argument_group('Basic')
        group.add_argument('--duckiebot_name', default=None,
                            help="Name of the Duckiebot on which to perform evaluation")
        group.add_argument('--duckiebot_username', default="duckie",
                           help="The duckiebot username")
        group.add_argument('--image', dest='image_name',
                           help="Image to evaluate, if none specified then we will build your current context",
                           default=None)
        group.add_argument('--glue_node_image', default="duckietown/challenge-aido_lf-duckiebot:aido2",
                           help="The node that glues your submission with ROS on the duckiebot. Probably don't change")
        group.add_argument('--duration', help="Number of seconds to run evaluation", default=15)
        group.add_argument('--remotely', action='store_true', default=True,
                           help="If true run the image over network without pushing to Duckiebot")
        group.add_argument('--no_cache', help="disable cache on docker build",
                           action="store_true", default=False)
        group.add_argument('--record_bag', action='store_true', default=False,
                           help="If true record a rosbag")
        group.add_argument("--debug", action='store_true', default=False,
                           help="If true you will get a shell instead of executing")
        group.add_argument('--max_vel', help="the max velocity for the duckiebot", default=0.7)
        group.add_argument('--challenge', help="Specific challenge to evaluate")
        parsed = parser.parse_args(args)

        tmpdir = '/tmp'
        USERNAME = getpass.getuser()
        dir_home_guest = os.path.expanduser('~')
        dir_fake_home = os.path.join(tmpdir, 'fake-%s-home' % USERNAME)
        if not os.path.exists(dir_fake_home):
            os.makedirs(dir_fake_home)
        get_calibration_files(dir_fake_home, parsed.duckiebot_username, parsed.duckiebot_name)

        client = check_docker_environment()
        agent_container_name = "agent"
        glue_container_name = "aido_glue"

        # remove the containers if they are already running
        remove_if_running(client, agent_container_name)
        remove_if_running(client, glue_container_name)

        # setup the fifos2 volume (requires pruning it if it's still hanging around from last time)
        try:
            client.volumes.prune()
            fifo2_volume=client.volumes.create(name='fifos2')
        except Exception as e:
            dtslogger.warn("error creating volume: %s" % e)


        duckiebot_ip = get_duckiebot_ip(parsed.duckiebot_name)

        duckiebot_client = get_remote_client(duckiebot_ip)
        try:
            duckiebot_containers = duckiebot_client.containers.list()
            interface_container_found=False
            for c in duckiebot_containers:
                if 'duckiebot-interface' in c.name:
                    interface_container_found=True
            if not interface_container_found:
                dtslogger.error("The  duckiebot-interface is not running on the duckiebot")
        except Exception as e:
            dtslogger.warn("Not sure if the duckiebot-interface is running because we got and exception when trying: %s" % e)
            

        # let's start building stuff for the "glue" node
        glue_volumes =  {fifo2_volume.name: {'bind': '/fifos', 'mode': 'rw'}}
        glue_env = {'HOSTNAME':parsed.duckiebot_name,
                    'DUCKIEBOT_NAME':parsed.duckiebot_name,
                    'ROS_MASTER_URI':'http://%s:11311' % duckiebot_ip}

        dtslogger.info("Running %s on localhost with environment vars: %s" %
                       (parsed.glue_node_image, glue_env))
        params = {'image': parsed.glue_node_image,
                  'name': glue_container_name,
                  'network_mode': 'host',
                  'privileged': True,
                  'environment': glue_env,
                  'detach': True,
                  'tty': True,
                  'volumes': glue_volumes}

        # run the glue container
        glue_container = client.containers.run(**params)

        if not parsed.debug:
            monitor_thread = threading.Thread(target=continuously_monitor, args=(client, glue_container.name))
            monitor_thread.start()

        if parsed.image_name is None:
            # if we didn't get an `image_name` we try need to build the local container
            path = '.'
            dockerfile = os.path.join(path, 'Dockerfile')
            if not os.path.exists(dockerfile):
                msg = 'No Dockerfile'
                raise Exception(msg)
            tag='myimage'
            if parsed.no_cache:
                cmd = ['docker', 'build', '--no-cache', '-t', tag, '-f', dockerfile]
            else:
                cmd = ['docker', 'build', '-t', tag, '-f', dockerfile]
            dtslogger.info("Running command: %s" % cmd)
            cmd.append(path)
            subprocess.check_call(cmd)
            image_name = tag
        else:
            image_name = parsed.image_name


        # start to build the agent stuff
        agent_env = {'AIDONODE_DATA_IN':'/fifos/agent-in',
                    'AIDONODE_DATA_OUT':'fifo:/fifos/agent-out'}

        agent_volumes = {fifo2_volume.name: {'bind': '/fifos', 'mode': 'rw'},
                         dir_fake_home: {'bind': '/data/config', 'mode': 'rw'}
                         }


        params = {'image': image_name,
                  'remove': True,
                  'name': agent_container_name,
                  'environment': agent_env,
                  'detach': True,
                  'tty': True,
                  'volumes': agent_volumes}

        if parsed.debug:
            params['command'] = '/bin/bash'
            params['stdin_open'] = True


        
        dtslogger.info("Running %s on localhost with environment vars: %s" % (image_name, agent_env))
        agent_container = client.containers.run(**params)

        if parsed.debug:
            attach_cmd = 'docker attach %s' % agent_container_name
            start_command_in_subprocess(attach_cmd)

        else:
            monitor_thread = threading.Thread(target=continuously_monitor,args=(client, agent_container_name))
            monitor_thread.start()

        duration = int(parsed.duration)
        # should we record a bag?
        if parsed.record_bag:
            bag_container = record_bag(parsed.hostname, duration)

        dtslogger.info("Running for %d s" % duration)
        time.sleep(duration)
        stop_container(glue_container)
        stop_container(agent_container)

        if parsed.record_bag:
            stop_container(bag_container)
    def command(shell, args):
        prog = 'dts start_gui_tools DUCKIEBOT_NAME'
        usage = """
Keyboard control: 

    %(prog)s
"""

        parser = argparse.ArgumentParser(prog=prog, usage=usage)
        parser.add_argument('hostname',
                            default=None,
                            help='Name of the Duckiebot to calibrate')
        parser.add_argument('--network',
                            default='host',
                            help='Name of the network which to connect')
        parser.add_argument('--sim',
                            action='store_true',
                            default=False,
                            help='are we running in simulator?')
        parser.add_argument(
            '--base_image',
            dest='image',
            default="duckietown/rpi-duckiebot-base:master19-no-arm",
            help="The base image, probably don't change the default")
        parsed_args = parser.parse_args(args)

        if parsed_args.sim:
            duckiebot_ip = "localhost"
        else:
            duckiebot_ip = get_duckiebot_ip(
                duckiebot_name=parsed_args.hostname)

        hostname = parsed_args.hostname
        image = parsed_args.image

        client = check_docker_environment()
        container_name = "interactive_gui_tools_%s" % hostname
        remove_if_running(client, container_name)

        if parsed_args.sim:
            env = {
                'HOSTNAME': 'default',
                'ROS_MASTER': hostname,
                'DUCKIEBOT_NAME': hostname,
                'ROS_MASTER_URI': 'http://%s:11311' % hostname
            }
        else:
            env = {
                'HOSTNAME': hostname,
                'ROS_MASTER': hostname,
                'DUCKIEBOT_NAME': hostname,
                'ROS_MASTER_URI': 'http://%s:11311' % duckiebot_ip
            }

        env['QT_X11_NO_MITSHM'] = 1

        p = platform.system().lower()
        volumes = {'/tmp/.X11-unix': {'bind': '/tmp/.X11-unix', 'mode': 'rw'}}

        if 'darwin' in p:
            subprocess.call(["xhost", "+", '127.0.0.1'])
            env['DISPLAY'] = 'host.docker.internal:0'
        else:
            subprocess.call(["xhost", "+"])
            env['DISPLAY'] = os.environ['DISPLAY']

        dtslogger.info("Running %s on localhost with environment vars: %s" %
                       (container_name, env))

        cmd = "/bin/bash"

        params = {
            'image': image,
            'name': container_name,
            'network_mode': parsed_args.network,
            'environment': env,
            'privileged': True,
            'stdin_open': True,
            'tty': True,
            'detach': True,
            'command': cmd,
            'volumes': volumes
        }

        container = client.containers.run(**params)
        attach_cmd = 'docker attach %s' % container_name
        start_command_in_subprocess(attach_cmd)