Hi all,

I'm developing a web client to control some robots, the non-web version 
works fine.
I use JSON-RPC to communicate with python service (running on Apache with 
mod_python - built for windows & python 2.7, if any one needs it, email me).
My solution is to render each frame to a JPEG file and save it to a folder 
on server, return the file path to client, and then the client loads it.
DOM seems to not reload an image from the same URL, so for each frame I 
choose a filename from a set of names.
It works, but after several frames, the client displays a random old image 
which doesn't exist on server anymore - I'm sure of it, when I stop the 
robot, every image on server is the same, whereas the client stutters with 
an old image once every several frames. I also tried using loadImages, no 
changes

I attach the source code of the client. If you need the server side 
components, I can upload them too.
Any helps will be deeply appreciated.

TIA,
hxp
import pyjd # dummy in pyjs
from pyjamas import DOM
from pyjamas.ui.RootPanel import RootPanel
from pyjamas.ui.Label import Label
from pyjamas.ui.VerticalPanel import VerticalPanel
from pyjamas.ui.Label import Label
from pyjamas.ui.FocusPanel import FocusPanel
from pyjamas.ui.SimplePanel import SimplePanel
from pyjamas.ui import Event
from pyjamas.ui import KeyboardListener
from pyjamas.ui import MouseListener
from pyjamas.ui.KeyboardListener import KeyboardHandler
from pyjamas.ui.MouseListener import MouseHandler
from pyjamas.ui.Image import Image
from pyjamas.Timer import Timer
from pyjamas import Window
from pyjamas.Canvas.GWTCanvas import GWTCanvas
from pyjamas.Canvas.ImageLoader import loadImages
from pyjamas.Canvas import Color
from pyjamas.JSONService import JSONProxy
from pyjamas import log
import pygwt


# this class handles RPC communication
class RoverService(JSONProxy):
    def __init__(self):
        JSONProxy.__init__(self, "services/RoverService.py", ["getgeneralinfo", "getframe", "getimagemain", "getimagethumb", "sendaction", "sendcommand"])

# client canvas, do the drawings
class GameCanvas(GWTCanvas, MouseHandler):
    def __init__(self, width, height, game):
        GWTCanvas.__init__(self, width, height)
        MouseHandler.__init__(self)
        self.old_w = 0
        self.old_h = 0
        self.width = width
        self.height = height
        self.game = game
        self.addMouseListener(self)
        self.frame = Image()
        self.frame.setUrl("rover_big.jpg")
        self.draw()

    def set_size(self, w, h):
        self.width = w
        self.height = h

    def load_frame(self, url):
        if self.frame.getUrl() == url or url == "FAIL":
            return
        self.frame.setUrl(url)
        self.draw()

    def draw(self):
        if self.old_h != self.height or self.old_w != self.width:
            self.resize(self.width, self.height)
            self.old_h = self.height
            self.old_w = self.width
        self.drawImage(self.frame, 0, 0)


    def onMouseDown(self, sender, x, y):
        for rover in self.game.rovers:
            if rover["x1"] <= x <= rover["x2"] and rover["y1"] <= (y-480) <= rover["y2"]:
                # hit
                self.game.select(rover["index"])
                break

# client window layout
class GameLayout(VerticalPanel, KeyboardHandler):
    def __init__(self, game):
        VerticalPanel.__init__(self)
        KeyboardHandler.__init__(self)
        self.game = game
        self.addKeyboardListener(self)

    def onKeyPress(self, sender, keyCode, modifiers = None):
        return

    def onKeyDown(self, sender, keyCode, modifiers = None):
        self.game.keypress(keyCode, True)

    def onKeyUp(self, sender, keyCode, modifiers = None):
        self.game.keypress(keyCode, False)


# logic
FPS = 25

