def main(self):
        if len(sys.argv) == 2:
            computeFromLogs(sys.argv[1])
        elif len(sys.argv) == 4:
            self.planeID = sys.argv[1]
            iface = sys.argv[2]
            self.logfile = sys.argv[3]
            self.log = Log(self.logfile)

            #TCP sender for communication with base station
            self.sender = TCPSender()
            self.sender.start()

            #Thread responsible for reading GPS coordinates
            self.t = Thread(target=self.readSTDIN, args=())
            self.t.start()

            self.receiver = Thread(target=self.readRoutingInstructions,
                                   args=())
            self.receiver.start()

            sniff(iface=iface, prn=self.trackClients, store=0)
        else:
            print "Invalid arguments"
            print "\tUsage live mode : ./PlaneSniffer <planeID> <interface> <logfile>"
            print "\tUsage replay mode : ./PlaneSniffer <logfile>"
	def main(self):
		if len(sys.argv) == 2:
			computeFromLogs(sys.argv[1])
		elif len(sys.argv) == 4:
			self.planeID = sys.argv[1]
			iface = sys.argv[2]
			self.logfile = sys.argv[3]
			self.log = Log(self.logfile)
			
			#TCP sender for communication with base station
			self.sender = TCPSender()
			self.sender.start()
			
			#Thread responsible for reading GPS coordinates
			self.t = Thread(target=self.readSTDIN, args = ())
			self.t.start()
			
			self.receiver = Thread(target=self.readRoutingInstructions, args = ())
			self.receiver.start()
			
			sniff(iface=iface,prn=self.trackClients,store=0)
		else:
			print "Invalid arguments"
			print "\tUsage live mode : ./PlaneSniffer <planeID> <interface> <logfile>"
			print "\tUsage replay mode : ./PlaneSniffer <logfile>"
