UDP Help

Discussion related to the Condor...

Moderators: Uros, Tom, OXO

Locked
wolfgang6444
Posts: 33
Joined: Sat Jun 10, 2017 8:22 am

UDP Help

Post by wolfgang6444 » Mon Jan 22, 2018 5:52 pm

I would like to receive the UDP data in some python program over the network, but I don't quite understand the UDP concept:

1)Does a running an instance of Condor require some special 'server-software' that polls the UDP-data or will it send its data e.g. to a telnet session on another computer?

2)What is the Host address? Is this the address of another computer being allowed access to the data? Can I enter netmasks here? How?

3)What network protocol is used to access the data? I guess UDP? Is there a better/simpler way than a telnet session to receive the data?

Thanks,

Wolfgang

sadatoni
Posts: 188
Joined: Sat Apr 15, 2017 1:02 am
Location: Central Ohio, USA

Re: UDP Help

Post by sadatoni » Mon Jan 22, 2018 6:21 pm

I use VSPE to create a COM2 port and forward that to an iP port. Once it is running, I set Condor to use COM2.

See http://www.eterlogic.com/Products.VSPE.html which also has python scripting.

"VSPE is intended to help software engineers and developers to create/debug/test applications that use serial ports. It is able to create various virtual devices to transmit/receive data. Unlike regular serial ports, virtual devices have special capabilities: for example, the same device can be opened more than once by different applications, that can be useful in many cases. With VSPE you are able to share physical serial port data for several applications, expose serial port to local network (via TCP protocol), create virtual serial port device pairs and so on. "
N5503T CN(0OU)

Image
John Ferguson

wolfgang6444
Posts: 33
Joined: Sat Jun 10, 2017 8:22 am

Re: UDP Help

Post by wolfgang6444 » Mon Jan 22, 2018 6:31 pm

I am confused:

There is a software called CondorUDP2COM that converts UDP to a com-port.
VSPE looks like the opposite: forward a serial port over the network.

What is the 'native' connection to receive UDP-data from Condor?
RS232 or IP ?

Thanks,

Wolfgang

User avatar
SteveK
Posts: 836
Joined: Fri May 26, 2006 5:32 pm
Location: London, England

Re: UDP Help

Post by SteveK » Mon Jan 22, 2018 7:12 pm

Looking at the networking side of things...

UDP is one of the protocols within TCP/IP - simplifying thigs a bit - most network data is transferred over TCP or UDP.

TCP is a two-way channel which ensures delivery of each packet of data (various handshakes go back and forth to ensure this). Web browsing, email transmission and collection all happen over TCP. The channel is setup, used for a while (possibly a long time) then the channel is gracefully closed down.

UDP is much simpler - you send a packet, it gets to its destination or it doesn't. That destination is listening to accept the packet or it isn't - You likely get no feedback whatsoever as to if your transmission was received and acted upon. There is no channel set up - you send each packet as a one-off transmission. There is no channel to tear down once you finish. Transmission is one way you send a packet - that's it. The other party can send a packet back, but that would be entirely unrelated to your sent packet (& you'd need to be listening for it).

Condor can be set-up to send data via UDP. In order to receive the data, you'd need to write a program that sat LISTENING for UDP data of the IP ADDRESS of the system your code was running on and on a PORT number that you chose to listen on. Then for each packet received your code could process it in whatever way you desired. The listening port is called a SOCKET.

The Host address is the IP address of the system running the program that includes your UDP listener. It's a single IP address so there is no need for a netmask.

Telnet(client) acts on TCP data. It does not receive data, especially not over UDP. It sets up a TCP connection to a server, then sends and receives data over that connection. Telnet (server) would handle the other of that connection and do something useful with whatever the user typed on the telnet client - again all over TCP and useless for the Condor data.

