HFO 8.04 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
                  'server::hfo_offense_on_ball=%i server::random_seed=%i ' \
52 53
                  'server::hfo_max_untouched_time=%i ' \
                  'server::say_msg_size=%i' \
54
                  %(server_port, coach_port, olcoach_port,
55 56
                    args.logging, args.logging, args.logging,
                    args.logDir, args.logDir, args.logDir,
57
                    args.sync, args.fullstate, args.fullstate,
58
                    args.maxFramesPerTrial, args.numTrials, args.numFrames,
59 60
                    args.offenseOnBall, args.seed, args.maxUntouchedTime, 
                    args.messageSize)
61
                  # server::record_messages=on -- useful for debug
Matthew Hausknecht's avatar
Matthew Hausknecht committed
62
  try:
63
    # Launch the Server
64
    server = launch(serverCommand + serverOptions, name='server', supressOutput=True)
Matthew Hausknecht's avatar
Matthew Hausknecht committed
65
    time.sleep(0.2)
66
    assert server.poll() is None,\
67
      '[start.py] Failed to launch Server with command: \"%s\"' \
Matthew Hausknecht's avatar
Matthew Hausknecht committed
68
      %(serverCommand + serverOptions)
69
    if not args.headless:
Matthew Hausknecht's avatar
Matthew Hausknecht committed
70 71 72
      monitorCommand = os.path.join(binary_dir, MONITOR_BIN)
      monitorOptions = ' --connect --port=%i'%(server_port)
      launch(monitorCommand + monitorOptions, name='monitor')
73
    # Launch the Trainer
Matthew Hausknecht's avatar
Matthew Hausknecht committed
74
    from Trainer import Trainer
75
    trainer = Trainer(args=args, server_port=server_port, coach_port=coach_port)
Matthew Hausknecht's avatar
Matthew Hausknecht committed
76
    trainer.initComm()
Matthew Hausknecht's avatar
Matthew Hausknecht committed
77 78 79 80 81
    # Add Team1
    trainer.addTeam(team1)
    # Add Team2
    trainer.addTeam(team2)
    # Run
Matthew Hausknecht's avatar
Matthew Hausknecht committed
82 83
    trainer.run(necProcesses)
  except KeyboardInterrupt:
84
    print '[start.py] Exiting for CTRL-C'
Matthew Hausknecht's avatar
Matthew Hausknecht committed
85
  finally:
86
    print '[start.py] Cleaning up server and other processes'
Matthew Hausknecht's avatar
Matthew Hausknecht committed
87
    for p in reversed(processes):
Matthew Hausknecht's avatar
Matthew Hausknecht committed
88
      try:
Matthew Hausknecht's avatar
Matthew Hausknecht committed
89 90 91
        p.terminate()
        time.sleep(0.1)
        p.kill()
Matthew Hausknecht's avatar
Matthew Hausknecht committed
92 93 94
      except:
        pass

95
def parseArgs():
96
  import argparse
97 98
  p = argparse.ArgumentParser(description='Start Half Field Offense.',
                              formatter_class=argparse.RawTextHelpFormatter)
99
  p.add_argument('--headless', dest='headless', action='store_true',
100
                 help='Run without a monitor.')
101
  p.add_argument('--trials', dest='numTrials', type=int, default=-1,
102 103
                 help='Number of trials to run.\n'\
                 'Negative values mean unlimited. Default: -1.')
104
  p.add_argument('--frames', dest='numFrames', type=int, default=-1,
105 106
                 help='Number of frames to run for.\n'\
                 'Negative values mean unlimited. Default: -1.')
107
  p.add_argument('--frames-per-trial', dest='maxFramesPerTrial', type=int,
108 109
                 default=1000, help='Max number of frames per trial.\n'\
                 'Negative values mean unlimited. Default: 1000.')
110
  p.add_argument('--untouched-time', dest='maxUntouchedTime', type=int,
111 112
                 default=100, help='Ends trial if ball is untouched for this long.\n'\
                'Negative values mean unlimited. Default: 100.')
113
  p.add_argument('--offense-agents', dest='offenseAgents', type=int, default=0,
114
                 help='Number of offensive agents. Default: 0.')
115
  p.add_argument('--defense-agents', dest='defenseAgents', type=int, default=0,
116
                 help='Number of defensive agents. Default: 0.')
117
  p.add_argument('--offense-npcs', dest='offenseNPCs', type=int, default=0,
118
                 help='Number of offensive uncontrolled players. Default: 0.')
119
  p.add_argument('--defense-npcs', dest='defenseNPCs', type=int, default=0,
120
                 help='Number of defensive uncontrolled players. Default: 0.')
121
  p.add_argument('--no-sync', dest='sync', action='store_false', default=True,
122
                 help='Run server in non-sync mode.')
123
  p.add_argument('--port', dest='port', type=int, default=6000,
124 125 126
                 help='Agent server\'s port. Default: 6000.\n'\
                 'rcssserver, coach, and ol_coach will be '\
                 'incrementally allocated the following ports.')
127 128
  p.add_argument('--no-logging', dest='logging', action='store_false',
                 default=True, help='Disable rcssserver logging.')
129
  p.add_argument('--log-dir', dest='logDir', default='log/',
130
                 help='Directory to store logs. Default: log/')
131 132
  p.add_argument('--record', dest='record', action='store_true',
                 help='Record logs of states and actions.')
133 134 135 136 137 138
  p.add_argument('--offense-on-ball', dest='offenseOnBall', type=int,
                 default=0, help='Ball given to the player represented by the value.\n'\
                 'If value greater than the number of offense players, '\
                 'ball given to a random offense player.\n'\
                 'If value non-positive, ball is not given to any player.\n'\
                 'Default: 0.')
139 140
  p.add_argument('--fullstate', dest='fullstate', action='store_true',
                 help='Server provides full-state information to agents.')
141
  p.add_argument('--seed', dest='seed', type=int, default=-1,
142
                 help='Seed the server\'s RNG. Default: time.')
143 144
  p.add_argument('--messageSize', dest='messageSize', type=int, default=1000,
                 help='Message size limit for communication')
145
  args = p.parse_args()
Matthew Hausknecht's avatar
Matthew Hausknecht committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
  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])')
166
  return args
167 168 169

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