HFO 7.22 KB
Newer Older
Matthew Hausknecht's avatar
Matthew Hausknecht committed
1 2 3
#!/usr/bin/env python
# encoding: utf-8

4
import subprocess, os, time, numpy, sys
Matthew Hausknecht's avatar
Matthew Hausknecht committed
5

6 7 8
# Global list of all/essential running processes
processes, necProcesses = [], []
# Command to run the rcssserver. Edit as needed.
Matthew Hausknecht's avatar
Matthew Hausknecht committed
9
SERVER_BIN = 'rcssserver'
10
# Command to run the monitor. Edit as needed.
Matthew Hausknecht's avatar
Matthew Hausknecht committed
11
MONITOR_BIN = 'soccerwindow2'
Matthew Hausknecht's avatar
Matthew Hausknecht committed
12

Matthew Hausknecht's avatar
Matthew Hausknecht committed
13
def launch(cmd, name = 'Unknown', necessary = True, supressOutput = True):
14
  """Launch a process.
Matthew Hausknecht's avatar
Matthew Hausknecht committed
15

16 17
  Appends to list of processes and (optionally) necProcesses if
  necessary flag is True.
Matthew Hausknecht's avatar
Matthew Hausknecht committed
18

19 20
  Returns: The launched process.
  """
Matthew Hausknecht's avatar
Matthew Hausknecht committed
21 22
  kwargs = {}
  if supressOutput:
Matthew Hausknecht's avatar
Matthew Hausknecht committed
23 24 25
    kwargs = {'stdout': open('/dev/null', 'w'),
              'stderr': open('/dev/null', 'w')}
  p = subprocess.Popen(cmd.split(' '), shell = False, **kwargs)
Matthew Hausknecht's avatar
Matthew Hausknecht committed
26 27 28 29 30
  processes.append(p)
  if necessary:
    necProcesses.append([p,name])
  return p

31
def main(args, team1='left', team2='right'):
Matthew Hausknecht's avatar
Matthew Hausknecht committed
32
  """Sets up the teams, launches the server and monitor, starts the trainer.
33
  """
34
  if args.logging and not os.path.exists(args.logDir):
35
    os.makedirs(args.logDir)
36
  num_agents   = args.offenseAgents + args.defenseAgents
37
  binary_dir   = os.path.dirname(os.path.realpath(__file__))
38 39 40
  server_port  = args.port + num_agents
  coach_port   = args.port + num_agents + 1
  olcoach_port = args.port + num_agents + 2
Matthew Hausknecht's avatar
Matthew Hausknecht committed
41
  serverCommand = os.path.join(binary_dir, SERVER_BIN)
42 43
  serverOptions = ' server::port=%i server::coach_port=%i ' \
                  'server::olcoach_port=%i server::coach=1 ' \
44
                  'server::game_logging=%i server::text_logging=%i ' \
45
                  'server::hfo_logging=%i server::hfo_log_dir=%s ' \
46
                  'server::game_log_dir=%s server::text_log_dir=%s '\
47 48
                  'server::synch_mode=%i server::hfo=1 ' \
                  'server::fullstate_l=%i server::fullstate_r=%i ' \
49
                  'server::coach_w_referee=1 server::hfo_max_trial_time=%i ' \
50
                  'server::hfo_max_trials=%i server::hfo_max_frames=%i ' \
51 52
                  'server::hfo_offense_on_ball=%i server::random_seed=%i ' \
                  'server::hfo_max_untouched_time=%i' \
53
                  %(server_port, coach_port, olcoach_port,
54 55
                    args.logging, args.logging, args.logging,
                    args.logDir, args.logDir, args.logDir,
56
                    args.sync, args.fullstate, args.fullstate,
57
                    args.maxFramesPerTrial, args.numTrials, args.numFrames,
58
                    args.offenseOnBall, args.seed, args.maxUntouchedTime)
59
                  # server::record_messages=on -- useful for debug
Matthew Hausknecht's avatar
Matthew Hausknecht committed
60
  try:
61
    # Launch the Server
62
    server = launch(serverCommand + serverOptions, name='server', supressOutput=True)
Matthew Hausknecht's avatar
Matthew Hausknecht committed
63
    time.sleep(0.2)
64
    assert server.poll() is None,\
65
      '[start.py] Failed to launch Server with command: \"%s\"' \
Matthew Hausknecht's avatar
Matthew Hausknecht committed
66
      %(serverCommand + serverOptions)
67
    if not args.headless:
Matthew Hausknecht's avatar
Matthew Hausknecht committed
68 69 70
      monitorCommand = os.path.join(binary_dir, MONITOR_BIN)
      monitorOptions = ' --connect --port=%i'%(server_port)
      launch(monitorCommand + monitorOptions, name='monitor')
71
    # Launch the Trainer
Matthew Hausknecht's avatar
Matthew Hausknecht committed
72
    from Trainer import Trainer
73
    trainer = Trainer(args=args, server_port=server_port, coach_port=coach_port)
Matthew Hausknecht's avatar
Matthew Hausknecht committed
74
    trainer.initComm()