Re second question.
Condor will normally do Serial (RS232/COM port -it's a tick box in the gui) - That dates back to old serial cables. Originally, you'd attach a PDA or logger via serial cable and it would suck up the data. These days the computer's logical com ports (that's what the old serial connections used to be presented as) can be emulated through software. Condor thinks it's working over serial cables but the software is using that data a different way. IP (UDP) is a way to access the data without all of conversions to / from logical com ports. If you are looking to write your own analysis software, then IP would be cleanest. If you were using COM ports, you'd just end up jury-rigging the com port side of things - you'd still need to write a listener of some kind. Either way it sounds as if would be quite a learning curve for you.

wolfgang6444
Posts: 33
Joined: Sat Jun 10, 2017 8:22 am

Re: UDP Help

Post by wolfgang6444 » Mon Jan 22, 2018 7:28 pm

Thanks a lot!

So all I need to do is configure the host-address of my receiving computer inside Condor, get the firewalls to allow access to the port and write some code to receive data vi UDP. That should be feasible.

Wolfgang

sadatoni
Posts: 188
Joined: Sat Apr 15, 2017 1:02 am
Location: Central Ohio, USA

Re: UDP Help

Post by sadatoni » Mon Jan 22, 2018 7:51 pm

I see. The Codor manual actually discusses its UDP port in section 7.2 (the 1.1.5 version of the manual).
N5503T CN(0OU)

Image
John Ferguson

wolfgang6444
Posts: 33
Joined: Sat Jun 10, 2017 8:22 am

Re: UDP Help

Post by wolfgang6444 » Mon Jan 22, 2018 8:06 pm

Given I only need to listen to UDP traffic on port 55278 of the PC running Condor, I have installed ncat and started:

ncat.exe -u -vvv localhost 55278 on the PC running Condor.

I don't get any data when Condor is running. UUDP2COM does however show the data.

What am still getting wrong still?

The Manual explains the data sent, but is not of much use when trying to establish the basic connection.

Wolfgang

User avatar
SteveK
Posts: 836
Joined: Fri May 26, 2006 5:32 pm
Location: London, England

Re: UDP Help

Post by SteveK » Mon Jan 22, 2018 8:07 pm

wolfgang6444 wrote:Thanks a lot!

So all I need to do is configure the host-address of my receiving computer inside Condor, get the firewalls to allow access to the port and write some code to receive data vi UDP. That should be feasible.

Wolfgang
..."Host address "...AND receiving port number... Your software BINDS to a port to LISTEN on it. Port numbers range from 1 to 65535. However the first 1024 are reserved for the OS and the lower numbers just above that range might be used by other software - I'd make the port number easily configurable.

"write some code to receive data via UDP." .... That might be more complex that you think - I don't know what facilities Python has to listen on raw ports. It may well be very be different to anything else you've done.

wolfgang6444
Posts: 33
Joined: Sat Jun 10, 2017 8:22 am

Re: UDP Help

Post by wolfgang6444 » Mon Jan 22, 2018 8:25 pm

Well not quite that complicated after all - once I got the concept thanks to your help:

import socket
port = 55278
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", port))
print("waiting on port:", port)
while 1:
data, addr = s.recvfrom(1024)
print(data)

That does the trick.

My misunderstanding: I need to program a server that LISTENS to port 55278 rather than establish a connection TO port 55278.

Thanks again,

Wolfgang

User avatar
SteveK
Posts: 836
Joined: Fri May 26, 2006 5:32 pm
Location: London, England

Re: UDP Help

Post by SteveK » Tue Jan 23, 2018 6:19 am

That 'synchronous' method will work as long as you can process the data received fully before the next packet arrives. If your processing takes too long you would lose samples.

If you are updating realtime instruments, that probably would not matter (having the display current is important, and what happened in the past does not matter). If you are processing the data or logging or statistics, then the missing samples probably would matter.

Where I though that complications might come in, was that was more thinking of asynchronous methods where you set a listener of some kind running continuously, and that calls your code for each packet received (runs a method/calls you back/executes some kind of closure - hopefully doing so in a different thread, as not to block the receiver thread).Additionally the rest (UI?) of your application would keep running whilst the listener was capturing.

wolfgang6444
Posts: 33
Joined: Sat Jun 10, 2017 8:22 am

Re: UDP Help

Post by wolfgang6444 » Tue Jan 23, 2018 7:16 am

