Add 'car/' from commit 'eee0e8dc445691e600680f4abc77f2814b20b054'
git-subtree-dir: car git-subtree-mainline:1d29a5526cgit-subtree-split:eee0e8dc44
This commit is contained in:
0
car/DecisionSystem/CentralisedDecision/__init__.py
Normal file
0
car/DecisionSystem/CentralisedDecision/__init__.py
Normal file
51
car/DecisionSystem/CentralisedDecision/ballotvoter.py
Normal file
51
car/DecisionSystem/CentralisedDecision/ballotvoter.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import json
|
||||
from DecisionSystem.messages import ConnectSwarm, SubmitVote, Message, deserialise, RequestVote, ClientVoteRequest, VoteResult
|
||||
from multiprocessing import Pool
|
||||
from messenger import Messenger
|
||||
|
||||
class BallotVoter:
|
||||
def __init__(self, on_vote, handle_agreement, messenger: Messenger):
|
||||
self.messenger = messenger
|
||||
self.messenger.add_message_callback(self.on_message)
|
||||
self.messenger.add_connect(self.on_connect)
|
||||
self.on_vote = on_vote
|
||||
self.handle_agreement = handle_agreement
|
||||
|
||||
def on_connect(self, rc):
|
||||
print("Connected with result code " + str(rc))
|
||||
|
||||
# Tell commander we are now connected.
|
||||
self.send_connect()
|
||||
|
||||
def on_message(self, message):
|
||||
print("Message Received!")
|
||||
messageD = deserialise(message.payload)
|
||||
print("Message Type: " + messageD.type)
|
||||
# Ok message.
|
||||
if messageD.type == RequestVote().type:
|
||||
print('Received vote message')
|
||||
self.submit_vote()
|
||||
elif messageD.type == "listening":
|
||||
self.send_connect()
|
||||
elif messageD.type == VoteResult.type:
|
||||
self.handle_agreement(messageD.data["vote"])
|
||||
|
||||
def submit_vote(self):
|
||||
v = self.on_vote()
|
||||
if v == None:
|
||||
print('Could not get vote')
|
||||
return
|
||||
print("Got Vote")
|
||||
vote = SubmitVote(v, self.messenger.id)
|
||||
print('Created Vote Message')
|
||||
self.messenger.broadcast_message(self.messenger.swarm, vote.serialise())
|
||||
print('published vote')
|
||||
|
||||
def send_connect(self):
|
||||
# Send a connected message to let any commanders know that
|
||||
# it is available.
|
||||
self.messenger.broadcast_message(self.messenger.swarm, ConnectSwarm(self.messenger.id).serialise())
|
||||
|
||||
def request_vote(self):
|
||||
"""Sends a request to the leader to start collecting votes."""
|
||||
self.messenger.broadcast_message(self.messenger.swarm, ClientVoteRequest(self.messenger.id).serialise())
|
||||
95
car/DecisionSystem/CentralisedDecision/cameraserver.py
Normal file
95
car/DecisionSystem/CentralisedDecision/cameraserver.py
Normal file
@@ -0,0 +1,95 @@
|
||||
from DecisionSystem.CentralisedDecision.ballotvoter import BallotVoter
|
||||
from DecisionSystem.CentralisedDecision.messenger import MqttMessenger
|
||||
import numpy as np
|
||||
import cv2
|
||||
import time
|
||||
import argparse
|
||||
import os.path
|
||||
import sys
|
||||
from GestureRecognition.simplehandrecogniser import SimpleHandRecogniser
|
||||
from threading import Thread
|
||||
from queue import Queue
|
||||
|
||||
import MyRaft.node as raft
|
||||
import MyRaft.leader as leader
|
||||
import DecisionSystem.CentralisedDecision.commander as commander
|
||||
import DecisionSystem.CentralisedDecision.messenger as messenger
|
||||
import DecisionSystem.CentralisedDecision.ballotvoter as voter
|
||||
|
||||
print("Parsing args")
|
||||
parser = argparse.ArgumentParser(description="Runs a file with OpenCV and gets consensus from the swarm.")
|
||||
|
||||
parser.add_argument('-V', '--video', help="Path to video file.")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
recogniser = SimpleHandRecogniser(None)
|
||||
|
||||
# Checks if video file is specified and if that file exists.
|
||||
if(args.video):
|
||||
print('finding video')
|
||||
if not os.path.isfile(args.video):
|
||||
print("Input video file ", args.video, " doesn't exist")
|
||||
sys.exit(1)
|
||||
else:
|
||||
# Exit if no video file specified - we aren't using webcam here.
|
||||
sys.exit(1)
|
||||
|
||||
def on_vote():
|
||||
# Get the current frame of the camera and process what hand
|
||||
# is currently being seen.
|
||||
print('getting frame')
|
||||
# Need to copy rather than just take a reference, as frame will
|
||||
# constantly be changing.
|
||||
global vd
|
||||
recogniser.set_frame(np.copy(vd.frame))
|
||||
print('Got frame, voting with recogniser')
|
||||
return recogniser.get_gesture()
|
||||
|
||||
def connect_to_broker(mqtt):
|
||||
print("Connecting to broker")
|
||||
max_collisions = 100
|
||||
collisions = 1
|
||||
while not mqtt.connect() and collisions <= max_collisions:
|
||||
time.sleep(2 ** collisions - 1)
|
||||
print("Reconnecting in %s" %(2 ** collisions - 1))
|
||||
collisions += 1
|
||||
|
||||
mqtt = MqttMessenger()
|
||||
v = BallotVoter(on_vote, mqtt)
|
||||
|
||||
def on_disconnect(rc):
|
||||
print("Client disconnected from broker")
|
||||
i = input("Would you like to reconnnect? (y|n)")
|
||||
if i == 'y':
|
||||
global mqtt
|
||||
connect_to_broker(mqtt)
|
||||
|
||||
mqtt.add_disconnect_callback(on_disconnect)
|
||||
connect_to_broker(mqtt)
|
||||
|
||||
# Start the video capture at the next whole minute.
|
||||
current_time_sec = time.gmtime(time.time()).tm_sec
|
||||
if current_time_sec < 40:
|
||||
time.sleep(60 - current_time_sec)
|
||||
else:
|
||||
time.sleep(60 - current_time_sec + 60)
|
||||
print('loading video')
|
||||
|
||||
|
||||
|
||||
print('Press q to quit the server, g to get votes/consensus')
|
||||
|
||||
while True:
|
||||
if vd.frame is None:
|
||||
continue
|
||||
frame = np.copy(vd.frame)
|
||||
cv2.imshow('Frame', frame)
|
||||
k = cv2.waitKey(33)
|
||||
if k == ord('q'):
|
||||
break
|
||||
elif k == -1:
|
||||
continue
|
||||
elif k == ord('g'):
|
||||
# Get votes
|
||||
pass
|
||||
15
car/DecisionSystem/CentralisedDecision/central_server.py
Normal file
15
car/DecisionSystem/CentralisedDecision/central_server.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from DecisionSystem.CentralisedDecision import commander
|
||||
from DecisionSystem.CentralisedDecision.messenger import MqttMessenger
|
||||
|
||||
mqtt = MqttMessenger()
|
||||
c = commander.Commander(mqtt, 10)
|
||||
mqtt.connect()
|
||||
|
||||
f = input("Press any key and enter other than q to get current observation of the swarm: ")
|
||||
|
||||
while f != "q":
|
||||
print("Vote is: ")
|
||||
print(c.get_votes())
|
||||
f = input("Press any key and enter other than q to get current observation of the swarm: ")
|
||||
|
||||
print("Thanks for trying!")
|
||||
106
car/DecisionSystem/CentralisedDecision/centralisedinstance.py
Normal file
106
car/DecisionSystem/CentralisedDecision/centralisedinstance.py
Normal file
@@ -0,0 +1,106 @@
|
||||
"""This module provides an instance of the centralised, distributed voter"""
|
||||
|
||||
from queue import Queue
|
||||
import json
|
||||
import argparse
|
||||
|
||||
import numpy as np
|
||||
import cv2
|
||||
|
||||
import MyRaft.node as raft
|
||||
import MyRaft.leader as leader
|
||||
import DecisionSystem.CentralisedDecision.commander as commander
|
||||
import DecisionSystem.CentralisedDecision.messenger as messenger
|
||||
import DecisionSystem.CentralisedDecision.ballotvoter as voter
|
||||
import DecisionSystem.CentralisedDecision.videoget as videoget
|
||||
import GestureRecognition.simplehandrecogniser as shr
|
||||
import GestureRecognition.starkaleid as sk
|
||||
|
||||
class Instance:
|
||||
"""An instance of the centralised, distributed approach to voting.
|
||||
"""
|
||||
def __init__(self, node_config='config.json', video_file=0):
|
||||
with open(node_config) as f:
|
||||
self.cfg= json.load(f)
|
||||
self.mqtt = messenger.MqttMessenger(self.cfg)
|
||||
self.we_lead = False
|
||||
self.node = raft.RaftGrpcNode(node_config)
|
||||
print("Node initialised")
|
||||
self.node.add_state_change(self.on_state_changed)
|
||||
|
||||
self.voter = voter.BallotVoter(self.on_vote, self.handle_agreement, self.mqtt)
|
||||
self.commander = commander.Commander(self.mqtt)
|
||||
self.recogniser = shr.SimpleHandRecogniser(None)
|
||||
|
||||
self.last_vote = -1
|
||||
|
||||
self.q = Queue(5)
|
||||
self.frame = None
|
||||
self.vd = videoget.VideoGet(self.q, video_file)
|
||||
|
||||
self.kaleid = False
|
||||
print("Initialised the instance")
|
||||
|
||||
def on_state_changed(self):
|
||||
"""Callback method for state of the raft node changing"""
|
||||
if isinstance(self.node._current_state, leader.Leader):
|
||||
# We are now the commander (or leader)
|
||||
self.commander = commander.Commander(self.mqtt)
|
||||
else:
|
||||
# No longer or never were a leader.
|
||||
try:
|
||||
del(self.commander)
|
||||
except SyntaxError:
|
||||
pass
|
||||
|
||||
def start(self):
|
||||
self.vd.start()
|
||||
self.mqtt.connect()
|
||||
go = True
|
||||
while go:
|
||||
if self.kaleid:
|
||||
go = self.show_kaleidoscope
|
||||
else:
|
||||
go = self.show_normal
|
||||
|
||||
def show_normal(self):
|
||||
self.frame = np.copy(self.q.get())
|
||||
cv2.imshow('Frame', self.frame)
|
||||
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||
return False
|
||||
elif cv2.waitKey(1) & 0xFF == ord('g'):
|
||||
self.voter.request_vote()
|
||||
|
||||
def show_kaleidoscope(self):
|
||||
self.frame = sk.make_kaleidoscope(np.copy(self.q.get()), 12)
|
||||
cv2.imshow('Frame', self.frame)
|
||||
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||
return False
|
||||
elif cv2.waitKey(1) & 0xFF == ord('g'):
|
||||
self.voter.request_vote()
|
||||
|
||||
def on_vote(self):
|
||||
# Get the current frame of the camera and process what hand
|
||||
# is currently being seen.
|
||||
print('getting frame')
|
||||
# Need to copy rather than just take a reference, as frame will
|
||||
# constantly be changing.
|
||||
self.recogniser.set_frame(np.copy(self.frame))
|
||||
print('Got frame, voting with recogniser')
|
||||
gesture = self.recogniser.get_gesture()
|
||||
self.last_vote = gesture
|
||||
return gesture
|
||||
|
||||
def handle_agreement(self, vote):
|
||||
if vote == 5:
|
||||
self.kaleid = True
|
||||
else:
|
||||
self.kaleid = False
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(description="An instance of CAIDE")
|
||||
|
||||
if __name__ == "__main__":
|
||||
instance = Instance(video_file="/Users/piv/Documents/Projects/Experiments/Camera1/video.mp4")
|
||||
instance.start()
|
||||
|
||||
119
car/DecisionSystem/CentralisedDecision/commander.py
Normal file
119
car/DecisionSystem/CentralisedDecision/commander.py
Normal file
@@ -0,0 +1,119 @@
|
||||
import time
|
||||
from DecisionSystem.messages import Message, CommanderWill, RequestVote, GetSwarmParticipants, deserialise, ClientVoteRequest, VoteResult
|
||||
import json
|
||||
import numpy as np
|
||||
|
||||
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, messenger, timeout = 60):
|
||||
'''
|
||||
Initial/default waiting time is 1 minute for votes to come in.
|
||||
'''
|
||||
self.timeout = timeout
|
||||
|
||||
self._messenger = messenger
|
||||
self._messenger.add_connect(self.on_connect)
|
||||
self._messenger.add_message_callback(self.on_message)
|
||||
self._messenger.add_disconnect_callback(self.on_disconnect)
|
||||
print('Connecting')
|
||||
|
||||
def make_decision(self):
|
||||
# Should change this to follow strategy pattern, for different implementations of
|
||||
# making a decision on the votes.
|
||||
print("Making a decision")
|
||||
votes = self._votes.values()
|
||||
print(type(votes))
|
||||
dif_votes = {}
|
||||
|
||||
for vote in votes:
|
||||
# Get the count of different votes.
|
||||
if vote in dif_votes:
|
||||
dif_votes[vote] = dif_votes[vote] + 1
|
||||
else:
|
||||
dif_votes[vote] = 1
|
||||
|
||||
max_vote = ""
|
||||
max_vote_num = 0
|
||||
# Should try using a numpy array for this.
|
||||
|
||||
for vote in dif_votes.keys():
|
||||
if dif_votes[vote] > max_vote_num:
|
||||
max_vote = vote
|
||||
max_vote_num = dif_votes[vote]
|
||||
|
||||
print("Made Decision!")
|
||||
return max_vote
|
||||
|
||||
def get_votes(self):
|
||||
# Should abstract messaging to another class.
|
||||
print("Gathering Votes")
|
||||
self._taking_votes = True
|
||||
# Publish a message that votes are needed.
|
||||
print("Sending request message")
|
||||
self._messenger.broadcast_message(self._messenger.swarm, RequestVote(self._messenger.id).serialise())
|
||||
print("published message")
|
||||
time.sleep(self.timeout)
|
||||
self._taking_votes = False
|
||||
# TODO: Work out how to broadcast votes back to the swarm, maybe using raft?
|
||||
return self.make_decision()
|
||||
|
||||
def on_message(self, message):
|
||||
print("Message Received")
|
||||
messageD = None
|
||||
try:
|
||||
messageD = deserialise(message.payload)
|
||||
except:
|
||||
print("Incorrect Message Has Been Sent")
|
||||
return
|
||||
|
||||
# Need to consider that a malicious message may have a type with incorrect subtypes.
|
||||
if messageD.type == "connect":
|
||||
print("Voter connected!")
|
||||
# Voter just connected/reconnnected.
|
||||
if not messageD["client"] in self._connectedVoters:
|
||||
self._connectedVoters.append(messageD["client"])
|
||||
elif messageD.type == "vote":
|
||||
print("Received a vote!")
|
||||
# Voter is sending in their vote.
|
||||
print(messageD.data["vote"])
|
||||
print("From: ", messageD.sender)
|
||||
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 messageD.sender not in self._votes:
|
||||
self._votes[messageD.sender] = int(messageD.data["vote"])
|
||||
elif messageD.type == ClientVoteRequest().type:
|
||||
# received a request to get votes/consensus.
|
||||
self.get_votes()
|
||||
|
||||
elif messageD.type == "disconnected":
|
||||
print("Voter disconnected :(")
|
||||
self._connectedVoters.remove(messageD.sender)
|
||||
|
||||
def on_connect(self, rc):
|
||||
# Subscribes now handled by the mqtt messenger, this is just here
|
||||
# for convenience later.
|
||||
pass
|
||||
|
||||
def get_participants(self):
|
||||
self._messenger.broadcast_message(self._messenger.swarm, GetSwarmParticipants().serialise())
|
||||
# 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.
|
||||
# That's the wrong method for setting a will.
|
||||
# self.client.publish("swarm1/voters", CommanderWill(self.client._client_id).serialise())
|
||||
|
||||
def on_disconnect(self, rc):
|
||||
pass
|
||||
|
||||
def propogate_result(self, result):
|
||||
self._messenger.broadcast_message(self._messenger.swarm, )
|
||||
138
car/DecisionSystem/CentralisedDecision/messenger.py
Normal file
138
car/DecisionSystem/CentralisedDecision/messenger.py
Normal file
@@ -0,0 +1,138 @@
|
||||
import paho.mqtt.client as mqtt
|
||||
import json
|
||||
import random
|
||||
|
||||
class Messenger:
|
||||
_connect_callbacks = []
|
||||
_disconnect_callbacks = []
|
||||
_message_callbacks = []
|
||||
|
||||
def broadcast_message(self, message):
|
||||
"""
|
||||
Broadcasts the specified message to the swarm based upon its topic(or group).
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def unicast_message(self, target, message):
|
||||
"""
|
||||
Broadcasts the specified message to the single target.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def connect(self):
|
||||
"""
|
||||
Connect to the swarm.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def disconnect(self):
|
||||
"""
|
||||
Disconnect from the swarm.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def add_connect(self, connect):
|
||||
"""
|
||||
Adds a callback to do something else once we are connected.
|
||||
"""
|
||||
self._connect_callbacks.append(connect)
|
||||
|
||||
def on_connect(self, code = None):
|
||||
"""
|
||||
Called once the messenger connects to the swarm.
|
||||
"""
|
||||
for cb in self._connect_callbacks:
|
||||
cb(code)
|
||||
|
||||
def on_disconnect(self, code = None):
|
||||
"""
|
||||
Called when the messenger is disconnected from the swarm.
|
||||
"""
|
||||
for cb in self._disconnect_callbacks:
|
||||
cb(code)
|
||||
|
||||
def add_disconnect_callback(self, on_disconnect):
|
||||
"""
|
||||
Adds a callback for when the messenger is disconnected.
|
||||
"""
|
||||
self._disconnect_callbacks.append(on_disconnect)
|
||||
|
||||
def add_message_callback(self, on_message):
|
||||
"""
|
||||
Adds a callback
|
||||
"""
|
||||
self._message_callbacks.append(on_message)
|
||||
|
||||
def on_message(self, message):
|
||||
"""
|
||||
Called when the messenger receives a message.
|
||||
"""
|
||||
for cb in self._message_callbacks:
|
||||
cb(message)
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
"""
|
||||
The id for this messenger that is being used in communication.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def swarm(self):
|
||||
"""
|
||||
Gets the name of the swarm this instance is a part of.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class MqttMessenger(Messenger):
|
||||
"""A messenger that uses MQTT."""
|
||||
def __init__(self, configuration):
|
||||
self._cfg = configuration
|
||||
self._client = mqtt.Client(client_id=str(random.randint(0,500)))
|
||||
self._client.on_connect = self.on_connect
|
||||
self._client.on_message = self.on_message
|
||||
self._client.on_disconnect = self.on_disconnect
|
||||
|
||||
def on_message(self, client, userdata, message):
|
||||
Messenger.on_message(self, message)
|
||||
|
||||
def on_connect(self, client, userdata, flags, rc):
|
||||
# Subscribe to the swarm specified in the config.
|
||||
self._client.subscribe(self._cfg['mqtt']['swarm'])
|
||||
|
||||
# Also subscribe to our own topic for unicast messages.
|
||||
self._client.subscribe(self._cfg['mqtt']['swarm'] + str(self._client._client_id))
|
||||
Messenger.on_connect(self, rc)
|
||||
|
||||
def on_disconnect(self, client, userdata, rc):
|
||||
Messenger.on_disconnect(self, rc)
|
||||
|
||||
def broadcast_message(self, message):
|
||||
self._client.publish(self._cfg['mqtt']['swarm'], message, qos=1)
|
||||
|
||||
def unicast_message(self, target, message):
|
||||
self._client.publish(target, message, qos=1)
|
||||
|
||||
def connect(self):
|
||||
try:
|
||||
self._client.connect(self._cfg['mqtt']['host'], \
|
||||
int(self._cfg['mqtt']['port']), \
|
||||
int(self._cfg['mqtt']['timeout']))
|
||||
except:
|
||||
print("Could not connect to broker")
|
||||
return False
|
||||
|
||||
self._client.loop_start()
|
||||
return True
|
||||
|
||||
def disconnect(self):
|
||||
self._client.disconnect()
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self._client._client_id
|
||||
|
||||
@property
|
||||
def swarm(self):
|
||||
return self._cfg['mqtt']['swarm']
|
||||
45
car/DecisionSystem/CentralisedDecision/videoget.py
Normal file
45
car/DecisionSystem/CentralisedDecision/videoget.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import numpy as np
|
||||
import cv2
|
||||
from threading import Thread
|
||||
from queue import Queue
|
||||
import time
|
||||
|
||||
class VideoGet:
|
||||
'''
|
||||
Code taken from Najam R Syed, available here:
|
||||
https://github.com/nrsyed/computer-vision/tree/master/multithread
|
||||
'''
|
||||
def __init__(self, q, src):
|
||||
'''
|
||||
Must provide a source so we don't accidently start camera at work.
|
||||
'''
|
||||
self._stream = cv2.VideoCapture(src)
|
||||
(self.grabbed, self.frame) = self._stream.read()
|
||||
self.stopped = False
|
||||
self.q = q
|
||||
self.q.put(np.copy(self.frame))
|
||||
self.src = src
|
||||
|
||||
def start(self):
|
||||
Thread(target=self.get, args=()).start()
|
||||
return self
|
||||
|
||||
def get(self):
|
||||
while not self.stopped:
|
||||
if not self.grabbed:
|
||||
# self.stopped = True
|
||||
print('frame not grabbed')
|
||||
self._stream.release()
|
||||
self._stream = cv2.VideoCapture(self.src)
|
||||
# time.sleep(2)
|
||||
self.grabbed, self.frame = self._stream.read()
|
||||
else:
|
||||
(self.grabbed, self.frame) = self._stream.read()
|
||||
if self.q.full():
|
||||
self.q.get()
|
||||
self.q.put(np.copy(self.frame))
|
||||
time.sleep(0.03) # Approximately 30fps
|
||||
# Start a new feed.
|
||||
|
||||
def stop(self):
|
||||
self.stopped = True
|
||||
128
car/DecisionSystem/DecentralisedActivityFusion/voter.py
Normal file
128
car/DecisionSystem/DecentralisedActivityFusion/voter.py
Normal file
@@ -0,0 +1,128 @@
|
||||
import paho.mqtt.client as mqtt
|
||||
import time
|
||||
import json
|
||||
import umsgpack
|
||||
import numpy as np
|
||||
|
||||
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.
|
||||
'''
|
||||
_votes = {}
|
||||
_connected_voters = []
|
||||
_taking_votes = False
|
||||
|
||||
def __init__(self, on_vote, swarm_name):
|
||||
'''
|
||||
on_vote: Callback to get the required vote to broadcast.
|
||||
'''
|
||||
# Load config file
|
||||
cfg = None
|
||||
with open('config.json') as json_config:
|
||||
cfg = json.load(json_config)
|
||||
self._cfg = cfg
|
||||
self.on_vote = on_vote
|
||||
self._swarm = swarm_name
|
||||
self._client = mqtt.Client()
|
||||
self._client.on_message = self.on_message
|
||||
self._client.on_connect = self.on_connect
|
||||
self._client.connect(cfg["mqtt"]["host"], cfg["mqtt"]["port"], cfg["mqtt"]["timeout"])
|
||||
self._client.loop_start()
|
||||
|
||||
def submit_vote(self):
|
||||
# Publish to swarm where all other voters will receive a vote.
|
||||
self._client.publish(self._swarm, self.collect_vote)
|
||||
self._taking_votes = True
|
||||
time.sleep(self._cfg["mqtt"]["timeout"])
|
||||
self._taking_votes = False
|
||||
# Wait a certain amount of time for responses, then fuse the information.
|
||||
self.fuse_algorithm()
|
||||
|
||||
# Need the error and number of timestamps since voting started to finalise the consensus.
|
||||
|
||||
def fuse_algorithm(self):
|
||||
# First calculate vi -> the actual vote that is taken
|
||||
# (Or the probability that the observation is a label for each)
|
||||
# We're just going to be doing 1 for the detected and 0 for all others.
|
||||
# vi is for each hand (action in paper), but we're just going to do a single
|
||||
# hand for our purposes. Will be able to use the CNN for all hands/gestures if we want to.
|
||||
vi = np.zeros(6,1)
|
||||
# Set correct vi.
|
||||
vote = self.on_vote()
|
||||
vi[vote] = 1
|
||||
# Now send this off to the other nodes. Potentially using gossip...
|
||||
|
||||
# Set diagonal of ANDvi to elements of vi.
|
||||
# This should actually be ANDvj, as it is for each observation received.
|
||||
ANDvi = np.diag(vi.flatten())
|
||||
|
||||
# Nee
|
||||
|
||||
# M is the probability of going from one state to the next, which
|
||||
# is assumed to be uniform for our situation - someone is just as likely
|
||||
# to raise 5 fingers from two or any other.
|
||||
# And so a 6x6 matrix is generated with all same probability to show this.
|
||||
# Remember they could be holding up no fingers...
|
||||
# m = np.full((6,6), 0.2)
|
||||
|
||||
# Y1T = np.full((6,1),1)
|
||||
|
||||
# Compute consensus state estimate by taking difference between our observations
|
||||
# and all others individually.
|
||||
|
||||
# Moving to an approach that does not require the previous
|
||||
# timestep (or so much math...)
|
||||
# First take other information and fuse, using algorithm
|
||||
# as appropriate.
|
||||
pass
|
||||
|
||||
def custom_fuse(self):
|
||||
vi = np.zeros(6,1)
|
||||
# Set correct vi.
|
||||
vote = self.on_vote()
|
||||
vi[vote] = 1
|
||||
|
||||
|
||||
def on_message(self, client, userdata, message):
|
||||
try:
|
||||
message_dict = umsgpack.unpackb(message.payload)
|
||||
except:
|
||||
print("Incorrect message received")
|
||||
return
|
||||
|
||||
if message_dict["type"] == "vote":
|
||||
# received a vote
|
||||
if self._taking_votes:
|
||||
self._votes[message_dict["client"]] = message_dict["vote"]
|
||||
|
||||
elif message_dict["type"] == "connect":
|
||||
# voter connected to the swarm
|
||||
self._connected_voters.append(message_dict["client"])
|
||||
|
||||
elif message_dict["type"] == "disconnect":
|
||||
# Sent as the voter's will message
|
||||
self._connected_voters.remove(message_dict["client"])
|
||||
|
||||
def on_connect(self, client, userdata, flags, rc):
|
||||
print("Connected with result code " + str(rc))
|
||||
self._client.subscribe(self._swarm)
|
||||
|
||||
def collect_vote(self):
|
||||
vote_message = umsgpack.packb({"type": "vote",
|
||||
"client":self._client._client_id, "vote": self.on_vote()})
|
||||
return vote_message
|
||||
|
||||
def start_vote(self):
|
||||
pass
|
||||
0
car/DecisionSystem/__init__.py
Normal file
0
car/DecisionSystem/__init__.py
Normal file
101
car/DecisionSystem/messages.py
Normal file
101
car/DecisionSystem/messages.py
Normal file
@@ -0,0 +1,101 @@
|
||||
import umsgpack
|
||||
import uuid
|
||||
|
||||
class Message:
|
||||
_type = None
|
||||
def __init__(self, sender = "", data = {}):
|
||||
self._sender = sender
|
||||
self._data = data
|
||||
|
||||
@property
|
||||
def sender(self):
|
||||
return self._sender
|
||||
|
||||
@sender.setter
|
||||
def sender(self, value):
|
||||
self._sender = value
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self._data
|
||||
|
||||
# I love using keywords...
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
@type.setter
|
||||
def type(self, value):
|
||||
self._type = value
|
||||
|
||||
def serialise(self):
|
||||
return umsgpack.packb({"type":self.type, "sender": self.sender, "data": self.data})
|
||||
|
||||
# SHould make this static in Message class.
|
||||
def deserialise(obj):
|
||||
"""
|
||||
Deserialises a given messagepack object into a Message.
|
||||
"""
|
||||
m = Message()
|
||||
unpacked = umsgpack.unpackb(obj)
|
||||
print('Unpacked Object')
|
||||
print(unpacked)
|
||||
m.type = unpacked["type"]
|
||||
m._sender = unpacked["sender"]
|
||||
m._data = unpacked["data"]
|
||||
return m
|
||||
|
||||
class RequestLeader(Message):
|
||||
_type = "RequestLeader"
|
||||
|
||||
class ProposeMessage(Message):
|
||||
_type = "Propose"
|
||||
|
||||
class ElectionVote(Message):
|
||||
_type = "Elect"
|
||||
|
||||
class Commit(Message):
|
||||
_type = "Commit"
|
||||
|
||||
class ConnectSwarm(Message):
|
||||
_type = "connect"
|
||||
|
||||
class RequestVote(Message):
|
||||
_type = "reqvote"
|
||||
|
||||
class ConnectResponse(Message):
|
||||
_type = "accepted"
|
||||
|
||||
class VoterWill(Message):
|
||||
_type = "disconnectedvoter"
|
||||
|
||||
class CommanderWill(Message):
|
||||
_type = "disconnectedcommander"
|
||||
|
||||
class SubmitVote(Message):
|
||||
_type = "vote"
|
||||
|
||||
def __init__(self, vote = None, sender = "", data = {}):
|
||||
Message.__init__(self, sender, data)
|
||||
self._data["vote"] = vote
|
||||
|
||||
@property
|
||||
def vote(self):
|
||||
return self._data["vote"]
|
||||
|
||||
@vote.setter
|
||||
def vote(self, value):
|
||||
self._data["vote"] = value
|
||||
|
||||
class GetSwarmParticipants(Message):
|
||||
_type = "listening"
|
||||
|
||||
class VoteResult(Message):
|
||||
_type = "voteresult"
|
||||
|
||||
def __init__(self, vote, sender='', data={}):
|
||||
super().__init__(sender=sender, data=data)
|
||||
self._data["vote"] = vote
|
||||
|
||||
class ClientVoteRequest(Message):
|
||||
_type = "clientvoterequest"
|
||||
Reference in New Issue
Block a user