Matthew Hausknecht's avatar
Matthew Hausknecht committed
75 76 77 78 79
    # Add Team1
    trainer.addTeam(team1)
    # Add Team2
    trainer.addTeam(team2)
    # Run
Matthew Hausknecht's avatar
Matthew Hausknecht committed
80 81
    trainer.run(necProcesses)
  except KeyboardInterrupt:
82
    print '[start.py] Exiting for CTRL-C'
Matthew Hausknecht's avatar
Matthew Hausknecht committed
83
  finally:
84
    print '[start.py] Cleaning up server and other processes'
Matthew Hausknecht's avatar
Matthew Hausknecht committed
85
    for p in reversed(processes):
Matthew Hausknecht's avatar
Matthew Hausknecht committed
86
      try:
Matthew Hausknecht's avatar
Matthew Hausknecht committed
87 88 89
        p.terminate()
        time.sleep(0.1)
        p.kill()
Matthew Hausknecht's avatar
Matthew Hausknecht committed
90 91 92
      except:
        pass

93
def parseArgs():
94 95 96 97 98 99 100 101
  import argparse
  p = argparse.ArgumentParser(description='Start Half Field Offense.')
  p.add_argument('--headless', dest='headless', action='store_true',
                 help='Run without a monitor')
  p.add_argument('--trials', dest='numTrials', type=int, default=-1,
                 help='Number of trials to run')
  p.add_argument('--frames', dest='numFrames', type=int, default=-1,
                 help='Number of frames to run for')
102 103 104
  p.add_argument('--frames-per-trial', dest='maxFramesPerTrial', type=int,
                 default=1000, help='Max number of frames per trial. '\
                 'Negative values mean unlimited.')
105 106 107
  p.add_argument('--untouched-time', dest='maxUntouchedTime', type=int,
                 default=100, help='Ends trial if ball is untouched for this long. '\
                 'Negative values mean unlimited.')
108
  p.add_argument('--offense-agents', dest='offenseAgents', type=int, default=0,
109 110 111 112 113 114 115
                 help='Number of offensive agents')
  p.add_argument('--defense-agents', dest='defenseAgents', type=int, default=0,
                 help='Number of defensive agents')
  p.add_argument('--offense-npcs', dest='offenseNPCs', type=int, default=0,
                 help='Number of offensive uncontrolled players')
  p.add_argument('--defense-npcs', dest='defenseNPCs', type=int, default=0,
                 help='Number of defensive uncontrolled players')
116 117
  p.add_argument('--no-sync', dest='sync', action='store_false', default=True,
                 help='Run server in non-sync mode')
118 119 120
  p.add_argument('--port', dest='port', type=int, default=6000,
                 help='Agent server\'s port. rcssserver, coach, and ol_coach'\
                 ' will be incrementally allocated the following ports.')
121 122
  p.add_argument('--no-logging', dest='logging', action='store_false',
                 default=True, help='Disable rcssserver logging.')
123 124
  p.add_argument('--log-dir', dest='logDir', default='log/',
                 help='Directory to store logs.')
125 126
  p.add_argument('--record', dest='record', action='store_true',
                 help='Record logs of states and actions.')
127 128
  p.add_argument('--offense-on-ball', dest='offenseOnBall', action='store_true',
                 help='Offense starts with the ball.')
129 130
  p.add_argument('--fullstate', dest='fullstate', action='store_true',
                 help='Server provides full-state information to agents.')
131
  p.add_argument('--seed', dest='seed', type=int, default=-1,
132
                 help='Seed the server\'s RNG. Default: time.')
133
  args = p.parse_args()
Matthew Hausknecht's avatar
Matthew Hausknecht committed
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
  if args.offenseAgents not in xrange(0, 11):
    p.error('argument --offense-agents: invalid choice: '\
            + str(args.offenseAgents) + ' (choose from [0-10])')
  if args.offenseNPCs not in xrange(0, 11):
    p.error('argument --offense-npcs: invalid choice: '\
            + str(args.offenseNPCs) + ' (choose from [0-10])')
  if args.defenseAgents not in xrange(0, 12):
    p.error('argument --defense-agents: invalid choice: '\
            + str(args.defenseAgents) + ' (choose from [0-11])')
  if args.defenseNPCs not in xrange(0, 12):
    p.error('argument --offense-npcs: invalid choice: '\
            + str(args.defenseNPCs) + ' (choose from [0-11])')
  if args.offenseAgents + args.offenseNPCs not in xrange(1, 11):
    p.error('Offense players (offense-agents + offense-npcs): '\
            'invalid choice: ' + str(args.offenseAgents + args.offenseNPCs) +\
            ' (choose from [1,10])')
  if args.defenseAgents + args.defenseNPCs not in xrange(0, 12):
    p.error('Defense players (defense-agents + defense-npcs): '\
            'invalid choice: ' + str(args.defenseAgents + args.defenseNPCs) +\
            ' (choose from [0,11])')
154
  return args
155 156 157

if __name__ == '__main__':
  main(parseArgs())