I am currently writing a python program that displays and logs the controls inputs
i.e. elevator, aileron, rudder, air-brakes and trim.
I am using pyglet to capture the joystick position directly from the USB-devices and
display them. That works fine so far.
Now I want to keep track of simulation time in order to be able to 'replay' the control-position
together with the actual flight replay.
To this end I want to use the 'time' information in the UDP frames.
The idea is to have a thread that constantly listens to the UDP-frames, extracts the time
information, and updates a variable shared by all threads.
Another thread would then dump all positions together with the 'time-stamp' to some file
on a regular basis.
Upon reply I will again receive the time from udp and then read and display all movements
from the file until the time-stamp in the file is greater than the current time-stamp received
from UDP. This will be repeated in the display-loop.
I hope that the thread dedicated to reading the UDP-input will keep track, so the potential
problems you mentioned can be avoided.

Wolfgang

Dicxit2
Posts: 16
Joined: Fri Jan 11, 2008 8:16 am
Location: Provence

Re: UDP Help

Post by Dicxit2 » Tue Jan 23, 2018 11:24 am

Good morning
watch at this programme developing by ZAD...
see you soon
Eric

http://condornav.fr/

wolfgang6444
Posts: 33
Joined: Sat Jun 10, 2017 8:22 am

Re: UDP Help

Post by wolfgang6444 » Sat Feb 03, 2018 6:53 pm

Hello,

I have finished my project and would like to share the result in case somebody can use this as source of inspiration:

forward_udp.py is as UDP-server listening on port 55278 and sending to port 55279 to some remote host.
forward_udp.py has to run on the same machine as Condor.
forward_udp.py adds information about the current joystick-position and pedal position to the UDP-stream.

coord.py is to run on the remote machine (Linux in my case). It listens to port 55279 and stores the information
in some temporary file.
coord.py displays all of the joystick and pedal positions in an X/Y display during the flight.
Upon replay it uses the temporary file and replays the joystick and pedal positions of the last recorded flight as it is being replayed
in Condor.
Adaptations need to be made to reflect the joystick and pedal type and the location of the temporary-file etc. - but that should be quite obvious.

Thanks again for the kick-start help,

Wolfgang

forward_udp.py:

Code: Select all

#!/usr/bin/env python
import multiprocessing
import os
import pyglet
import re
import socket

def udp(aileron,elevator,air_brakes,trimm,rudder,receive_port,send_port,send_ip):
    sin = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sout = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sin.bind(("", receive_port))
    total_string=''
    p = re.compile('time=[\\d\\.]+\\r\\n')
    while 1:
        data, addr = sin.recvfrom(1024)
        total_string = total_string + data.decode('utf-8')
        if re.search(p,total_string):
            for m in p.finditer(total_string):
#                print(total_string[0:m.start()],end='')
                sout.sendto(bytes(total_string[0:m.start()], "utf-8"), (send_ip, send_port))

#                print(total_string[m.start():m.end()],end='')
                sout.sendto(bytes(total_string[m.start():m.end()], "utf-8"), (send_ip, send_port))

#                print("aileron=%f"%aileron.value);
                sout.sendto(bytes("aileron=%f\r\n" % aileron.value, "utf-8"), (send_ip, send_port))

#                print("elevator=%f"%elevator.value);
                sout.sendto(bytes("elevator=%f\r\n" % elevator.value, "utf-8"), (send_ip, send_port))

#                print("rudder=%f"%rudder.value);
                sout.sendto(bytes("rudder=%f\r\n" % rudder.value, "utf-8"), (send_ip, send_port))

#                print("air_brakes=%f"%air_brakes.value);
                sout.sendto(bytes("air_brakes=%f\r\n" % air_brakes.value, "utf-8"), (send_ip, send_port))

#                print("trimm=%f"%trimm.value);
                sout.sendto(bytes("trimm=%f\r\n" % trimm.value, "utf-8"), (send_ip, send_port))

                total_string=total_string[m.end():]
                pass

