Merge branch 'master' of /Users/piv/Documents/Work/Test
Merge from work
This commit is contained in:
80
COCO-classes.txt
Normal file
80
COCO-classes.txt
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
person
|
||||||
|
bicycle
|
||||||
|
car
|
||||||
|
motorcycle
|
||||||
|
airplane
|
||||||
|
bus
|
||||||
|
train
|
||||||
|
truck
|
||||||
|
boat
|
||||||
|
traffic light
|
||||||
|
fire hydrant
|
||||||
|
stop sign
|
||||||
|
parking meter
|
||||||
|
bench
|
||||||
|
bird
|
||||||
|
cat
|
||||||
|
dog
|
||||||
|
horse
|
||||||
|
sheep
|
||||||
|
cow
|
||||||
|
elephant
|
||||||
|
bear
|
||||||
|
zebra
|
||||||
|
giraffe
|
||||||
|
backpack
|
||||||
|
umbrella
|
||||||
|
handbag
|
||||||
|
tie
|
||||||
|
suitcase
|
||||||
|
frisbee
|
||||||
|
skis
|
||||||
|
snowboard
|
||||||
|
sports ball
|
||||||
|
kite
|
||||||
|
baseball bat
|
||||||
|
baseball glove
|
||||||
|
skateboard
|
||||||
|
surfboard
|
||||||
|
tennis racket
|
||||||
|
bottle
|
||||||
|
wine glass
|
||||||
|
cup
|
||||||
|
fork
|
||||||
|
knife
|
||||||
|
spoon
|
||||||
|
bowl
|
||||||
|
banana
|
||||||
|
apple
|
||||||
|
sandwich
|
||||||
|
orange
|
||||||
|
broccoli
|
||||||
|
carrot
|
||||||
|
hot dog
|
||||||
|
pizza
|
||||||
|
donut
|
||||||
|
cake
|
||||||
|
chair
|
||||||
|
couch
|
||||||
|
potted plant
|
||||||
|
bed
|
||||||
|
dining table
|
||||||
|
toilet
|
||||||
|
tv
|
||||||
|
laptop
|
||||||
|
mouse
|
||||||
|
remote
|
||||||
|
keyboard
|
||||||
|
cell phone
|
||||||
|
microwave
|
||||||
|
oven
|
||||||
|
toaster
|
||||||
|
sink
|
||||||
|
refrigerator
|
||||||
|
book
|
||||||
|
clock
|
||||||
|
vase
|
||||||
|
scissors
|
||||||
|
teddy bear
|
||||||
|
hair drier
|
||||||
|
toothbrush
|
||||||
45
DecisionSystem/CentralisedDecision/ballotvoter.py
Normal file
45
DecisionSystem/CentralisedDecision/ballotvoter.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import paho.mqtt.client as mqtt
|
||||||
|
import umsgpack
|
||||||
|
|
||||||
|
class BallotVoter:
|
||||||
|
def __init__(self, on_vote):
|
||||||
|
self.client = mqtt.Client()
|
||||||
|
# id is generated automatically.
|
||||||
|
self.client.connect('172.16.13.128')
|
||||||
|
self.on_vote = on_vote
|
||||||
|
|
||||||
|
def on_connect(self, client, userdata, flags, rc):
|
||||||
|
print("Connected with result code " + str(rc))
|
||||||
|
|
||||||
|
self.client.subscribe('swarm1/voters', qos=1)
|
||||||
|
|
||||||
|
# Create the message to send that it is now part of the swarm.
|
||||||
|
|
||||||
|
# Need to set a will as well to broadcast on unexpected disconnection, so commander
|
||||||
|
# knows it is no longer part of the set of voters.
|
||||||
|
# Leaving this until core centralised system is working.
|
||||||
|
#will_message = {"type": "UDisconnect"}
|
||||||
|
|
||||||
|
self.send_connect()
|
||||||
|
|
||||||
|
def on_message(self, client, userdata, message):
|
||||||
|
messageDict = umsgpack.unpackb(message)
|
||||||
|
if "type" in messageDict.keys:
|
||||||
|
# Ok message.
|
||||||
|
if messageDict["type"] == "reqVote":
|
||||||
|
self.submit_vote()
|
||||||
|
if messageDict["type"] == "listening":
|
||||||
|
self.send_connect()
|
||||||
|
else:
|
||||||
|
# Bad message.
|
||||||
|
pass
|
||||||
|
|
||||||
|
def submit_vote(self):
|
||||||
|
binary = umsgpack.packb("type": "vote", "client": self.client._client_id, "vote": self.on_vote())
|
||||||
|
self.client.publish('swarm1/commander', binary)
|
||||||
|
|
||||||
|
def send_connect(self):
|
||||||
|
# Send a connected message to let any commanders know that
|
||||||
|
# it is available.
|
||||||
|
binary = umsgpack.packb({"type": "connect", "id": self.client._client_id})
|
||||||
|
self.client.publish("swarm/commander", binary)
|
||||||
90
DecisionSystem/CentralisedDecision/commander.py
Normal file
90
DecisionSystem/CentralisedDecision/commander.py
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import paho.mqtt.client as mqtt
|
||||||
|
import time
|
||||||
|
import umsgpack
|
||||||
|
|
||||||
|
class Commander:
|
||||||
|
currentVote = None
|
||||||
|
|
||||||
|
# Stores voters that connect to maintain a majority.
|
||||||
|
# Voters who do not vote in latest round are removed.
|
||||||
|
_connectedVoters = []
|
||||||
|
# Dict has format: {clientId: vote}
|
||||||
|
_votes = {}
|
||||||
|
_taking_votes = False
|
||||||
|
|
||||||
|
def __init__(self, timeout = 60):
|
||||||
|
'''
|
||||||
|
Initial/default waiting time is 1 minute for votes to come in.
|
||||||
|
'''
|
||||||
|
self.timeout = timeout
|
||||||
|
|
||||||
|
self.client = mqtt.Client()
|
||||||
|
self.client.connect('172.16.13.128')
|
||||||
|
|
||||||
|
self.client.subscribe("swarm1/commander")
|
||||||
|
# Commander needs a will message too, for the decentralised version, so the
|
||||||
|
# voters know to pick a new commander.
|
||||||
|
# If using apache zookeeper this won't be needed.
|
||||||
|
|
||||||
|
def make_decision(self):
|
||||||
|
# Should change this to follow strategy pattern, for different implementations of
|
||||||
|
# making a decision on the votes.
|
||||||
|
votes = self._votes
|
||||||
|
dif_votes = {}
|
||||||
|
|
||||||
|
for vote in votes:
|
||||||
|
# Get the count of different votes.
|
||||||
|
if str(vote) in dif_votes:
|
||||||
|
dif_votes[str(vote)] = dif_votes[str(vote)] + 1
|
||||||
|
else:
|
||||||
|
dif_votes[str(vote)] = 1
|
||||||
|
|
||||||
|
max_vote = None
|
||||||
|
max_vote_num = 0
|
||||||
|
for vote in dif_votes.keys():
|
||||||
|
if dif_votes[vote] > max_vote_num:
|
||||||
|
max_vote = vote
|
||||||
|
max_vote_num = dif_votes[vote]
|
||||||
|
|
||||||
|
return max_vote
|
||||||
|
|
||||||
|
def get_votes(self):
|
||||||
|
# Should consider abstracting these messages to another class for portability.
|
||||||
|
message = {"type": "reqVote"}
|
||||||
|
message_packed = umsgpack.packb(message)
|
||||||
|
self._taking_votes = True
|
||||||
|
# Publish a message that votes are needed.
|
||||||
|
self.client.publish("swarm1/voters", message_packed)
|
||||||
|
time.sleep(self.timeout)
|
||||||
|
self._taking_votes = False
|
||||||
|
self.make_decision()
|
||||||
|
|
||||||
|
def on_message(self, client, userdata, message):
|
||||||
|
messageDict = umsgpack.unpackb()
|
||||||
|
if "type" in messageDict.keys:
|
||||||
|
# Need to consider that a malicious message may have a type with incorrect subtypes.
|
||||||
|
if messageDict["type"] == "connect":
|
||||||
|
# Voter just connected/reconnnected.
|
||||||
|
if not messageDict["client"] in self._connectedVoters:
|
||||||
|
self._connectedVoters.append(messageDict["client"])
|
||||||
|
elif messageDict["type"] == "vote":
|
||||||
|
# Voter is sending in their vote.
|
||||||
|
if self._taking_votes:
|
||||||
|
# Commander must have requested their taking votes, and the timeout
|
||||||
|
# has not occurred.
|
||||||
|
# Only add vote to list if the client has not already voted.
|
||||||
|
if messageDict["client"] not in self._votes:
|
||||||
|
self._votes[messageDict["client"]] = messageDict["vote"]
|
||||||
|
|
||||||
|
elif messageDict["type"] == "disconnected":
|
||||||
|
self._connectedVoters.remove(messageDict["type"])
|
||||||
|
else:
|
||||||
|
# Not a message we should be using.
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_connect(self, client, userdata, flags, rc):
|
||||||
|
self.client.subscribe("swarm1/commander")
|
||||||
|
|
||||||
|
def get_participants(self):
|
||||||
|
|
||||||
|
self.client.publish("swarm1/voters")
|
||||||
26
DecisionSystem/DecentralisedActivityFusion/voter.py
Normal file
26
DecisionSystem/DecentralisedActivityFusion/voter.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
class Voter:
|
||||||
|
'''
|
||||||
|
This class acts to replicate sensor information with the network to come to a consensus
|
||||||
|
of an activity occurrance. This is based upon research by Song et al. available at:
|
||||||
|
https://ieeexplore.ieee.org/document/5484586
|
||||||
|
|
||||||
|
The main advantage of this approach, as apposed to techniques such as by using zookeeper
|
||||||
|
or consul, is it can be completely decentralised and so works without a central server,
|
||||||
|
or needing to elect a central server. Additionally, it does not require all nodes
|
||||||
|
to run a Zookeeper/Consul server instance, which were not designed for these constrained
|
||||||
|
combat environments, which will fail if half the nodes fail, and also use a lot of resources
|
||||||
|
for handling services not required by this task.
|
||||||
|
|
||||||
|
The original approach in the paper requires some previous training before sensing, so
|
||||||
|
that there is a probability of a given action based upon the previous set of actions.
|
||||||
|
'''
|
||||||
|
def __init__(self, on_vote):
|
||||||
|
'''
|
||||||
|
on_vote: Callback to get the required vote to broadcast.
|
||||||
|
'''
|
||||||
|
self.on_vote = on_vote
|
||||||
|
|
||||||
|
def submit_vote(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def
|
||||||
26
DecisionSystem/PaxosDecision/acceptor.py
Normal file
26
DecisionSystem/PaxosDecision/acceptor.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from proposer import Proposer
|
||||||
|
from paxosmessenger import Messenger
|
||||||
|
|
||||||
|
class Acceptor():
|
||||||
|
highest_proposal = None
|
||||||
|
highest_promise = None
|
||||||
|
messenger = None
|
||||||
|
|
||||||
|
def __init__(self, messenger: Messenger):
|
||||||
|
self.messenger = messenger
|
||||||
|
|
||||||
|
def on_message(self, client, userdata, message):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def accept_request(self, fromt_uid, proposal_id, value):
|
||||||
|
'''
|
||||||
|
Called when an accept message is received from a proposer
|
||||||
|
'''
|
||||||
|
if proposal_id >= self.highest_promise:
|
||||||
|
self.highest_promise = proposal_id
|
||||||
|
self.accepted_id = proposal_id
|
||||||
|
self.accepted_value = value
|
||||||
|
self.messenger.send_accepted(proposal_id, self.accepted_value)
|
||||||
2
DecisionSystem/PaxosDecision/learner.py
Normal file
2
DecisionSystem/PaxosDecision/learner.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
class Learner():
|
||||||
|
pass
|
||||||
42
DecisionSystem/PaxosDecision/mqttmessenger.py
Normal file
42
DecisionSystem/PaxosDecision/mqttmessenger.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
from DecisionSystem.PaxosDecision.paxosmessenger import Messenger
|
||||||
|
from
|
||||||
|
|
||||||
|
class MqttMessenger(Messenger):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
|
||||||
|
def send_prepare(self, proposal_id):
|
||||||
|
'''
|
||||||
|
Broadcasts a Prepare message to all Acceptors
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def send_promise(self, proposer_id, proposal_id, previous_proposal):
|
||||||
|
'''
|
||||||
|
Sends a Promise message to the specified Proposer
|
||||||
|
'''
|
||||||
|
|
||||||
|
NotImplementedError
|
||||||
|
|
||||||
|
def send_accept(self, proposal):
|
||||||
|
'''
|
||||||
|
Broadcasts an Accept message to all Acceptors
|
||||||
|
'''
|
||||||
|
|
||||||
|
NotImplementedError
|
||||||
|
|
||||||
|
def send_accepted(self, proposal):
|
||||||
|
'''
|
||||||
|
Broadcasts an Accepted message to all Learners
|
||||||
|
'''
|
||||||
|
|
||||||
|
NotImplementedError
|
||||||
|
|
||||||
|
def on_resolution(self, proposal_id, value):
|
||||||
|
'''
|
||||||
|
Called when a resolution is reached
|
||||||
|
'''
|
||||||
|
|
||||||
|
NotImplementedError
|
||||||
14
DecisionSystem/PaxosDecision/paxos_instance.py
Normal file
14
DecisionSystem/PaxosDecision/paxos_instance.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
'''
|
||||||
|
@author Michael Pivato
|
||||||
|
|
||||||
|
Much thanks to Tom Cocagne by providing basic paxos code
|
||||||
|
which was the basis of this module and algorithm.
|
||||||
|
Check out the original at: https://github.com/cocagne/paxos/blob/master/paxos/essential.py
|
||||||
|
'''
|
||||||
|
|
||||||
|
from learner import Learner
|
||||||
|
from acceptor import Acceptor
|
||||||
|
from proposer import Proposer
|
||||||
|
|
||||||
|
class PaxosInstance():
|
||||||
|
pass
|
||||||
37
DecisionSystem/PaxosDecision/paxosmessenger.py
Normal file
37
DecisionSystem/PaxosDecision/paxosmessenger.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
from proposal import Proposal
|
||||||
|
|
||||||
|
class Messenger():
|
||||||
|
def send_prepare(self, proposal_id):
|
||||||
|
'''
|
||||||
|
Broadcasts a Prepare message to all Acceptors
|
||||||
|
'''
|
||||||
|
|
||||||
|
NotImplementedError
|
||||||
|
|
||||||
|
def send_promise(self, proposer_id, proposal_id, previous_proposal):
|
||||||
|
'''
|
||||||
|
Sends a Promise message to the specified Proposer
|
||||||
|
'''
|
||||||
|
|
||||||
|
NotImplementedError
|
||||||
|
|
||||||
|
def send_accept(self, proposal):
|
||||||
|
'''
|
||||||
|
Broadcasts an Accept message to all Acceptors
|
||||||
|
'''
|
||||||
|
|
||||||
|
NotImplementedError
|
||||||
|
|
||||||
|
def send_accepted(self, proposal):
|
||||||
|
'''
|
||||||
|
Broadcasts an Accepted message to all Learners
|
||||||
|
'''
|
||||||
|
|
||||||
|
NotImplementedError
|
||||||
|
|
||||||
|
def on_resolution(self, proposal_id, value):
|
||||||
|
'''
|
||||||
|
Called when a resolution is reached
|
||||||
|
'''
|
||||||
|
|
||||||
|
NotImplementedError
|
||||||
32
DecisionSystem/PaxosDecision/proposal.py
Normal file
32
DecisionSystem/PaxosDecision/proposal.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from Messaging.messaginginterface import Message
|
||||||
|
import umsgpack
|
||||||
|
|
||||||
|
# Uses MessagePack for message transfer.
|
||||||
|
|
||||||
|
class Proposal(Message):
|
||||||
|
ballot_number = None
|
||||||
|
vote = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def serialise(self) -> str:
|
||||||
|
return umsgpack.packb({"ballot": self.ballot_number, "vote": self.vote})
|
||||||
|
|
||||||
|
def deserialise(self, binary: bytearray):
|
||||||
|
'''
|
||||||
|
Deserialises a given proposal message into a proposal object.
|
||||||
|
'''
|
||||||
|
obj = umsgpack.unpackb(binary)
|
||||||
|
old_ballot = self.ballot_number
|
||||||
|
old_vote = self.vote
|
||||||
|
try:
|
||||||
|
self.ballot_number = obj['ballot']
|
||||||
|
self.vote = obj['vote']
|
||||||
|
except:
|
||||||
|
# Reset the values in case they have been changed.
|
||||||
|
self.ballot_number = old_ballot
|
||||||
|
self.vote = old_vote
|
||||||
|
print("Error: binary object is not a proposal")
|
||||||
|
|
||||||
|
|
||||||
3
DecisionSystem/PaxosDecision/proposer.py
Normal file
3
DecisionSystem/PaxosDecision/proposer.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
class Proposer():
|
||||||
|
def propose(self):
|
||||||
|
pass
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import Messaging.mqttsession as ms
|
|
||||||
import time
|
|
||||||
import umsgpack
|
|
||||||
|
|
||||||
class Commander:
|
|
||||||
|
|
||||||
def __init__(self, timeout = 60):
|
|
||||||
self.timeout = timeout
|
|
||||||
self._votes = []
|
|
||||||
ms.Client()
|
|
||||||
|
|
||||||
def on_message(client, userdata, message):
|
|
||||||
self._votes.append(umsgpack.unpackb(message.payload))
|
|
||||||
|
|
||||||
ms.client.subscribe("FakeSwarm/FirstTest", on_message)
|
|
||||||
|
|
||||||
ms.client.loop_start()
|
|
||||||
|
|
||||||
def make_decision(self):
|
|
||||||
votes = self._votes
|
|
||||||
|
|
||||||
for vote in votes:
|
|
||||||
continue
|
|
||||||
|
|
||||||
def get_votes(self, topic, message, qos=0):
|
|
||||||
# Publish a message that votes are needed.
|
|
||||||
ms.client.publish(topic, message, qos)
|
|
||||||
time.sleep(self.timeout)
|
|
||||||
self.make_decision()
|
|
||||||
|
|
||||||
def add_subscription(self, topic, callback=None, qos=0):
|
|
||||||
ms.client.subscribe(topic)
|
|
||||||
|
|
||||||
if callback is not None:
|
|
||||||
ms.client.message_callback_add(topic, callback)
|
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
from Messaging.packmessage import PackMessage
|
from Messaging.packmessage import PackMessage
|
||||||
|
|
||||||
class Vote(PackMessage):
|
class Vote(PackMessage):
|
||||||
def __init__(self, vote = None):
|
def __init__(self, client, vote = None):
|
||||||
self._vote = vote
|
self._vote = vote
|
||||||
|
self._client = client
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def vote(self):
|
def vote(self):
|
||||||
|
|||||||
@@ -2,12 +2,8 @@ from Messaging.packmessage import PackMessage
|
|||||||
import umsgpack
|
import umsgpack
|
||||||
|
|
||||||
class Voter:
|
class Voter:
|
||||||
def __init__(self):
|
def submit_vote(self):
|
||||||
# self._client =
|
|
||||||
pass
|
|
||||||
|
|
||||||
def submit_vote(self, vote_contents):
|
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def request_vote(self):
|
def send_connected(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
@@ -1,11 +1,28 @@
|
|||||||
import paho.mqtt.client as mqtt
|
import paho.mqtt.client as mqtt
|
||||||
|
|
||||||
|
"""
|
||||||
|
Wrapper module for paho mqtt library, providing a singleton instance of the client to be used.
|
||||||
|
Also adds some convenience functions such as having multiple connected callbacks,
|
||||||
|
and managing whether the client is still connected.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
client = mqtt.Client()
|
client = mqtt.Client()
|
||||||
host = None
|
host = None
|
||||||
|
|
||||||
"""
|
connect_callbacks = []
|
||||||
Wrapper module for paho mqtt library, providing a singleton instance of the client to be used.
|
disconnect_callbacks = []
|
||||||
"""
|
|
||||||
|
def on_connect(client, userdata, flags, rc):
|
||||||
|
print("Connected with result code " + str(rc))
|
||||||
|
if rc == 0:
|
||||||
|
global connected
|
||||||
|
connected = True
|
||||||
|
|
||||||
|
for callback in connect_callbacks:
|
||||||
|
callback()
|
||||||
|
|
||||||
|
client.subscribe('hello/test', qos=1)
|
||||||
|
|
||||||
# Arguably not needed, just want to make the client static, but here anyway.
|
# Arguably not needed, just want to make the client static, but here anyway.
|
||||||
def connect():
|
def connect():
|
||||||
@@ -16,6 +33,14 @@ def connect():
|
|||||||
client.connect(host, port=1883, keepalive=60, bind_address="")
|
client.connect(host, port=1883, keepalive=60, bind_address="")
|
||||||
client.loop_start()
|
client.loop_start()
|
||||||
|
|
||||||
|
def add_connect_callback(callback):
|
||||||
|
global connect_callbacks
|
||||||
|
connect_callbacks += callback
|
||||||
|
connectted = True
|
||||||
|
|
||||||
|
def add_disconnect_callback(callback):
|
||||||
|
global
|
||||||
|
|
||||||
def disconnect():
|
def disconnect():
|
||||||
global client
|
global client
|
||||||
if client is not None:
|
if client is not None:
|
||||||
@@ -24,6 +49,13 @@ def disconnect():
|
|||||||
else:
|
else:
|
||||||
print("Error: Client is not initialised.")
|
print("Error: Client is not initialised.")
|
||||||
|
|
||||||
|
def on_disconnect(client, userdata, rc):
|
||||||
|
if rc != 0:
|
||||||
|
print("Unexpected disconnection.")
|
||||||
|
|
||||||
|
global connected
|
||||||
|
connected = False
|
||||||
|
|
||||||
def Client():
|
def Client():
|
||||||
global client
|
global client
|
||||||
if client is None:
|
if client is None:
|
||||||
|
|||||||
Reference in New Issue
Block a user