class Sniffer():
    """This class contains the core algorithms reponsible for geolocalizing
	people on the ground, using the beacon frames received by their
	smartphone and sniffed by a radio interface.
	
	GPS position (lat, lon, alt, heading) should be passed through stdin.
	It also provide a communication channel (TCP) with the base station.
	
	If you want to use this script on the plane (gumstix) you should set
	FLIGHT_MODE to TRUE.
	If you want to compute the localization from the log file, you should set it
	to False.
	"""
    def __init__(self):

        #Detected wireless clients and their signal's power + coordinates of the plane
        self.clientsSignalPower = {}

        #Decrease search area (radius, in meters)
        self.reducing_search = False
        self.search_radius = 249

        #Min acceptable power to localize users
        self.MIN_POWER = 0

        #Coordinates
        self.coord = (0, 0, 0)
        self.angle = 0

        #Logging system
        self.logfile = ""

    def readSTDIN(self):
        """
		Read STDIN until EOF char received
		Receive plane's coordinate from the GPS
		"""
        try:
            buff = ''
            while True:
                buff += sys.stdin.read(1)
                if buff.endswith('\n'):
                    buff = buff[:-1].split('\n')[-1]
                    buff = buff.split(', ')
                    self.angle = float(buff[5])
                    self.coord = tuple(
                        (float(buff[0]), float(buff[1]), float(buff[2])))
                    t = Thread(target=self.send_position_to_station,
                               args=(self.coord, self.angle))
                    t.start()
                    buff = ''
        except KeyboardInterrupt:
            sys.stdout.flush()
            pass

    def reduceSearchArea(self, target='c4:88:e5:24:3d:83'):
        """
		Route the plane on a smaller circle each 2 minutes 
		And localize the target user. The latest localization
		will be the new center of the next circle.
		"""
        while True:

            (lat, lon) = self.localize_user(target, 30, 100)
            self.writeFileForPilot(lat, lon, self.search_radius)
            print "Reducing search area to circle : %f,%f radius : %f" % (
                lat, lon, self.search_radius)
            self.search_radius = self.search_radius * 0.5  #reduce radius for next iteration
            if (self.search_radius < 20.0):
                sys.exit(0)  #End of search !

            time.sleep(1 * 60 * 2)

    def readRoutingInstructions(self):
        """
		Wait for routing instruction send by the base station on the
		TCP connection.
		"""
        while True:
            instructions = self.sender.receive()
            if not instructions == None:
                (event, lat, lon, radius) = instructions
                print "Received routing instructions ! %r %r %r" % (lat, lon,
                                                                    radius)
                #compute the center:
                radius = float(radius)
                radius = min(radius, 249)
                self.writeFileForPilot(lat, lon, radius)
                self.t = Thread(target=self.reduceSearchArea, args=(''))
                self.t.start()

    def writeFileForPilot(self, center_x, center_y, radius, altitude=50):
        """This is the command that allows to pass a new waypoint to the
		plane's autopilot"""
        command = "/smavnet/gapi_sendcoordinates %.8f %.8f %.8f %.8f" % (
            float(center_x), float(center_y), altitude, float(radius))
        os.system(command)

    def compute_center_of_mass(self, samples, sort_tuple, map_pwr_func,
                               pwr_thresh, beacon_thresh, beacon_rpt_int):
        """Compute the geolocalization of every user that the plane is
		aware of
		
		Keyword arguments:
		samples 	-- the list of beacon frames received
				       following the format : (
		sort_tuple 	-- number of the tuple by which the samples should
					  be sorted
		map_pwr_func -- mapping function of the power
		pwr_thresh -- power threshold (min power)
		beacon_thresh -- number of beacon frames considered
		beacon_rpt_int -- unused
		"""

        usr = list(set(samples))
        usr.sort(key=lambda tup: tup[sort_tuple], reverse=True)
        usr = GPSUtil.remove_duplicate_GPS(usr, beacon_rpt_int)

        allLat = 0
        allLon = 0

        pwrs = []
        for (lat, lon, alt, pwr, mac) in usr[0:min(len(usr), beacon_thresh)]:
            if pwr >= pwr_thresh and lat > 0.0 and lon > 0.0:
                pwr = map_pwr_func(pwr)

                ###DISABLED IN FLIGHT MODE !
                if not FLIGHT_MODE:
                    self.gMapDisplay.addLabel(lat,
                                              lon,
                                              text="%f %f" % (lat, pwr))
                #############################

                pwrs.append(pwr)
                allLat += pwr * lat
                allLon += pwr * lon

        if sum(pwrs) == 0:
            return None

        return (allLat / sum(pwrs), allLon / sum(pwrs))

    def localize_user(self,
                      user,
                      pwr_thresh=20,
                      beacon_thresh=15,
                      beacon_rpt_int=5,
                      sort_tuple=3):
        """Compute the localization of a specific user """
        samples = self.clientsSignalPower[user]
        pwr_func = lambda x: x * 2**math.log(x / 10.0)  # if x > 30 else x
        return self.compute_center_of_mass(samples=samples,
                                           sort_tuple=sort_tuple,
                                           map_pwr_func=pwr_func,
                                           pwr_thresh=pwr_thresh,
                                           beacon_thresh=beacon_thresh,
                                           beacon_rpt_int=beacon_rpt_int)

    def send_beacon_to_station(self, user, coord, pwr):
        self.sender.send("[beacon]%s\t%s\t%s\t%f" %
                         (user, coord[0], coord[1], pwr))
        print "Sending beacon !"

    def send_position_to_station(self, coord, angle):
        self.log.writePlanePosition(self.planeID, coord, angle)
        self.sender.send("[plane]%s\t%s\t%s\t%d" %
                         (self.planeID, coord[0], coord[1], angle))

    def send_localization_to_station(self, user, coord):
        self.log.writeLocalization(user, coord)
        self.sender.send("[user]%s\t%s\t%s" % (user, coord[0], coord[1]),
                         retry=True)

    def cleanLogFile(self, log):
        """ It happens that log files generated by the planes
		are somehow corrupted (null bytes, empty lines etc...)
		This method tries to correct the format of this log file
		"""
        clean = []
        with open(log) as tsv:
            for entry in csv.reader(tsv, dialect="excel-tab"):
                if len(entry) == 0:
                    continue
                if entry[0] == "[BEACON]":
                    if not len(entry) == 7:
                        if not len(entry) == 13:
                            print "Unrecoverable line in logfile. Skipped..."
                        else:
                            (event0, ts0, mac0, lat0, lon0, alt0,
                             pwr0MixEvent1, ts1, plane1, lat1, lon1, alt1,
                             angle1) = entry
                            pwr0 = float(pwr0MixEvent1.replace("[COORD]", ""))
                            #print "Invalid line recovered"
                            frame0 = (event0, ts0, mac0, lat0, lon0, alt0,
                                      pwr0)
                            frame1 = ("[COORD]", ts1, plane1, lat1, lon1, alt1,
                                      angle1)

                            clean.append(frame0)
                            clean.append(frame1)
                    else:
                        clean.append(entry)
        return clean

    def feedData(self, log, mac_filter):
        """Load the data from the logs"""
        minPower = 100
        maxPower = 0

        for entry in self.cleanLogFile(log):
            if entry[0] == "[BEACON]":
                (event, ts, mac, lat, lon, alt, pwr) = entry

                mac = mac[1:-1]

                if lat == 0 or lon == 0 or pwr < 0 or not mac in mac_filter:
                    continue

                lat = float(lat)
                lon = float(lon)
                alt = float(alt)
                pwr = float(pwr)
                ts = int(ts)

                if not mac in self.clientsSignalPower:
                    self.clientsSignalPower[mac] = []
                self.clientsSignalPower[mac].append(
                    (ts, lat, lon, alt, pwr, mac))

                maxPower = max(pwr, maxPower)
                minPower = min(pwr, minPower)

    def computeFromLogs(self,
                        log,
                        mac_filter,
                        pwr_thresh=28,
                        beacon_thresh=5,
                        beacon_rpt_int=5,
                        sort_tuple=4,
                        output_file="flight.html"):
        """Compute the geolocalization from the log files"""
        global app
        self.feedData(log, mac_filter)

        ###DISABLED IN FLIGHT MODE !
        if not FLIGHT_MODE:
            if app == None:
                app = QtGui.QApplication([])
            self.gMapDisplay = GoogleMapDisplay(46.518550,
                                                6.562460,
                                                zoom=18,
                                                output_file=output_file)
        ############################

        lastGPS = None

        for user in mac_filter:
            guess = self.localize_user(user, pwr_thresh, beacon_thresh,
                                       beacon_rpt_int, sort_tuple)
            refPosition = GPSPosition(mac_filter[user][0], mac_filter[user][1])

            ###DISABLED IN FLIGHT MODE !
            if not FLIGHT_MODE:
                self.gMapDisplay.addLabel(guess[0],
                                          guess[1],
                                          text=user,
                                          fontFamily='sans-serif',
                                          fontSize=18,
                                          fontColor='#00ff00',
                                          strokeWeight=8,
                                          strokeColor='#00ff00',
                                          align='center',
                                          marker=True)
            ##################################

            error = GPSUtil.haversine_meter(GPSPosition(guess[0], guess[1]),
                                            refPosition)
            #print "Accuracy of %s : %fm." % (user, error)

        ###DISABLED IN FLIGHT MODE !
        if not FLIGHT_MODE:
            for (lat, lon) in mac_filter.values():
                self.gMapDisplay.addPoint(lat,
                                          lon,
                                          radius=5,
                                          fillOpacity=1.0,
                                          fillColor='#000000',
                                          strokeColor='#0F000F')
            self.gMapDisplay.drawMap()
        ##################################

        return error

    def main(self):
        if len(sys.argv) == 2:
            computeFromLogs(sys.argv[1])
        elif len(sys.argv) == 4:
            self.planeID = sys.argv[1]
            iface = sys.argv[2]
            self.logfile = sys.argv[3]
            self.log = Log(self.logfile)

            #TCP sender for communication with base station
            self.sender = TCPSender()
            self.sender.start()

            #Thread responsible for reading GPS coordinates
            self.t = Thread(target=self.readSTDIN, args=())
            self.t.start()

            self.receiver = Thread(target=self.readRoutingInstructions,
                                   args=())
            self.receiver.start()

            sniff(iface=iface, prn=self.trackClients, store=0)
        else:
            print "Invalid arguments"
            print "\tUsage live mode : ./PlaneSniffer <planeID> <interface> <logfile>"
            print "\tUsage replay mode : ./PlaneSniffer <logfile>"

    def trackClients(self, p):
        """Listen for probe requests/response in the network"""

        #We're only concerned by probe request packets
        #Also, sometime, addr2 is NoneType (don't know why actually)
        #p.type = 0 -> management frame
        if not p.haslayer(Dot11) or p.addr2 is None:
            return

        #Ensure that this is a client
        if p.type == 0 and p.subtype in (0, 2, 4):
            #Signal strength
            #if not p.addr2 == 'c4:88:e5:24:3d:83':
            #return
            sig_str = 100 - (256 - ord(p.notdecoded[-4:-3]))
            self.send_beacon_to_station(p.addr2, self.coord, sig_str)
            t = Thread(target=self.send_beacon_to_station,
                       args=(p.addr2, self.coord, sig_str))
            t.start()
            self.log.writeBeacon(p.addr2, self.coord, sig_str)
            if not p.addr2 in self.clientsSignalPower:
                self.clientsSignalPower[p.addr2] = []
            self.clientsSignalPower[p.addr2].append(
                (self.log.ts(), self.coord[0], self.coord[1], self.coord[2],
                 sig_str, p.addr2))
            center_of_mass = self.localize_user(p.addr2,
                                                pwr_thresh=26,
                                                beacon_thresh=26,
                                                beacon_rpt_int=5,
                                                sort_tuple=3)
            if not center_of_mass == None:
                t = Thread(target=self.send_localization_to_station,
                           args=(p.addr2, center_of_mass))
                t.start()