def get_joystick(name,aileron,elevator,air_brakes,trimm,rudder):
    joysticks = pyglet.input.get_joysticks()
    assert joysticks, 'No joystick device is connected'

    for joystick in joysticks:
        if(re.match(name,joystick.device.name)) :
            stick=joystick

    stick.open()

    @stick.event
    def on_joyaxis_motion(joystick, axis, value):
        if(re.match('SideWinder',stick.device.name)):
            if(axis == "x"):
                aileron.value = value
            if(axis == "y"):
                elevator.value = value
            if(axis == "z"):
                air_brakes.value = value
            if(axis == "rz"):
                trimm.value = value

        if(re.match('VKBsim Black Box',stick.device.name) and axis == 'rx'):
            rudder.value = value
    pyglet.clock.schedule(lambda dt: None)
    pyglet.app.run()

def draw_canvas(aileron,elevator,air_brakes,trimm,rudder):
    pyglet.clock.schedule(lambda dt: None)
    pyglet.app.run()

if __name__ == '__main__':
    aileron = multiprocessing.Value('d', 0)
    elevator = multiprocessing.Value('d', 0)
    rudder = multiprocessing.Value('d', 0)
    air_brakes = multiprocessing.Value('d', 0)
    trimm = multiprocessing.Value('d', 0)

    p1 = multiprocessing.Process(target=get_joystick, args=('SideWinder',aileron,elevator,air_brakes,trimm,rudder))
    p2 = multiprocessing.Process(target=get_joystick, args=('VKBsim Black Box',aileron,elevator,air_brakes,trimm,rudder))
    p3 = multiprocessing.Process(target=draw_canvas, args=(aileron,elevator,air_brakes,trimm,rudder))
    p4 = multiprocessing.Process(target=udp, args=(aileron,elevator,air_brakes,trimm,rudder,55278,55279,'192.168.2.33'))

    p1.start()
    p2.start()
    p3.start()
    p4.start()
    p1.join()
    p2.join()
    p3.join()
    p4.join()
coord.py:

Code: Select all

#!/usr/bin/env python
import multiprocessing
import os
import pyglet
import pyglet.window
import pyglet.gl
import re
import socket
import time
import scanf
import fileinput

def read_file(replay,sim_time,airspeed,aileron,elevator,air_brakes,trimm,rudder):
    replay_time =0
    last_sim_time=0
    r_file=open("/var/Condor/Condor.udp","r")
    while(1):
        if(not replay.is_set):
            replay_time =0
            last_sim_time=0
            r_file.close()
        replay.wait()
        if(r_file.closed):
            r_file=open("/var/Condor/Condor.udp","r")
            replay_time=0
            print("opening file for read")

        line=r_file.readline()
        if(line):
            tup=scanf.scanf("time=%f", line)
            if not(tup is None):
                replay_time=tup[0]
#                print("replay_time:%f,sim_time: %f" % (replay_time, sim_time.value))
                
            while(replay_time > sim_time.value):
#                print("SIM_TIME: %f" % sim_time.value)
#                print("LAST_SIM_TIME: %f" % last_sim_time)
#                print("replay_time: %f\n" % replay_time)
#reread-file if sim_time steps back.                
                if(last_sim_time > sim_time.value):
                      print("replay detected")
                      r_file.close()
                      last_sim_time = 0
                      break
                last_sim_time = sim_time.value
                pass
            tup=scanf.scanf("airspeed=%f", line)
            if not(tup is None):
                airspeed.value=tup[0] *3.6
            tup=scanf.scanf("aileron=%f", line)
            if not(tup is None):
                aileron.value=tup[0]
            tup=scanf.scanf("elevator=%f", line)
            if not(tup is None):
                elevator.value=tup[0]

            tup=scanf.scanf("rudder=%f", line)
            if not(tup is None):
                rudder.value=tup[0]

            tup=scanf.scanf("air_brakes=%f", line)
            if not(tup is None):
                air_brakes.value=tup[0]

            tup=scanf.scanf("trimm=%f", line)
            if not(tup is None):
                trimm.value=tup[0]
        else:
            r_file.close()
            sim_time.value=0
            time.sleep(1)


