Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
beaf993
re-introduced address book
yozohu Nov 1, 2020
66f3a77
linting
yozohu Nov 1, 2020
2d97f1e
mic file
yozohu Nov 4, 2020
7bfe816
mic file
yozohu Nov 4, 2020
72e82c9
testing voice libraries
yozohu Nov 5, 2020
394e88d
Merge branch 'master' of https://github.com/Bellboy-Capstone/System i…
yozohu Nov 5, 2020
5bb04d2
new shutdown process
yozohu Nov 6, 2020
76a9c7d
BETTER LOGGING
yozohu Nov 8, 2020
a1ce21a
better logging
yozohu Nov 8, 2020
e995442
linting
yozohu Nov 8, 2020
2d93e22
linting
yozohu Nov 8, 2020
e5aefbe
Merge branch 'Multiproc_Logging' into Shutdown_Actors
yozohu Nov 8, 2020
68a34d9
uhh
yozohu Nov 8, 2020
6b88ba5
hmhh
yozohu Nov 8, 2020
9ca4ddf
logging from main included
yozohu Nov 8, 2020
a645e12
Merge branch 'Multiproc_Logging' into Shutdown_Actors
yozohu Nov 8, 2020
f39c14b
linting
yozohu Nov 8, 2020
2bc6ff3
linting
yozohu Nov 8, 2020
75061af
shut down tests w system context management
yozohu Nov 8, 2020
923f993
linting
yozohu Nov 8, 2020
71892dc
shutting down tests
yozohu Nov 8, 2020
f7ebd99
LINT
yozohu Nov 8, 2020
deae64f
Merge branch 'Voice_Recognition' of https://github.com/Bellboy-Capsto…
yozohu Nov 9, 2020
bfff6ba
mic stuff
yozohu Nov 10, 2020
da1fb71
more
yozohu Nov 10, 2020
642de62
Merge branch 'Shutdown_Actors' into Voice_Recognition
yozohu Nov 10, 2020
a63f11e
more
yozohu Nov 10, 2020
a62d6bc
problems shutting down on windows and lead's addressbook??
yozohu Nov 10, 2020
09d16e1
test
yozohu Nov 12, 2020
4c8d310
idk
yozohu Nov 14, 2020
0db762c
Merge branch 'Voice_Recognition' of https://github.com/Bellboy-Capsto…
yozohu Nov 14, 2020
222427a
testing mic on rpi
yozohu Nov 27, 2020
dfc1f7f
hmm
yozohu Nov 27, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions bellboy/actors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
import logging


log = logging.getLogger("actors")
5 changes: 3 additions & 2 deletions bellboy/actors/elevator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ class for the elevator and button related stuff.
in actors for now.. could move
"""

from actors import log
import logging

from collections import deque
from utils.messages import SensorEvent, SensorEventMsg


log = logging.getLogger("elevator")
# simple "buttons", only have a position (depth) value and a radius.. all in cm
BTN1_POS = 8.5
BTN2_POS = 16
Expand Down
55 changes: 33 additions & 22 deletions bellboy/actors/generic.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import os
from abc import ABC, abstractmethod

from actors import log
from thespian.actors import ActorAddress, ActorTypeDispatcher
from utils.messages import Init, Response, StatusReq, SummaryReq, TestMode

Expand All @@ -22,7 +23,7 @@ def __init__(self, *args, **kwargs):
def nameOf(self, address: ActorAddress):
"""
Returns name of actor if it's entry exists in address book.