class Sniffer():
	"""This class contains the core algorithms reponsible for geolocalizing
	people on the ground, using the beacon frames received by their
	smartphone and sniffed by a radio interface.
	
	GPS position (lat, lon, alt, heading) should be passed through stdin.
	It also provide a communication channel (TCP) with the base station.
	
	If you want to use this script on the plane (gumstix) you should set
	FLIGHT_MODE to TRUE.
	If you want to compute the localization from the log file, you should set it
	to False.
	"""

	def __init__(self):
	
		#Detected wireless clients and their signal's power + coordinates of the plane
		self.clientsSignalPower = {}
		
		#Decrease search area (radius, in meters)
		self.reducing_search = False
		self.search_radius = 249 
		
		#Min acceptable power to localize users
		self.MIN_POWER = 0
		
		#Coordinates
		self.coord = (0,0,0)
		self.angle = 0
	
		#Logging system
		self.logfile = ""
		
	
	def readSTDIN(self):
		"""
		Read STDIN until EOF char received
		Receive plane's coordinate from the GPS
		"""
		try:
			buff = ''
			while True:
				buff += sys.stdin.read(1)
				if buff.endswith('\n'):
					buff = buff[:-1].split('\n')[-1]
					buff = buff.split(', ')
					self.angle = float(buff[5])
					self.coord = tuple((float(buff[0]), float(buff[1]), float(buff[2])))
					t = Thread(target=self.send_position_to_station, args = (self.coord, self.angle))
					t.start()
					buff = ''
		except KeyboardInterrupt:
			sys.stdout.flush()
			pass
			
	def reduceSearchArea(self, target='c4:88:e5:24:3d:83'):
		"""
		Route the plane on a smaller circle each 2 minutes 
		And localize the target user. The latest localization
		will be the new center of the next circle.
		"""
		while True:
			
			(lat,lon) = self.localize_user(target,30,100)
			self.writeFileForPilot(lat,lon,self.search_radius)
			print "Reducing search area to circle : %f,%f radius : %f" % (lat,lon,self.search_radius)
			self.search_radius = self.search_radius * 0.5 #reduce radius for next iteration
			if (self.search_radius < 20.0):
				sys.exit(0) #End of search !
				
			time.sleep(1*60*2)
			
			
	def readRoutingInstructions(self):
		"""
		Wait for routing instruction send by the base station on the
		TCP connection.
		"""
		while True:
			instructions = self.sender.receive()
			if not instructions == None:
				(event, lat,lon	,radius) = instructions
				print "Received routing instructions ! %r %r %r" % (lat,lon,radius)
				#compute the center:
				radius = float(radius)
				radius = min(radius, 249)
				self.writeFileForPilot(lat,lon,radius)
				self.t = Thread(target=self.reduceSearchArea, args = (''))
				self.t.start()
				
	def writeFileForPilot(self, center_x, center_y, radius, altitude=50):
		"""This is the command that allows to pass a new waypoint to the
		plane's autopilot"""
		command = "/smavnet/gapi_sendcoordinates %.8f %.8f %.8f %.8f" % (float(center_x), float(center_y), altitude, float(radius))
		os.system(command)

	def compute_center_of_mass(self,samples, sort_tuple, map_pwr_func, pwr_thresh, beacon_thresh, beacon_rpt_int):
		"""Compute the geolocalization of every user that the plane is
		aware of
		
		Keyword arguments:
		samples 	-- the list of beacon frames received
				       following the format : (
		sort_tuple 	-- number of the tuple by which the samples should
					  be sorted
		map_pwr_func -- mapping function of the power
		pwr_thresh -- power threshold (min power)
		beacon_thresh -- number of beacon frames considered
		beacon_rpt_int -- unused
		"""
		
		usr = list(set(samples))
		usr.sort(key=lambda tup: tup[sort_tuple], reverse=True)
		usr = GPSUtil.remove_duplicate_GPS(usr, beacon_rpt_int)
		
		allLat = 0
		allLon = 0	 	
		
		pwrs = []		
		for (lat,lon,alt,pwr,mac) in usr[0:min(len(usr),beacon_thresh)]:
			if pwr >= pwr_thresh and lat > 0.0 and lon > 0.0:
				pwr = map_pwr_func(pwr)
				
				###DISABLED IN FLIGHT MODE !
				if not FLIGHT_MODE:
					self.gMapDisplay.addLabel(lat, lon, text="%f %f" % (lat, pwr))
				#############################
				
				pwrs.append(pwr)
				allLat += pwr * lat
				allLon += pwr * lon
				
		if sum(pwrs) == 0:
			return None

		return (allLat / sum(pwrs), allLon / sum(pwrs))

	def localize_user(self, user, pwr_thresh=20, beacon_thresh=15, beacon_rpt_int=5, sort_tuple=3):
		"""Compute the localization of a specific user """
		samples = self.clientsSignalPower[user]
		pwr_func = lambda x : x * 2**math.log(x/10.0)# if x > 30 else x
		return self.compute_center_of_mass(samples=samples, sort_tuple=sort_tuple, map_pwr_func=pwr_func, pwr_thresh=pwr_thresh, beacon_thresh=beacon_thresh, beacon_rpt_int=beacon_rpt_int)
		
	def send_beacon_to_station(self, user, coord, pwr):
		self.sender.send("[beacon]%s\t%s\t%s\t%f" % (user, coord[0], coord[1], pwr))
		print "Sending beacon !"
	
	def send_position_to_station(self, coord, angle):
		self.log.writePlanePosition(self.planeID,coord, angle)
		self.sender.send("[plane]%s\t%s\t%s\t%d" % (self.planeID, coord[0], coord[1], angle))

	def send_localization_to_station(self,user, coord):
		self.log.writeLocalization(user,coord)
		self.sender.send("[user]%s\t%s\t%s" % (user, coord[0], coord[1]), retry=True)
		
	def cleanLogFile(self,log):
		""" It happens that log files generated by the planes
		are somehow corrupted (null bytes, empty lines etc...)
		This method tries to correct the format of this log file
		"""
		clean = []
		with open(log) as tsv:
			for entry in csv.reader(tsv, dialect="excel-tab"):
				if len(entry) == 0:
					continue
				if entry[0] == "[BEACON]":
					if not len(entry) == 7:
						if not len(entry) == 13:
							print "Unrecoverable line in logfile. Skipped..."
						else:
							(event0, ts0,mac0,lat0,lon0,alt0,pwr0MixEvent1,ts1,plane1,lat1,lon1,alt1,angle1) = entry
							pwr0 = float(pwr0MixEvent1.replace("[COORD]",""))
							#print "Invalid line recovered"
							frame0 = (event0,ts0,mac0,lat0,lon0,alt0,pwr0)
							frame1 = ("[COORD]", ts1, plane1, lat1,lon1,alt1,angle1)
							
							clean.append(frame0)
							clean.append(frame1)
					else:
						clean.append(entry)
		return clean
		
	def feedData(self, log, mac_filter):
		"""Load the data from the logs"""
		minPower = 100
		maxPower = 0
		

		for entry in self.cleanLogFile(log):
			if entry[0] == "[BEACON]":
				(event, ts, mac, lat, lon, alt, pwr) = entry
					
				mac = mac[1:-1]
				
				if lat == 0 or lon == 0 or pwr < 0 or not mac in mac_filter:	
					continue
	
				lat = float(lat)
				lon = float(lon)
				alt = float(alt)
				pwr = float(pwr)
				ts = int(ts)
				
				if not mac in self.clientsSignalPower:
					self.clientsSignalPower[mac] = []
				self.clientsSignalPower[mac].append((ts, lat, lon, alt, pwr, mac))
							
				maxPower = max(pwr, maxPower)
				minPower = min(pwr, minPower)
		
	def computeFromLogs(self, log, mac_filter, pwr_thresh=28, beacon_thresh=5, beacon_rpt_int=5, sort_tuple=4, output_file="flight.html"):
		"""Compute the geolocalization from the log files"""
		global app
		self.feedData(log,mac_filter)
		
		###DISABLED IN FLIGHT MODE !
		if not FLIGHT_MODE:
			if app == None:
				app = QtGui.QApplication([])
			self.gMapDisplay = GoogleMapDisplay(46.518550, 6.562460, zoom=18, output_file=output_file)
		############################
		
		lastGPS = None
		
		for user in mac_filter:
			guess = self.localize_user(user, pwr_thresh, beacon_thresh, beacon_rpt_int, sort_tuple)
			refPosition = GPSPosition(mac_filter[user][0], mac_filter[user][1])

			###DISABLED IN FLIGHT MODE !
			if not FLIGHT_MODE:
				self.gMapDisplay.addLabel(guess[0], guess[1], text=user,
						 fontFamily='sans-serif',fontSize=18,
						 fontColor='#00ff00', strokeWeight=8,
						 strokeColor='#00ff00', align='center',
						 marker=True)	
			##################################
	 
			error = GPSUtil.haversine_meter(GPSPosition(guess[0], guess[1]),refPosition)
			#print "Accuracy of %s : %fm." % (user, error)
		
		###DISABLED IN FLIGHT MODE !
		if not FLIGHT_MODE:
			for (lat,lon) in mac_filter.values():
				self.gMapDisplay.addPoint(lat, lon, radius=5, fillOpacity=1.0, fillColor='#000000', strokeColor='#0F000F')
			self.gMapDisplay.drawMap()
		##################################
		
		return error
	
	def main(self):
		if len(sys.argv) == 2:
			computeFromLogs(sys.argv[1])
		elif len(sys.argv) == 4:
			self.planeID = sys.argv[1]
			iface = sys.argv[2]
			self.logfile = sys.argv[3]
			self.log = Log(self.logfile)
			
			#TCP sender for communication with base station
			self.sender = TCPSender()
			self.sender.start()
			
			#Thread responsible for reading GPS coordinates
			self.t = Thread(target=self.readSTDIN, args = ())
			self.t.start()
			
			self.receiver = Thread(target=self.readRoutingInstructions, args = ())
			self.receiver.start()
			
			sniff(iface=iface,prn=self.trackClients,store=0)
		else:
			print "Invalid arguments"
			print "\tUsage live mode : ./PlaneSniffer <planeID> <interface> <logfile>"
			print "\tUsage replay mode : ./PlaneSniffer <logfile>"
		
	def trackClients(self, p):
		"""Listen for probe requests/response in the network"""
		
		#We're only concerned by probe request packets
		#Also, sometime, addr2 is NoneType (don't know why actually)
		#p.type = 0 -> management frame
		if not p.haslayer(Dot11) or p.addr2 is None :
			return
			
		#Ensure that this is a client
		if p.type == 0 and p.subtype in (0,2,4):
			#Signal strength
			#if not p.addr2 == 'c4:88:e5:24:3d:83':
				#return
			sig_str = 100-(256-ord(p.notdecoded[-4:-3]))
			self.send_beacon_to_station(p.addr2, self.coord, sig_str)
			t = Thread(target=self.send_beacon_to_station, args = (p.addr2,self.coord,sig_str))
			t.start()
			self.log.writeBeacon(p.addr2, self.coord, sig_str)
			if not p.addr2 in self.clientsSignalPower:
				self.clientsSignalPower[p.addr2] = []
			self.clientsSignalPower[p.addr2].append((self.log.ts(), self.coord[0], self.coord[1], self.coord[2], sig_str, p.addr2))
			center_of_mass = self.localize_user(p.addr2, pwr_thresh=26, beacon_thresh=26, beacon_rpt_int=5, sort_tuple=3)
			if not center_of_mass == None:
				t = Thread(target=self.send_localization_to_station, args = (p.addr2,center_of_mass))
				t.start()