def udp(replay,sim_time,airspeed,aileron,elevator,air_brakes,trimm,rudder,receive_port):
    last_sim_time=0
    w_file=open("/var/Condor/Condor.udp","r")
    w_file.close()
    sin = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sin.bind(("", receive_port))
    p = re.compile('airspeed=[\\d\\.]+\\r\\n')
    total_string=''
    while 1:
        data, addr = sin.recvfrom(1024)

        if(not w_file.closed):
            if(data):
                w_file.write(data)
            if(replay.is_set()):
                w_file.close                
        else:
            if(not replay.is_set()):
                print("opening file for write")
                w_file=open("/var/Condor/Condor.udp","w")
                pass

        total_string = total_string + data.decode('utf-8')
        if re.search(p,total_string):
            for m in p.finditer(total_string):

                tup=scanf.scanf("time=%f", total_string)
                if not(tup is None):
                    sim_time.value=tup[0]
#                    print("SIM_TIME_X: %f" % sim_time.value)
#                    print("LAST_SIM_TIME_X: %f" % last_sim_time)
#goto replay if sim_time steps back                    
                    if(last_sim_time > sim_time.value):
                        print("replay detected_X")
                        last_sim_time = 0
                        replay.set()
                    last_sim_time = sim_time.value

                if(not replay.is_set()):
                    tup=scanf.scanf("airspeed=%f", total_string)
                    if not(tup is None):
                        airspeed.value=tup[0] * 3.6
                    tup=scanf.scanf("aileron=%f", total_string)
                    if not(tup is None):
                        aileron.value=tup[0]
                    tup=scanf.scanf("elevator=%f", total_string)
                    if not(tup is None):
                        elevator.value=tup[0]

                    tup=scanf.scanf("rudder=%f", total_string)
                    if not(tup is None):
                        rudder.value=tup[0]

                    tup=scanf.scanf("air_brakes=%f", total_string)
                    if not(tup is None):
                        air_brakes.value=tup[0]

                    tup=scanf.scanf("trimm=%f", total_string)
                    if not(tup is None):
                        trimm.value=tup[0]

                total_string=total_string[m.end():]

def get_joystick(name,aileron,elevator,air_brakes,trimm,rudder):
    joysticks = pyglet.input.get_joysticks()
    assert joysticks, 'No joystick device is connected'

    for joystick in joysticks:
        if(re.match(name,joystick.device.name)) :
            stick=joystick

    stick.open()

    @stick.event
    def on_joyaxis_motion(joystick, axis, value):
        if(re.match('SideWinder',stick.device.name)):
            if(axis == "x"):
                aileron.value = value
            if(axis == "y"):
                elevator.value = value
            if(axis == "z"):
                air_brakes.value = value
            if(axis == "rz"):
                trimm.value = value

        if(re.match('VKBsim Black Box',stick.device.name) and axis == 'rx'):
            rudder.value = value
    pyglet.clock.schedule(lambda dt: None)
    pyglet.app.run()

def draw_canvas(replay,airspeed,aileron,elevator,air_brakes,trimm,rudder):
    window = pyglet.window.Window()

    @window.event
    def on_key_press(symbol, modifiers):
        global hold
        global pointsize

        if symbol == pyglet.window.key.Q:
            quit()
        if symbol == pyglet.window.key.H:
            if(hold==True):
                hold=False
                pointsize=5
            else:
                hold=True
                pointsize=1
        if symbol == pyglet.window.key.R:
            if(replay.is_set()):
                replay.clear()
            else:
                replay.set()

    @window.event
    def on_key_release(symbol, modifiers):
        global extra_clear
        if symbol == pyglet.window.key.H:
            extra_clear = 10
        if symbol == pyglet.window.key.R:
            extra_clear = 10

    @window.event
    def on_draw():
        global hold
        global pointsize
        global extra_clear

        if(not hold):
            pyglet.gl.glClear(pyglet.gl.GL_COLOR_BUFFER_BIT)

        if(extra_clear>0):
            pyglet.gl.glClear(pyglet.gl.GL_COLOR_BUFFER_BIT)
            extra_clear=extra_clear-1

        pyglet.gl.glLoadIdentity()

#        print("airspeed=%.0f" % airspeed.value * 3.6)
        replay_label=pyglet.text.Label('replay',
                          font_name='Times New Roman',
                          font_size=18,
                          x=0.05*window.width,
                          y=0.95*window.height,
                          anchor_x='center', anchor_y='center')
        speed_label=pyglet.text.Label("airspeed=%.0f" % airspeed.value,
                          font_name='Times New Roman',
                          font_size=18,
                          x=0.5*window.width,
                          y=0.05*window.height,
                          anchor_x='center', anchor_y='center')
        if(not hold):
            speed_label.draw()
        if(replay.is_set()):
            replay_label.draw()
        
        pyglet.gl.glColor3f(0, 1, 0)    
        # main diagonal
        pyglet.gl.glBegin(pyglet.gl.GL_LINES)
        pyglet.gl.glVertex2f(0.1*window.width,0.1*window.height)
        pyglet.gl.glVertex2f(0.9*window.width,0.9*window.height)
        pyglet.gl.glEnd()
        
        # horizontal grid-lines
        pyglet.gl.glColor3f(0.5, 0.5, 0.5)    
        pyglet.gl.glBegin(pyglet.gl.GL_LINES)
        pyglet.gl.glVertex2f(0.1*window.width,0.1*window.height)
        pyglet.gl.glVertex2f(0.9*window.width,0.1*window.height)
        pyglet.gl.glEnd()
        
        pyglet.gl.glBegin(pyglet.gl.GL_LINES)
        pyglet.gl.glVertex2f(0.1*window.width,0.3*window.height)
        pyglet.gl.glVertex2f(0.9*window.width,0.3*window.height)
        pyglet.gl.glEnd()
        
        pyglet.gl.glBegin(pyglet.gl.GL_LINES)
        pyglet.gl.glVertex2f(0.1*window.width,0.5*window.height)
        pyglet.gl.glVertex2f(0.9*window.width,0.5*window.height)
        pyglet.gl.glEnd()
        
        pyglet.gl.glBegin(pyglet.gl.GL_LINES)
        pyglet.gl.glVertex2f(0.1*window.width,0.7*window.height)
        pyglet.gl.glVertex2f(0.9*window.width,0.7*window.height)
        pyglet.gl.glEnd()
        
        pyglet.gl.glBegin(pyglet.gl.GL_LINES)
        pyglet.gl.glVertex2f(0.1*window.width,0.9*window.height)
        pyglet.gl.glVertex2f(0.9*window.width,0.9*window.height)
        pyglet.gl.glEnd()
        
        # vertical grid-lines
        pyglet.gl.glBegin(pyglet.gl.GL_LINES)
        pyglet.gl.glVertex2f(0.1*window.width,0.1*window.height)
        pyglet.gl.glVertex2f(0.1*window.width,0.9*window.height)
        pyglet.gl.glEnd()
        
        pyglet.gl.glBegin(pyglet.gl.GL_LINES)
        pyglet.gl.glVertex2f(0.3*window.width,0.1*window.height)
        pyglet.gl.glVertex2f(0.3*window.width,0.9*window.height)
        pyglet.gl.glEnd()
        
        pyglet.gl.glBegin(pyglet.gl.GL_LINES)
        pyglet.gl.glVertex2f(0.5*window.width,0.1*window.height)
        pyglet.gl.glVertex2f(0.5*window.width,0.9*window.height)
        pyglet.gl.glEnd()
        
        pyglet.gl.glBegin(pyglet.gl.GL_LINES)
        pyglet.gl.glVertex2f(0.7*window.width,0.1*window.height)
        pyglet.gl.glVertex2f(0.7*window.width,0.9*window.height)
        pyglet.gl.glEnd()
        
        pyglet.gl.glBegin(pyglet.gl.GL_LINES)
        pyglet.gl.glVertex2f(0.9*window.width,0.1*window.height)
        pyglet.gl.glVertex2f(0.9*window.width,0.9*window.height)
        pyglet.gl.glEnd()
        
        pyglet.gl.glColor3f(1, 0, 0)
        pyglet.gl.glTranslatef((0.8*rudder.value + 1)*window.width/2,(0.8*aileron.value + 1)*window.height/2, 0)
        pyglet.gl.glBegin(pyglet.gl.GL_QUADS)
        pyglet.gl.glVertex2f(-pointsize, -pointsize)
        pyglet.gl.glVertex2f(-pointsize, pointsize)
        pyglet.gl.glVertex2f(pointsize, pointsize)
        pyglet.gl.glVertex2f(pointsize, -pointsize)
        pyglet.gl.glEnd()

        pyglet.gl.glLoadIdentity()
        pyglet.gl.glColor3f(0.8, 0.8, 0.8)
        pyglet.gl.glTranslatef((0.8*aileron.value + 1)*window.width/2,(-0.8*elevator.value + 1)*window.height/2, 0)
        pyglet.gl.glBegin(pyglet.gl.GL_QUADS)
        pyglet.gl.glVertex2f(-pointsize, -pointsize)
        pyglet.gl.glVertex2f(-pointsize, pointsize)
        pyglet.gl.glVertex2f(pointsize, pointsize)
        pyglet.gl.glVertex2f(pointsize, -pointsize)
        pyglet.gl.glEnd()

        pyglet.gl.glLoadIdentity()
        pyglet.gl.glColor3f(0, 0, 1)
        pyglet.gl.glTranslatef(0.1*window.width,(-0.8*air_brakes.value + 1)*window.height/2, 0)
        pyglet.gl.glBegin(pyglet.gl.GL_QUADS)
        pyglet.gl.glVertex2f(-5, -5)
        pyglet.gl.glVertex2f(-5, 5)
        pyglet.gl.glVertex2f(5, 5)
        pyglet.gl.glVertex2f(5, -5)
        pyglet.gl.glEnd()

        pyglet.gl.glLoadIdentity()
        pyglet.gl.glColor3f(0, 1, 0)
        pyglet.gl.glTranslatef(0.9*window.width,(-0.8*trimm.value + 1)*window.height/2, 0)
        pyglet.gl.glBegin(pyglet.gl.GL_QUADS)
        pyglet.gl.glVertex2f(-5, -5)
        pyglet.gl.glVertex2f(-5, 5)
        pyglet.gl.glVertex2f(5, 5)
        pyglet.gl.glVertex2f(5, -5)
        pyglet.gl.glEnd()

    pyglet.clock.schedule(lambda dt: None)
    pyglet.app.run()