Else returns the toString of the actorAddress.
"""

Expand Down Expand Up @@ -67,11 +68,17 @@ def receiveMsg_Init(self, message, sender):
self._nameAddress(sender, message.senderName)

if self.globalName is None:
log.warning("unnamed actor created!")
self.log = log.getChild(str(self.myAddress))
else:
self.log = log.getChild(self.globalName)
self.log.info(str.format("{} created by {}", self.globalName, sender))
self.globalName = str(self.myAddress)

self.log = logging.getLogger(self.globalName)
self.log.info(
str.format(
"{} created by {}, pid={}",
self.globalName,
self.nameOf(sender),
os.getpid(),
)
)

self.status = Response.READY
self.send(sender, self.status)
Expand All @@ -85,24 +92,28 @@ def receiveMsg_StatusReq(self, message: StatusReq, sender):
"""Sends a status update to sender."""
self.send(sender, self.status)

def receiveMsg_WakeupMessage(self, message: dict, sender: ActorAddress):
"""On wakeup request."""
self.send(sender, Response.AWAKE)

@abstractmethod
def receiveMsg_SummaryReq(self, message: SummaryReq, sender):
"""
sends a summary of the actor to the sender.
Sends a summary of the actor to the sender.
"""
self.send(sender, self.summary())

def receiveMsg_ActorExitRequest(self, msg, sender):
"""This is last msg processed before the Actor is shutdown."""
self.log.debug("Received shutdown message!")
self.teardown()

to be defined in child classes.
@abstractmethod
def teardown(self):
"""
Actor's teardown sequence, called before shutdown. (i.e. close threads, disconnect from services, etc)
"""
pass


# NOTE:
# If d actor isnt created by a bellboy actor, u must send an Init msg to it explicitly in order to use bellboy logs.
# This should only matter for the lead actor and during testing,
# cus all actors are sposed to be created thru bellboy lead anyways.
# Reason is bc the actors are running in independent processes, they dont share globals, i.e. the logger.
# Everything is communicated thru messaging.
# tldr the init msg holds the addressbook and log configs together
@abstractmethod
def summary(self):
"""
Returns a summary of the actor. The summary can be an object of any type described in the messages module.
:rtype: object
"""
pass
82 changes: 57 additions & 25 deletions bellboy/actors/lead.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
from actors.elevator import buttonHovered
from actors.generic import GenericActor
from actors.ultrasonic import UltrasonicActor
from actors.microphone import MicrophoneActor

from thespian.actors import ActorAddress
from utils.messages import Request, Response, SensorMsg, SensorReq, SensorResp
from utils.messages import (
Request,
Response,
SensorMsg,
SensorReq,
SensorResp,
MicReq,
MicMsg,
MicResp,
)


class BellboyLeadActor(GenericActor):
Expand All @@ -16,8 +27,7 @@ def startBellboyLead(self):
"""
Starts bellboy lead actor services.

Configures global RPI Board. Spawns and sets up child actors
(ultrasonic sensor).
Spawns and sets up child actors
"""
self.log.info("Starting bellboy services.")

Expand All @@ -26,12 +36,17 @@ def startBellboyLead(self):
self.ultrasonic_sensor = self.createActor(
UltrasonicActor, globalName="ultrasonic"
)
self.microphone = self.createActor(MicrophoneActor, globalName="microphone")

# request to setup sensor
# setup actors
# ultrasonic
self.send(
self.ultrasonic_sensor,
SensorMsg(SensorReq.SETUP, trigPin=23, echoPin=24, maxDepth_cm=200),
)

self.send(self.microphone, MicMsg(MicReq.SETUP, micNumber=0))

self.status = Response.STARTED

def stopBellboyLead(self):
Expand All @@ -55,32 +70,24 @@ def receiveMsg_Request(self, message: Request, sender: ActorAddress):
elif message is Request.STOP:
self.stopBellboyLead()

elif message is Request.STATUS:
self.log.debug(str.format("Status check - {}", Response.ALIVE.name))

else:
msg = "Unhandled Request Enum value sent."
self.log.error(msg)
raise Exception(msg)

self.send(sender, self.status)

# handling sensor msgs
def receiveMsg_SensorResp(self, message, sender):
self.log.info(
str.format("Received message {} from {}", message, self.nameOf(sender))
)

# if bellboy is complete, we can ignore any response msgs.

if message == SensorResp.SET:
if sender == self.ultrasonic_sensor:
# sensor is setup and ready to go, lets start polling for a hovered button.
self.send(
sender,
SensorMsg(
SensorReq.POLL, pollPeriod_ms=100, triggerFunc=buttonHovered
),
)
# sensor is setup and ready to go, lets start polling for a hovered button.
self.send(
sender,
SensorMsg(
SensorReq.POLL,
pollPeriod_ms=100,
triggerFunc=buttonHovered,
),
)

def receiveMsg_SensorEventMsg(self, message, sender):
self.event_count += 1
Expand All @@ -101,7 +108,32 @@ def receiveMsg_SensorEventMsg(self, message, sender):
self.log.debug("received 3 events, turning off sensor.")
self.send(self.ultrasonic_sensor, SensorReq.STOP)

def receiveMsg_SummaryReq(self, message, sender):
"""sends a summary of the actor."""
# handling mic msgs
def receiveMsg_MicResp(self, message, sender):
self.log.info(
str.format("Received message {} from {}", message, self.nameOf(sender))
)

if message == MicResp.SET:
self.send(sender, MicReq.START_LISTENING)

def receiveMsg_MicEventMsg(self, message, sender):
self.log.info(
str.format("Received message {} from {}", message, self.nameOf(sender))
)
self.log.info(
str.format(
"{} event from {} - {}",
message.eventType,
self.nameOf(sender),
message.phraseHeard,
)
)

def summary(self):
"""Returns a summary of the actor."""
return self.status
# TODO flesh this out...
self.send(sender, self.status)

def teardown(self):
pass
130 changes: 130 additions & 0 deletions bellboy/actors/microphone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import speech_recognition as sr
import time
from threading import Thread

from actors.generic import GenericActor
from utils.messages import MicEvent, MicMsg, MicEventMsg, MicReq, MicResp, Response

class MicrophoneActor(GenericActor):
"""
Class for the voice recognition microphone. nnn
"""

def __init__(self):
super().__init__()
self.microphone = None
self.listening_thread = None
self.threadOn = False
self.recognizer = sr.Recognizer()

def microphoneList(self):
"""return list of microphones in the system"""
return self.sr.Microphone.list_microphone_names()

# STATE METHODS
def setupMicrophone(self, micNumber):
"""Choose system microphone to use as mic

