Commit 5f67fe09 authored by Leigh Stoller's avatar Leigh Stoller

Checkpoint some robot changes.

* New robot event listener:

    * It is intended to be started and stopped from the experiment
      swapin path instead of as a global daemon. It takes the pid/eid
      of the experiment, and will deal with events only for those
      nodes that are allocated to the experiment. We have some long
      range plans of time sharing the robot lab, so I figured we might
      as get a little bit of a start on that.

    * Once it fires up, it subscribes to the usual assortment of
      events, just like the loclistener does.

    * It then binds a socket on which to listen for connections from
      the web server.

    * Then it loops, looking for events and for connections from the
      web server. Connections from the web server are for forwarding
      the event stream in real time to whatever applets are currently
      viewing the robot lab.

    * As each event comes in, it is parsed, entered into the DB (nodes
      and location_info table), and fired out (in a textual form) to
      all the applet listeners. The web interface just acts as pipe in
      this case for the data.

    * The event stream is also duplicated to a file in the experiment
      directory (the same stuff that is piped to the applet), named by
      the current resource record ID. I hope to use this stream to
      playback the motion in the applet (coupled with webcam images
      once I figure out how to sync them).

* tbswap: Start and stop the new listener.

* Robotrack: I changed the interface for how we actually communicate
  the event data. Much more reasonable then it was (a comma separated
  string of numbers!).

* new database fields in the experiments table to hold the process ID
  of the listener and the port it is listening on. The port is not
  used yet, as the robot lab is still not shared. Will need to revist
  this later. Currently uses a fixed port number.

* www/robotrack/robopipe.php3: Killed most of the old code and replace
  with simple socket connect to the listener.
parent c5b79546
......@@ -35,10 +35,16 @@ all: robomonitord all-subdirs
client: client-subdirs
client-install: client-install-subdirs
check: check-subdirs
install: install-subdirs install-scripts
@echo "Don't forget to do a post-install as root"
boss-install: install
control-install: control-install-subdirs
post-install:
@$(MAKE) -C emc post-install
include $(TESTBED_SRCDIR)/GNUmakerules
clean: clean-subdirs
......
......@@ -11,7 +11,7 @@ SUBDIR = robots/emc
include $(OBJDIR)/Makeconf
PROGS = emcd loclistener
PROGS = locpiper emcd
TESTS = test_emcd.sh
all: $(PROGS)
......@@ -37,11 +37,19 @@ emcd: $(OBJS) ../mtp/libmtp.a
install: all
-mkdir -p $(INSTALL_DIR)/opsdir/sbin
$(INSTALL_PROGRAM) emcd $(INSTALL_DIR)/opsdir/sbin/emcd
$(INSTALL_PROGRAM) loclistener $(INSTALL_SBINDIR)/loclistener
$(INSTALL_PROGRAM) locpiper $(INSTALL_SBINDIR)/locpiper
@echo "Don't forget to do a post-install as root"
post-install:
chmod 775 $(INSTALL_SBINDIR)
chown root $(INSTALL_SBINDIR)/locpiper
chmod u+s $(INSTALL_SBINDIR)/locpiper
control-install: all
-mkdir -p $(INSTALL_DIR)/sbin
$(INSTALL_PROGRAM) emcd $(INSTALL_DIR)/sbin/emcd
boss-install: install
clean:
rm -f *.o
This diff is collapsed.
......@@ -410,6 +410,9 @@ public class NodeSelect extends JApplet {
*/
g2.drawImage(floorimage, 0, 0, fw, fh, this);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
/*
* Then we draw a bunch of stuff on it, like the robots.
*/
......
......@@ -406,98 +406,115 @@ public class RoboTrack extends JApplet {
* should create an XML representation of it!
*/
public void parseRobot(String str) {
StringTokenizer tokens = new StringTokenizer(str, ",");
String tmp;
StringTokenizer tokens;
String nodeid;
Robot robbie;
int index;
int index, ch;
System.out.println(str);
tmp = tokens.nextToken().trim();
//
// nodeid X=1,Y=2, ...
//
ch = str.indexOf(' ');
nodeid = str.substring(0, ch);
str = str.substring(ch+1);
tokens = new StringTokenizer(str, ",");
if ((robbie = (Robot) robots.get(tmp)) == null) {
if ((robbie = (Robot) robots.get(nodeid)) == null) {
// For testing from the shell.
if (!shelled)
return;
robbie = new Robot();
index = robotcount++;
robbie.index = index;
robbie.pname = tmp;
robbie.radius = 18;
robbie.size = 27;
robbie.type = "garcia";
robbie.mobile = true;
robbie = new Robot();
index = robotcount++;
robbie.index = index;
robbie.pname = nodeid;
robbie.vname = nodeid;
robbie.radius = 18;
robbie.size = 27;
robbie.type = "garcia";
robbie.z = 1.0;
robbie.z_meters = "1.0";
robbie.or = 90.0;
robbie.or_string = "90.0";
robbie.battery_percentage = "0.0";
robbie.battery_voltage = "0.0";
robbie.mobile = true;
robbie.allocated = true;
robots.put(tmp, robbie);
robots.put(nodeid, robbie);
robotmap.insertElementAt(robbie, index);
}
robbie.vname = tokens.nextToken().trim();
robbie.x = Integer.parseInt(tokens.nextToken().trim());
robbie.y = Integer.parseInt(tokens.nextToken().trim());
robbie.x_meters = FORMATTER.format(robbie.x / pixels_per_meter);
robbie.y_meters = FORMATTER.format(robbie.y / pixels_per_meter);
str = tokens.nextToken().trim();
if (str.length() > 0) {
robbie.z = Double.parseDouble(str);
robbie.z_meters = FORMATTER.format(robbie.z);
}
else {
robbie.z = 0.0;
robbie.z_meters = "";
}
str = tokens.nextToken().trim();
if (str.length() > 0) {
robbie.or = Double.parseDouble(str);
robbie.or_string = FORMATTER.format(robbie.or);
}
else {
robbie.or = 500.0;
robbie.or_string = "";
}
while (tokens.hasMoreTokens()) {
String tmp = tokens.nextToken().trim();
int delim = tmp.indexOf('=');
str = tokens.nextToken().trim();
if (str.length() > 0) {
robbie.dx = Integer.parseInt(str);
robbie.dy = Integer.parseInt(tokens.nextToken().trim());
robbie.dor = Double.parseDouble(tokens.nextToken().trim());
robbie.dx_meters = FORMATTER.format(robbie.dx /
pixels_per_meter);
robbie.dy_meters = FORMATTER.format(robbie.dy /
pixels_per_meter);
robbie.dor_string = FORMATTER.format(robbie.dor);
robbie.gotdest = true;
}
else {
// Consume next two tokens and clear strings/values.
str = tokens.nextToken();
str = tokens.nextToken();
robbie.dx = 0;
robbie.dy = 0;
robbie.dor = 500.0;
robbie.dx_meters = "";
robbie.dy_meters = "";
robbie.dor_string = "";
robbie.gotdest = false;
}
if (delim < 0)
continue;
// Store these as strings for easy display.
str = tokens.nextToken().trim();
if (str.length() > 0)
robbie.battery_percentage =
FORMATTER.format(Float.parseFloat(str));
else
robbie.battery_percentage = "";
str = tokens.nextToken().trim();
if (str.length() > 0)
robbie.battery_voltage =
FORMATTER.format(Float.parseFloat(str));
else
robbie.battery_voltage = "";
String key = tmp.substring(0, delim);
String val = tmp.substring(delim+1);
if (key.equals("X")) {
robbie.x = Integer.parseInt(val);
robbie.x_meters = FORMATTER.format(robbie.x /
pixels_per_meter);
}
else if (key.equals("Y")) {
robbie.y = Integer.parseInt(val);
robbie.y_meters = FORMATTER.format(robbie.y /
pixels_per_meter);
}
else if (key.equals("OR")) {
robbie.or = Double.parseDouble(val);
robbie.or_string = FORMATTER.format(robbie.or);
}
else if (key.equals("DX")) {
if (val.equals("NULL")) {
robbie.dx = 0;
robbie.dx_meters = "";
robbie.gotdest = false;
}
else {
robbie.dx = Integer.parseInt(val);
robbie.dx_meters = FORMATTER.format(robbie.dx /
pixels_per_meter);
robbie.gotdest = true;
}
}
else if (key.equals("DY")) {
if (val.equals("NULL")) {
robbie.dy = 0;
robbie.dy_meters = "";
}
else {
robbie.dy = Integer.parseInt(val);
robbie.dy_meters = FORMATTER.format(robbie.dy /
pixels_per_meter);
}
}
else if (key.equals("DOR")) {
if (val.equals("NULL")) {
robbie.dor = 500.0;
robbie.dor_string = "";
}
else {
robbie.dor = Double.parseDouble(val);
robbie.dor_string = FORMATTER.format(robbie.dor);
}
}
else if (key.equals("BATV")) {
// Store these as strings for easy display.
robbie.battery_voltage =
FORMATTER.format(Float.parseFloat(val));
}
else if (key.equals("BAT%")) {
// Store these as strings for easy display.
robbie.battery_percentage =
FORMATTER.format(Float.parseFloat(val));
}
}
robbie.last_update = System.currentTimeMillis();
now.setTime(robbie.last_update);
robbie.update_string = TIME_FORMAT.format(now);
......@@ -949,7 +966,7 @@ public class RoboTrack extends JApplet {
long now = System.currentTimeMillis();
long diff = (now - start_time) / 1000;
System.out.println("" + diff);
//System.out.println("" + diff);
parseRobot(str);
repaint();
......@@ -1566,7 +1583,7 @@ public class RoboTrack extends JApplet {
System.out.println(str);
StringTokenizer tokens = new StringTokenizer(str, ",");
String nodeid;
String nodeid, tmp;
Robot robbie;
nodeid = tokens.nextToken().trim();
......@@ -1591,6 +1608,33 @@ public class RoboTrack extends JApplet {
robbie.radius = (int)
(Float.parseFloat(tokens.nextToken().trim()) *
pixels_per_meter);
robbie.x = Integer.parseInt(tokens.nextToken().trim());
robbie.y = Integer.parseInt(tokens.nextToken().trim());
robbie.x_meters = FORMATTER.format(robbie.x /
pixels_per_meter);
robbie.y_meters = FORMATTER.format(robbie.y /
pixels_per_meter);
tmp = tokens.nextToken().trim();
if (tmp.length() > 0) {
robbie.z = Double.parseDouble(tmp);
robbie.z_meters = FORMATTER.format(robbie.z);
}
else {
robbie.z = 0.0;
robbie.z_meters = "";
}
tmp = tokens.nextToken().trim();
if (tmp.length() > 0) {
robbie.or = Double.parseDouble(tmp);
robbie.or_string = FORMATTER.format(robbie.or);
}
else {
robbie.or = 500.0;
robbie.or_string = "";
}
}
is.close();
}
......
......@@ -405,6 +405,8 @@ CREATE TABLE experiments (
paniced tinyint(1) NOT NULL default '0',
panic_date datetime default NULL,
delay_capacity tinyint(3) unsigned default NULL,
locpiper_pid int(11) default '0',
locpiper_port int(11) default '0',
PRIMARY KEY (eid,pid),
KEY idx (idx),
KEY batchmode (batchmode)
......
......@@ -2644,3 +2644,11 @@ last_net_act,last_cpu_act,last_ext_act);
alter table experiments add elabinelab_cvstag varchar(64) \
default NULL after elabinelab_eid;
1.136: Add a process id and local port number fields for the location
piper.
alter table experiments add locpiper_pid int(11) default '0' \
after delay_capacity;
alter table experiments add locpiper_port int(11) default '0' \
after locpiper_pid;
......@@ -34,6 +34,7 @@ sub usage()
my $TBROOT = "@prefix@";
my $TESTMODE = @TESTMODE@;
my $DISABLE_EVENTS = "@DISABLE_EVENT_SCHED@";
my $piper = "$TBROOT/sbin/locpiper";
# Untaint the path
$ENV{'PATH'} = "/usr/bin:$TBROOT/libexec:$TBROOT/libexec/ns2ir" .
......@@ -387,6 +388,17 @@ sub doSwapout($) {
print STDERR "*** Failed to stop the event system.\n";
$swapout_errors = 1;
}
#
# Stop the location piper.
#
if (-x $piper) {
print "Stopping the location piper\n";
if (system("$piper -k $pid $eid")) {
print STDERR "*** Failed to stop location piper.\n";
$swapout_errors = 1;
}
}
}
}
......@@ -1079,6 +1091,18 @@ sub doSwapin($) {
# event system previously, so starting it again will fail!
#
if (! ($DISABLE_EVENTS || $elabinelab)) {
#
# For the robot testbed, start the location piper *before* the event
# system.
#
if (-x $piper && ($type != UPDATE && $type != UPDATE_RECOVER)) {
print "Starting the location piper.\n";
if (system("$piper $pid $eid")) {
print STDERR "*** Failed to start the location piper.\n";
return 1;
}
}
if ( $update_Eventsys_restart ||
($type != UPDATE && $type != UPDATE_RECOVER) ) {
print "Starting the event system.\n";
......
......@@ -87,11 +87,8 @@ while ($row = mysql_fetch_array($query_result)) {
if (!isset($selector)) {
echo "$vname, ";
}
echo "$type, $alloc, $mobile, $size, $radius";
if (isset($selector)) {
echo ", $loc_x, $loc_y, $loc_z, $or";
}
echo "$type, $alloc, $mobile, $size, $radius, ";
echo "$loc_x, $loc_y, $loc_z, $or";
echo "\n";
}
......
......@@ -38,34 +38,22 @@ header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
flush();
#
# Clean up when the remote user disconnects
#
function SPEWCLEANUP()
{
exit(0);
}
register_shutdown_function("SPEWCLEANUP");
if (isset($fake)) {
#
# Just loop forever writing out some stuff.
#
$x1 = 100;
$y1 = 100;
$z1 = 0.5;
$x2 = 700;
$y2 = 200;
$z2 = 1.5;
$i = 0;
do {
echo "garcia1, robbie, $x1, $y1, $z1, 90.0, 700, 300, -90.0, 10, 20\n";
echo "garcia2, mary, $x2, $y2, $z2, 0.0, , , , 50, 60\n";
echo "garcia3, robin, 300, 300, 0.2, 0.0, , , , 90, 95\n";
echo "garcia1 X=$x1,Y=$y1,OR=-90.0,DX=700,DY=300,DOR=-90.0\n";
echo "garcia2 X=$x2,Y=$y2,OR=-5.66424,BATV=50.34567,BAT%=100.0\n";
echo "garcia3 X=300,Y=300,OR=0.0,BATV=90,BAT%=95\n";
flush();
sleep(1);
$x1 +=2;
......@@ -76,77 +64,34 @@ if (isset($fake)) {
return;
}
$last_stamp = 0;
$loop_count = 0;
# Loop forever.
while (1) {
if ($loop_count == 30) {
# The point is to update everything every 30 seconds.
$stamp_clause = "";
$loop_count = 0;
}
elseif ($last_stamp)
$stamp_clause = " and stamp>$last_stamp ";
else
$stamp_clause = "";
$query_string =
"select loc.*,r.pid,r.eid,r.vname, ".
" n.battery_voltage,n.battery_percentage, ".
" n.destination_x,n.destination_y, ".
" n.destination_orientation ".
" from location_info as loc ".
"left join reserved as r on r.node_id=loc.node_id ".
"left join nodes as n on n.node_id=loc.node_id ".
"where loc.building='$building' and ".
" loc.floor='$floor' $stamp_clause ".
"order by n.type,n.node_id";
#
# Clean up when the remote user disconnects
#
$socket = 0;
$query_result = DBQueryFatal($query_string);
function SPEWCLEANUP()
{
global $socket;
while ($row = mysql_fetch_array($query_result)) {
$pname = $row["node_id"];
$vname = $row["vname"];
$x = $row["loc_x"];
$y = $row["loc_y"];
$z = $row["loc_z"];
$or = $row["orientation"];
$dx = $row["destination_x"];
$dy = $row["destination_y"];
$dor = $row["destination_orientation"];
$bvolts= $row["battery_voltage"];
$bper = $row["battery_percentage"];
$stamp = $row["stamp"];
if (!$socket || !connection_aborted()) {
exit();
}
fclose($socket);
exit();
}
# ignore_user_abort(1);
register_shutdown_function("SPEWCLEANUP");
if ($stamp > $last_stamp)
$last_stamp = $stamp;
$socket = fsockopen("localhost", 9005);
if (!$socket) {
TBERROR("Error opening locpiper socket - $errstr",1);
}
if (!isset($vname))
$vname = $pname;
if (!isset($z))
$z = "";
if (!isset($or))
$or = "";
if (!isset($dx)) {
$dx = "";
$dy = "";
$dor = "";
}
else {
$dx = (int) $dx;
$dy = (int) $dy;
}
if (!isset($bvolts))
$bvolts = "";
if (!isset($bper))
$bper = "";
echo "$pname, $vname, $x, $y, $z, $or, $dx, $dy, $dor, $bper, $bvolts\n";
}
$loop_count++;
while (! feof($socket)) {
$buffer = fgets($socket, 1024);
echo $buffer;
flush();
sleep(1);
}
fclose($socket);
?>
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