if __name__ == '__main__':
    airspeed =    multiprocessing.Value('d', 0)
    aileron =    multiprocessing.Value('d', 0)
    elevator =   multiprocessing.Value('d', 0)
    rudder =     multiprocessing.Value('d', 0)
    air_brakes = multiprocessing.Value('d', 0)
    trimm =      multiprocessing.Value('d', 0)
    sim_time =   multiprocessing.Value('d', 0)
    replay=      multiprocessing.Event()
    extra_clear=10

    replay.set()

    hold=True
    pointsize=1

    p1 = multiprocessing.Process(target=get_joystick, args=('SideWinder',aileron,elevator,air_brakes,trimm,rudder))
    p2 = multiprocessing.Process(target=get_joystick, args=('VKBsim Black Box',aileron,elevator,air_brakes,trimm,rudder))
    p3 = multiprocessing.Process(target=draw_canvas, args=(replay,airspeed,aileron,elevator,air_brakes,trimm,rudder))
    p4 = multiprocessing.Process(target=udp, args=(replay,sim_time,airspeed,aileron,elevator,air_brakes,trimm,rudder,55279))
    p5 = multiprocessing.Process(target=read_file,args=(replay,sim_time,airspeed,aileron,elevator,air_brakes,trimm,rudder))
#    p1.start()
#    p2.start()
    p3.start()
    p4.start()
    p5.start()
#    p1.join()
#    p2.join()
    p3.join()
    p4.terminate()
    p5.terminate()
    quit()
    p4.join()
    p5.join()

Locked