:param micNumber: microphone number as indexed by microphoneList()
:type micNumber: int
"""
self.micIx = micNumber
self.status = MicResp.SET

def listening_loop(self):
"""To run in mic's thread. Listens for speech."""

self.status = MicResp.LISTENING
timeout_sec = 30.0
self.log.info("begun listening.")
while self.threadOn:

# do the processing
with sr.Microphone(device_index=self.micIx) as source:
try:
audio = self.recognizer.listen(source, timeout=timeout_sec)
try:
recognized_audio = self.recognizer.recognize_google(audio)
self.log.info(
str.format("Someone said <<{}>>", recognized_audio)
)
if "floor" in str(recognized_audio):
self.send(
self.parent,
MicEventMsg(
eventType=MicEvent.SPEECH_HEARD,
speechHeard=str(recognized_audio),
),
)
except sr.UnknownValueError:
self.log.debug("Google API: unknown speech heard")

except speech_recognition.RequestError:
pass
# use sphinx instead


except sr.WaitTimeoutError:
self.log.debug(
str.format("Nothing was heard for {} seconds", timeout_sec)
)

self.log.info("Stopped listening thread")
self.status = MicResp.SET

def start_listening(self):
if self.status != MicResp.SET:
self.log.warning("Mic not setup!")
return

if self.status == MicResp.LISTENING:
self.log.info("Alreay listening!")
return

self.threadOn = True
self.listening_thread = Thread(target=self.listening_loop)
self.listening_thread.start()

def stop_listening(self):
if not self.threadOn:
self.log.info("Not listening")
return

self.log.debug("Terminating listener thread")
self.threadOn = False
# join?

# MSG HANDLING
def receiveMsg_MicMsg(self, msg, sender):
self.log.info(
str.format("Received message {} from {}", msg, self.nameOf(sender))
)
if msg.msgType == MicReq.SETUP:
self.setupMicrophone(msg.micNumber)

if self.status != MicResp.SET:
self.send(sender, Response.FAIL)

else:
self.send(sender, self.status)

def receiveMsg_MicReq(self, msg, sender):
self.log.info(
str.format("Received message {} from {}", msg.name, self.nameOf(sender))
)
if msg == MicReq.GET_MIC_LIST:
self.send(
sender, MicMsg(msgType=MicResp.MIC_LIST, micList=microphoneList())
)
elif msg == MicReq.START_LISTENING:
self.start_listening()

elif msg == MicReq.STOP_LISTENING:
self.stop_listening()

# overrides
def summary(self):
return self.status

def teardown(self):
self.stop_listening()
Loading