class Game:
    def __init__(self):
        self.rovers = []
        self.main = -1
        self.remote_service = RoverService()
        self.run = False
        self.main = -1
        self.online = 0
        self.all = False
        self.infra = False
        self.direction = 0
        self.old_n = 0
        # key flags
        self.key_up = False
        self.key_down = False
        self.key_left = False
        self.key_right = False
        self.key_a = False
        self.key_space = False
        self.key_i = False
        # status
        self.status = False

    def load(self):
        self.game_panel = GameLayout(self)
        self.label = Label("Status: Calling servers ...")
        self.label2 = Label("Select All: No")
        self.game_canvas = GameCanvas(640, 600, self)
        self.game_panel.add(self.label)
        self.game_panel.add(self.label2)
        focus_panel = FocusPanel(Widget=self.game_canvas)
        self.game_panel.add(focus_panel)
        RootPanel().add(self.game_panel)
        focus_panel.setFocus(True)
        self.get_info("GENERAL")

    # service call handlers
    def onRemoteResponse(self, response, request_info):
        self.remote_response(request_info.method, response)

    def onRemoteError(self, code, errobj, request_info):
        message = errobj['message']
        if code != 0:
            text = "HTTP error %d: %s from %s" % (code, message, request_info.method)
        else:
            code = errobj['code']
            text = "JSONRPC Error %s: %s from %s" % (code, message, request_info.method)
        self.remote_error(request_info.method, text)

    # start
    def start(self):
        self.run = True
        self.onTimer()

    # calling services
    def get_info(self, msg):
        self.remote_service.getgeneralinfo(msg, self)

    def get_image(self, msg):
        if msg == "MAIN":
            self.remote_service.getimagemain(msg, self)
        elif msg == "THUMB":
            self.remote_service.getimagethumb(msg, self)
        elif msg == "FRAME":
            self.remote_service.getframe(msg, self)

    def send_action(self, msg):
        self.remote_service.sendaction(msg, self)

    def select(self, index):
        if not self.run:
            return
        if index == self.main:
            return
        self.main = index
        if self.rovers[index]["stat"] != "online":
            return
        msg = "SET_MAIN"
        l = 15 - len(msg)
        for i in range(l):
            msg = msg + " "
        msg = msg + str(index)
        l = 50 - len(msg)
        for i in range(l):
            msg = msg + " "
        self.remote_service.sendcommand(msg, self)

    # handle responses from server
    def remote_response(self, method_name, response):
        if method_name == "getgeneralinfo":
            self.process_info_general(response)
        elif method_name == "getframe":
            self.process_frame(response)
        elif method_name == "sendaction":
            pass
        elif method_name == "sendcommand":
            pass

    def remote_error(self, method_name, message):
        if not self.run:
            Window.alert("Couldn't call services. Client will not start!!!")
        else:
            if method_name == "sendaction":
                pass
            elif method_name == "sendcommand":
                pass
            else:
                Window.alert("Services call failed. Client stopped!!!")
                self.run = False


    # process the returned data
    def update_info(self, data):
        chunks = data.split(" ")
        count = chunks[0].split("=")
        n = int(count[1])
        if n <= 0:
            return False
        tmp = chunks[1].split("=")
        main_ip = tmp[1]
        self.online = 0
        self.rovers = []
        for i in range(n):
            tmp = chunks[i+2].split("=")
            rover = {}
            rover["index"] = i
            rover["ip"] = tmp[1]
            rover["stat"] = tmp[0]
            if tmp[0] == "online":
                self.online += 1
            if tmp[1] == main_ip:
                self.main = i
            # set coordinates
            rows = int(i / 4)
            cols = i % 4
            x1 = cols * 160
            x2 = x1 + 159
            y1 = rows * 120
            y2 = y1 + 119
            rover["x1"] = x1
            rover["x2"] = x2
            rover["y1"] = y1
            rover["y2"] = y2
            self.rovers.append(rover)
        if self.online == 0:
            return False
        else:
            text = "[Status]: [Online: " + str(self.online) + "] ; Main Rover [" + str(self.main)+ "] IP: " + self.rovers[self.main]["ip"]
            self.label.setText(text)
        if self.old_n != n:
            cols = n % 4
            if cols == 0:
                rows = int(n / 4)
            else:
                rows = int(n / 4) + 1
            self.game_canvas.set_size(640, rows * 120 + 480)
            self.old_n = n
        return True


    def process_info_general(self, msg):
        if not self.run:
            # game not started. do smth here
            if msg == "FAIL":
                Window.alert("Couldn't retrieve rovers' information. Client will not start!!!")
            else:
                # update information
                if self.update_info(msg):
                    self.start()
                    self.get_image("FRAME")
                else:
                    Window.alert("Error. Client will not start.")
        else:
            # update rovers information
            if msg != "FAIL":
                self.update_info(msg)
            self.get_image("FRAME")

    def process_frame(self, msg):
        if msg != "FAIL":
            self.game_canvas.load_frame(msg)
        self.status = False

    # timer, to update screen & info
    def onTimer(self, t=None):
        Timer(int(1000/FPS), self)
        if not self.run:
            return
        self.event_loop()
        if not self.status:
            self.update_display()


    def switch_rover(self):
        index = self.main + 1
        while index != self.main:
            if index >= len(self.rovers):
                index = 0
            if index == self.main:
                break
            elif self.rovers[index]["stat"] == "online":
                break
            else:
                index += 1
        return index

    def event_loop(self):
        # all or not
        if self.key_a:
            self.all = not self.all
        if self.all:
            self.label2.setText("[Select All] : Yes")
            header = "ALL"
        else:
            self.label2.setText("[Select All] : No")
            s = str(self.main)
            if len(s) == 1:
                header = "00" + s
            elif len(s) == 2:
                header = "0" + s
            else:
                header = s
        # infra red
        if self.key_i:
            self.infra = not self.infra
            if self.infra:
                msg = header + "INFRA_ON"
            else:
                msg = header + "INFRA_OFF"
            self.send_action(msg)
        # switch rover
        if self.key_space:
            index = self.switch_rover()
            if index != self.main:
                self.select(index)
                self.main = index
        # movements
        if self.key_up or self.key_down:
            if self.key_up:
                if self.direction >= 0:
                    if self.key_left:
                        msg = header + "FWD_LEFT"
                    elif self.key_right:
                        msg = header + "FWD_RIGHT"
                    else:
                        msg = header + "FORWARD"
                    self.direction = 1
                else:
                    msg = header + "STOP_BACK"
                    self.direction = 0
            if self.key_down:
                if self.direction <= 0:
                    if self.key_left:
                        msg = header + "BWD_LEFT"
                    elif self.key_right:
                        msg = header + "BWD_RIGHT"
                    else:
                        msg = header + "BACKWARD"
                    self.direction = -1
                else:
                    msg = header + "STOP_FRONT"
                    self.direction = 0
            self.send_action(msg)

    def update_display(self):
        self.status = True
        self.get_info("GENERAL")


    def keypress(self, keycode, status):
        if keycode == KeyboardListener.KEY_UP:
            self.key_up = status
        elif keycode == KeyboardListener.KEY_DOWN:
            self.key_down = status
        elif keycode == KeyboardListener.KEY_LEFT:
            self.key_left = status
        elif keycode == KeyboardListener.KEY_RIGHT:
            self.key_right = status
        elif keycode == 65: # A
            self.key_a = status
        elif keycode == 73: # I
            self.key_i = status
        elif keycode == 32: # SPACE
            self.key_space = status


if __name__ == '__main__':
    pyjd.setup("public/RoverWebClient.html")
    game = Game()
    game.load()
    pyjd.run()

Reply via email to