Commit 2687b320 authored by Matthew Hausknecht's avatar Matthew Hausknecht

Merge pull request #17 from sanmit/master

Added Communication Interface
parents b9ad3f3e 9fbbf409
...@@ -49,13 +49,15 @@ def main(args, team1='left', team2='right'): ...@@ -49,13 +49,15 @@ def main(args, team1='left', team2='right'):
'server::coach_w_referee=1 server::hfo_max_trial_time=%i ' \ 'server::coach_w_referee=1 server::hfo_max_trial_time=%i ' \
'server::hfo_max_trials=%i server::hfo_max_frames=%i ' \ 'server::hfo_max_trials=%i server::hfo_max_frames=%i ' \
'server::hfo_offense_on_ball=%i server::random_seed=%i ' \ 'server::hfo_offense_on_ball=%i server::random_seed=%i ' \
'server::hfo_max_untouched_time=%i' \ 'server::hfo_max_untouched_time=%i ' \
'server::say_msg_size=%i' \
%(server_port, coach_port, olcoach_port, %(server_port, coach_port, olcoach_port,
args.logging, args.logging, args.logging, args.logging, args.logging, args.logging,
args.logDir, args.logDir, args.logDir, args.logDir, args.logDir, args.logDir,
args.sync, args.fullstate, args.fullstate, args.sync, args.fullstate, args.fullstate,
args.maxFramesPerTrial, args.numTrials, args.numFrames, args.maxFramesPerTrial, args.numTrials, args.numFrames,
args.offenseOnBall, args.seed, args.maxUntouchedTime) args.offenseOnBall, args.seed, args.maxUntouchedTime,
args.messageSize)
# server::record_messages=on -- useful for debug # server::record_messages=on -- useful for debug
try: try:
# Launch the Server # Launch the Server
...@@ -138,6 +140,8 @@ def parseArgs(): ...@@ -138,6 +140,8 @@ def parseArgs():
help='Server provides full-state information to agents.') help='Server provides full-state information to agents.')
p.add_argument('--seed', dest='seed', type=int, default=-1, p.add_argument('--seed', dest='seed', type=int, default=-1,
help='Seed the server\'s RNG. Default: time.') help='Seed the server\'s RNG. Default: time.')
p.add_argument('--message-size', dest='messageSize', type=int, default=1000,
help='Message size limit for communication')
args = p.parse_args() args = p.parse_args()
if args.offenseAgents not in xrange(0, 11): if args.offenseAgents not in xrange(0, 11):
p.error('argument --offense-agents: invalid choice: '\ p.error('argument --offense-agents: invalid choice: '\
......
...@@ -119,6 +119,7 @@ class Trainer(object): ...@@ -119,6 +119,7 @@ class Trainer(object):
agent_cmd += ' -g' agent_cmd += ' -g'
if self._record: if self._record:
agent_cmd += ' --record' agent_cmd += ' --record'
# Comment next two lines to show output from agent.cpp and the server
kwargs = {'stdout':open('/dev/null', 'w'), kwargs = {'stdout':open('/dev/null', 'w'),
'stderr':open('/dev/null', 'w')} 'stderr':open('/dev/null', 'w')}
p = subprocess.Popen(agent_cmd.split(' '), shell = False, **kwargs) p = subprocess.Popen(agent_cmd.split(' '), shell = False, **kwargs)
......
...@@ -2,13 +2,16 @@ ...@@ -2,13 +2,16 @@
#include <vector> #include <vector>
#include <HFO.hpp> #include <HFO.hpp>
#include <cstdlib> #include <cstdlib>
#include <stdio.h>
#include <math.h>
#include <iostream>
using namespace std; using namespace std;
using namespace hfo; using namespace hfo;
// Before running this program, first Start HFO server: // Before running this program, first Start HFO server:
// $./bin/HFO --offense-agents 1 // $./bin/HFO --offense-agents 1
#define PI 3.14159265
int main(int argc, char** argv) { int main(int argc, char** argv) {
int port = 6000; int port = 6000;
if (argc > 1) { if (argc > 1) {
...@@ -21,19 +24,24 @@ int main(int argc, char** argv) { ...@@ -21,19 +24,24 @@ int main(int argc, char** argv) {
hfo.connectToAgentServer(port, HIGH_LEVEL_FEATURE_SET); hfo.connectToAgentServer(port, HIGH_LEVEL_FEATURE_SET);
// Play 5 episodes // Play 5 episodes
for (int episode=0; ; episode++) { for (int episode=0; ; episode++) {
int step = 0;
status_t status = IN_GAME; status_t status = IN_GAME;
while (status == IN_GAME) { while (status == IN_GAME) {
// Get the vector of state features for the current state // Get the vector of state features for the current state
const vector<float>& feature_vec = hfo.getState(); const vector<float>& feature_vec = hfo.getState();
// Get any incoming communication // Get any incoming communication
std::string msg = hfo.hear(); std::string msg = hfo.hear();
// TODO: [Sanmit] Do something with incoming communication // Do something with incoming communication
// Perform the action cout << "HEARD: " << msg.c_str() << endl;
hfo.act(DASH, 0, 0); float target_x = sin((step % 360) * PI/180);
// TODO: [Sanmit] Do something with outgoing communication float target_y = cos((step % 360) * PI/180);
hfo.act(DRIBBLE_TO, target_x, target_y);
// Do something with outgoing communication
hfo.say("Message"); hfo.say("Message");
// Advance the environment and get the game status // Advance the environment and get the game status
status = hfo.step(); status = hfo.step();
step+=2;
} }
} }
hfo.act(QUIT); hfo.act(QUIT);
......
#!/usr/bin/env python
# encoding: utf-8
import sys
# First Start the server: $> bin/start.py
if __name__ == '__main__':
port = 6000
if len(sys.argv) > 1:
port = int(sys.argv[1])
try:
from hfo import *
except:
print 'Failed to import hfo. To install hfo, in the HFO directory'\
' run: \"pip install .\"'
exit()
# Create the HFO Environment
hfo_env = hfo.HFOEnvironment()
# Connect to the agent server on port 6000 with the specified
# feature set. See feature sets in hfo.py/hfo.hpp.
hfo_env.connectToAgentServer(port, HFO_Features.HIGH_LEVEL_FEATURE_SET)
# Play 5 episodes
for episode in xrange(5):
status = HFO_Status.IN_GAME
while status == HFO_Status.IN_GAME:
# Grab the state features from the environment
features = hfo_env.getState()
# Get any incoming communication
msg = hfo_env.hear()
# Do something with incoming communication
print 'Heard: ', msg
# Take an action and get the current game status
hfo_env.act(HFO_Actions.DASH, 20.0, 0)
# Do something with outgoing communication
hfo_env.say('Message')
status = hfo_env.step()
print 'Episode', episode, 'ended with',
# Check what the outcome of the episode was
if status == HFO_Status.GOAL:
print 'goal'
elif status == HFO_Status.CAPTURED_BY_DEFENSE:
print 'captured by defense'
elif status == HFO_Status.OUT_OF_BOUNDS:
print 'out of bounds'
elif status == HFO_Status.OUT_OF_TIME:
print 'out of time'
else:
print 'Unknown status', status
exit()
# Cleanup when finished
hfo_env.cleanup()
#!/usr/bin/env python #!/usr/bin/env python
# encoding: utf-8 # encoding: utf-8
# First Start the server: $> bin/start.py import sys
# First Start the server: $> bin/start.py
if __name__ == '__main__': if __name__ == '__main__':
port = 6000
if len(sys.argv) > 1:
port = int(sys.argv[1])
try: try:
from hfo import * from hfo import *
except: except:
...@@ -14,7 +18,7 @@ if __name__ == '__main__': ...@@ -14,7 +18,7 @@ if __name__ == '__main__':
hfo = hfo.HFOEnvironment() hfo = hfo.HFOEnvironment()
# Connect to the agent server on port 6000 with the specified # Connect to the agent server on port 6000 with the specified
# feature set. See feature sets in hfo.py/hfo.hpp. # feature set. See feature sets in hfo.py/hfo.hpp.
hfo.connectToAgentServer(6000, HFO_Features.HIGH_LEVEL_FEATURE_SET) hfo.connectToAgentServer(port, HFO_Features.HIGH_LEVEL_FEATURE_SET)
# Play 5 episodes # Play 5 episodes
for episode in xrange(5): for episode in xrange(5):
status = HFO_Status.IN_GAME status = HFO_Status.IN_GAME
...@@ -22,7 +26,8 @@ if __name__ == '__main__': ...@@ -22,7 +26,8 @@ if __name__ == '__main__':
# Grab the state features from the environment # Grab the state features from the environment
features = hfo.getState() features = hfo.getState()
# Take an action and get the current game status # Take an action and get the current game status
status = hfo.act(HFO_Actions.DASH, 20.0, 0) hfo.act(HFO_Actions.DASH, 20.0, 0)
hfo.step()
print 'Episode', episode, 'ended with', print 'Episode', episode, 'ended with',
# Check what the outcome of the episode was # Check what the outcome of the episode was
if status == HFO_Status.GOAL: if status == HFO_Status.GOAL:
......
...@@ -9,7 +9,6 @@ using namespace hfo; ...@@ -9,7 +9,6 @@ using namespace hfo;
// This agent demonstrates the use of the MOVE_TO action to visit the // This agent demonstrates the use of the MOVE_TO action to visit the
// corners of the play field. Before running this program, first Start // corners of the play field. Before running this program, first Start
// HFO server: $./bin/HFO --offense-agents 1 // HFO server: $./bin/HFO --offense-agents 1
int main(int argc, char** argv) { int main(int argc, char** argv) {
int port = 6000; int port = 6000;
if (argc > 1) { if (argc > 1) {
......
...@@ -45,8 +45,8 @@ class HFOEnvironment(object): ...@@ -45,8 +45,8 @@ class HFOEnvironment(object):
self.numFeatures = None # Given by the server in handshake self.numFeatures = None # Given by the server in handshake
self.features = None # The state features self.features = None # The state features
self.requested_action = None # Action to execute and parameters self.requested_action = None # Action to execute and parameters
self.say_msg = None # Outgoing message to say self.say_msg = '' # Outgoing message to say
self.hear_msg = None # Incoming heard message self.hear_msg = '' # Incoming heard message
def NumParams(self, action_type): def NumParams(self, action_type):
''' Returns the number of required parameters for each action type. ''' ''' Returns the number of required parameters for each action type. '''
...@@ -94,6 +94,12 @@ class HFOEnvironment(object): ...@@ -94,6 +94,12 @@ class HFOEnvironment(object):
self.cleanup() self.cleanup()
exit(1) exit(1)
self.features = struct.unpack('f'*self.numFeatures, state_data) self.features = struct.unpack('f'*self.numFeatures, state_data)
# Get first hear message
hearMsgLengthData = self.socket.recv(struct.calcsize('I'))
hearMsgLength = struct.unpack('I', hearMsgLengthData)[0]
if hearMsgLength > 0:
hearMsgData = self.socket.recv(struct.calcsize('c')*hearMsgLength)
self.hear_msg = struct.unpack(str(hearMsgLength)+'s', hearMsgData)[0]
def handshakeAgentServer(self, feature_set): def handshakeAgentServer(self, feature_set):
'''Handshake with the agent's server. ''' '''Handshake with the agent's server. '''
...@@ -144,11 +150,16 @@ class HFOEnvironment(object): ...@@ -144,11 +150,16 @@ class HFOEnvironment(object):
# Send action and parameters # Send action and parameters
self.socket.send(struct.pack('i'+'f'*(len(self.requested_action)-1), self.socket.send(struct.pack('i'+'f'*(len(self.requested_action)-1),
*self.requested_action)) *self.requested_action))
# TODO: [Sanmit] Send self.say_msg # [Sanmit] Send self.say_msg
self.socket.send(struct.pack('I', len(self.say_msg)))
if len(self.say_msg) > 0:
self.socket.send(struct.pack(str(len(self.say_msg))+'s', self.say_msg))
self.say_msg = '' self.say_msg = ''
# Get the current game status # Get the current game status
data = self.socket.recv(struct.calcsize("i")) data = self.socket.recv(struct.calcsize("i"))
status = struct.unpack("i", data)[0] status = struct.unpack("i", data)[0]
# Get the next state features # Get the next state features
state_data = self.socket.recv(struct.calcsize('f')*self.numFeatures) state_data = self.socket.recv(struct.calcsize('f')*self.numFeatures)
if not state_data: if not state_data:
...@@ -157,7 +168,13 @@ class HFOEnvironment(object): ...@@ -157,7 +168,13 @@ class HFOEnvironment(object):
exit(1) exit(1)
self.features = struct.unpack('f'*self.numFeatures, state_data) self.features = struct.unpack('f'*self.numFeatures, state_data)
self.hear_msg = '' self.hear_msg = ''
# TODO: [Sanmit] Receive self.hear_msg # [Sanmit] Receive self.hear_msg
hearMsgLengthData = self.socket.recv(struct.calcsize('I'))
hearMsgLength = struct.unpack('I', hearMsgLengthData)[0]
if hearMsgLength > 0:
hearMsgData = self.socket.recv(struct.calcsize('c')*hearMsgLength)
self.hear_msg = struct.unpack(str(hearMsgLength)+'s', hearMsgData)[0]
return status return status
def cleanup(self): def cleanup(self):
......
...@@ -188,6 +188,25 @@ void HFOEnvironment::connectToAgentServer(int server_port, ...@@ -188,6 +188,25 @@ void HFOEnvironment::connectToAgentServer(int server_port,
close(sockfd); close(sockfd);
exit(1); exit(1);
} }
// Get first hear message
// Message length
uint32_t msgLength;
if (recv(sockfd, &msgLength, sizeof(uint32_t), 0) < 0){
perror("[Agent Client] ERROR recieving hear message length from socket");
close(sockfd);
exit(1);
}
// Message
if (msgLength > 0){
std::vector<char> hearMsgBuffer;
hearMsgBuffer.resize(msgLength);
if (recv(sockfd, &hearMsgBuffer[0], msgLength, 0) < 0){
perror("[Agent Client] ERROR recieving hear message from socket");
close(sockfd);
exit(1);
}
hear_msg.assign(&(hearMsgBuffer[0]), hearMsgBuffer.size());
}
} }
void HFOEnvironment::handshakeAgentServer(feature_set_t feature_set) { void HFOEnvironment::handshakeAgentServer(feature_set_t feature_set) {
...@@ -288,7 +307,24 @@ status_t HFOEnvironment::step() { ...@@ -288,7 +307,24 @@ status_t HFOEnvironment::step() {
exit(1); exit(1);
} }
} }
// TODO: [Sanmit] Send say_msg // [Sanmit] Send say_msg
// Send message length
uint32_t sendMsgLength = say_msg.size();
if (send(sockfd, &sendMsgLength, sizeof(uint32_t), 0) < 0){
perror("[Agent Client] ERROR sending from socket");
close(sockfd);
exit(1);
}
// Send message
if (sendMsgLength > 0){
if (send(sockfd, say_msg.c_str(), say_msg.size(), 0) < 0){
perror("[Agent Client] ERROR sending from socket");
close(sockfd);
exit(1);
}
}
// Clear say message buffer
say_msg.clear(); say_msg.clear();
// Get the game status // Get the game status
...@@ -298,13 +334,33 @@ status_t HFOEnvironment::step() { ...@@ -298,13 +334,33 @@ status_t HFOEnvironment::step() {
exit(1); exit(1);
} }
// Get the next game state // Get the next game state
if (recv(sockfd, &(feature_vec.front()), numFeatures*sizeof(float), 0) < 0) { if (recv(sockfd, &(feature_vec.front()), numFeatures * sizeof(float), 0) < 0) {
perror("[Agent Client] ERROR recieving state features from socket"); perror("[Agent Client] ERROR recieving state features from socket");
close(sockfd); close(sockfd);
exit(1); exit(1);
} }
// [Sanmit] Receive comm_msg
// Clear last message
hear_msg.clear(); hear_msg.clear();
// TODO: [Sanmit] Receive comm_msg // Message length
uint32_t msgLength;
if (recv(sockfd, &msgLength, sizeof(uint32_t), 0) < 0){
perror("[Agent Client] ERROR recieving hear message length from socket");
close(sockfd);
exit(1);
}
// Message
if (msgLength > 0){
std::vector<char> hearMsgBuffer;
hearMsgBuffer.resize(msgLength);
if (recv(sockfd, &hearMsgBuffer[0], msgLength, 0) < 0){
perror("[Agent Client] ERROR recieving hear message from socket");
close(sockfd);
exit(1);
}
hear_msg.assign(&(hearMsgBuffer[0]), hearMsgBuffer.size());
}
return game_status; return game_status;
} }
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#endif #endif
#include "agent.h" #include "agent.h"
#include "custom_message.h"
#include "strategy.h" #include "strategy.h"
#include "field_analyzer.h" #include "field_analyzer.h"
...@@ -100,6 +101,7 @@ ...@@ -100,6 +101,7 @@
#include <rcsc/param/cmd_line_parser.h> #include <rcsc/param/cmd_line_parser.h>
#include <iostream> #include <iostream>
#include <fstream>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <cstdlib> #include <cstdlib>
...@@ -120,6 +122,7 @@ Agent::Agent() ...@@ -120,6 +122,7 @@ Agent::Agent()
M_field_evaluator(createFieldEvaluator()), M_field_evaluator(createFieldEvaluator()),
M_action_generator(createActionGenerator()), M_action_generator(createActionGenerator()),
lastTrainerMessageTime(-1), lastTrainerMessageTime(-1),
lastTeammateMessageTime(-1),
server_port(6008), server_port(6008),
client_connected(false), client_connected(false),
num_teammates(-1), num_teammates(-1),
...@@ -422,9 +425,39 @@ void Agent::actionImpl() { ...@@ -422,9 +425,39 @@ void Agent::actionImpl() {
if (send(newsockfd, &(features.front()), if (send(newsockfd, &(features.front()),
features.size() * sizeof(float), 0) < 0) { features.size() * sizeof(float), 0) < 0) {
perror("[Agent Server] ERROR sending state features from socket"); perror("[Agent Server] ERROR sending state features from socket");
close(sockfd);
exit(1); exit(1);
} }
// TODO: [Sanmit] Send the communication heard by the agent
// [Sanmit] Send the communication heard by the agent
// Hear for teammate messages and send them via socket to the HFO interface.
std::string teammateMessage = "";
// Received a new message
if (audioSensor().teammateMessageTime().cycle() > lastTeammateMessageTime){
// Receive all teammate messages
std::list<HearMessage> teammateMessages = audioSensor().teammateMessages();
for (std::list<HearMessage>::iterator msgIterator = teammateMessages.begin(); msgIterator != teammateMessages.end(); msgIterator++){
if ((*msgIterator).unum_ != world().self().unum()){
teammateMessage = (*msgIterator).str_;
break; // For now we just take one. Remove this and concatenate messages if desired -- though technically, agents should only be able to hear one message.
}
}
}
// Send message size
uint32_t hearMsgLength = teammateMessage.size();
if (send(newsockfd, &hearMsgLength, sizeof(uint32_t), 0) < 0){
perror("[Agent Server] ERROR sending hear message length from socket");
close(sockfd);
exit(1);
}
// Send message
if (hearMsgLength > 0){
if (send(newsockfd, teammateMessage.c_str(), teammateMessage.size(), 0) < 0){
perror("[Agent Server] ERROR sending hear message from socket");
close(sockfd);
exit(1);
}
}
// Get the action type // Get the action type
action_t action; action_t action;
...@@ -443,8 +476,38 @@ void Agent::actionImpl() { ...@@ -443,8 +476,38 @@ void Agent::actionImpl() {
exit(1); exit(1);
} }
} }
// TODO: [Sanmit] Receive the outgoing communication // [Sanmit] Receive the outgoing communication
// TODO: [Sanmit] "Say" in the actual game // Receive message length
uint32_t sayMsgLength;
if (recv(newsockfd, &sayMsgLength, sizeof(uint32_t), 0) < 0){
perror("[Agent Server] ERROR recv size of say message from socket");
close(sockfd);
exit(1);
}
// Receive message
std::vector<char> sayMsgBuffer;
sayMsgBuffer.resize(sayMsgLength);
std::string msgString = "";
// Check message size
if (sayMsgLength > ServerParam::i().playerSayMsgSize()){
perror("[Agent Server] ERROR message size too large. Increase size by starting bin/HFO with larger --messageSize argument");
close(sockfd);
exit(1);
}
if (sayMsgLength > 0) {
if (recv(newsockfd, &sayMsgBuffer[0], sayMsgLength, 0) < 0){
perror("[Agent Server] ERROR recv say message from socket");
close(sockfd);
exit(1);
}
msgString.assign(&(sayMsgBuffer[0]),sayMsgBuffer.size());
// [Sanmit] "Say" in the actual game
addSayMessage(new CustomMessage(msgString));
}
if (action == SHOOT) { if (action == SHOOT) {
const ShootGenerator::Container & cont = const ShootGenerator::Container & cont =
...@@ -704,7 +767,8 @@ Agent::communicationImpl() ...@@ -704,7 +767,8 @@ Agent::communicationImpl()
{ {
if ( M_communication ) if ( M_communication )
{ {
M_communication->execute( this ); // [Sanmit]: Turning this off since it adds default communication messages which can conflict with our comm messages.
// M_communication->execute( this );
} }
} }
......
...@@ -79,6 +79,7 @@ protected: ...@@ -79,6 +79,7 @@ protected:
protected: protected:
FeatureExtractor* feature_extractor; FeatureExtractor* feature_extractor;
long lastTrainerMessageTime; // Last time the trainer sent a message long lastTrainerMessageTime; // Last time the trainer sent a message
long lastTeammateMessageTime; // Last time a teammate sent a message
int server_port; // Port to start the server on int server_port; // Port to start the server on
bool client_connected; // Has the client connected and handshake? bool client_connected; // Has the client connected and handshake?
int sockfd, newsockfd; // Server sockets int sockfd, newsockfd; // Server sockets
......
#ifndef CUSTOM_MESSAGE_H
#define CUSTOM_MESSAGE_H
#include <rcsc/player/say_message_builder.h>
class CustomMessage : public rcsc::SayMessage {
private:
std::string msg;
public:
CustomMessage(std::string m) : msg(m) {}
char header() const { return 'm'; } // Should be one (unique) character
int length() const {return msg.length(); }
bool toStr(std::string & to) const {to+=msg; return true;}
std::ostream & printDebug( std::ostream & os ) const { os << "[MYMSG]"; return os;} // TODO [SANMIT]
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment