From 4688a8fe17724294b48ede342616681c80a77634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otgaar?= Date: Thu, 30 Oct 2025 17:07:20 +0100 Subject: [PATCH] chore: cleanup for merging/ switching to later branches --- README.md | 83 -------------------------- main.py | 149 ----------------------------------------------- requirements.txt | 4 -- state.py | 53 ----------------- state.pyc | Bin 2301 -> 0 bytes 5 files changed, 289 deletions(-) delete mode 100644 main.py delete mode 100644 state.py delete mode 100644 state.pyc diff --git a/README.md b/README.md index cda89a4..c5a8c97 100644 --- a/README.md +++ b/README.md @@ -2,88 +2,6 @@ ### Linux (or WSL) Start off by installing [Pyenv](https://github.com/pyenv/pyenv?tab=readme-ov-file#installation) and walk through the steps outlined there (be sure to also add it to PATH). Also install the [Python build requirements](https://github.com/pyenv/pyenv/wiki#suggested-build-environment). Afterwards, install Python 2.7 and activate it for your current shell: -<<<<<<< HEAD -```bash -pyenv install 2.7 -pyenv shell 2.7 -``` - -You can check that this worked by typing - -```bash -python -V -``` - -Which should return `Python 2.7.18`. - -Next, `cd` into this repository and create (and activate) a virtual environment: - -```bash -cd / -python -m pip install virtualenv -python -m virtualenv .venv -source .venv/bin/activate -``` - -To be able to install the PyAudio Python package, you'll need to have the `portaudio` system package installed. On Debian or Ubuntu: - -```shell -sudo apt install portaudio19-dev -``` - -Then you can install the required packages with - -```bash -pip install -r requirements.txt -``` - -Now we need to install the NaoQi SDK into our virtual environment, which we need to do manually. Begin by downloading the SDK: - -```bash -wget https://community-static.aldebaran.com/resources/2.5.10/Python%20SDK/pynaoqi-python2.7-2.5.7.1-linux64.tar.gz -``` - -Next, move into the `site-packages` directory and extract the file you just downloaded: - -```bash -cd .venv/lib/python2.7/site-packages/ -tar xvfz /pynaoqi-python2.7-2.5.7.1-linux64.tar.gz -rm /pynaoqi-python2.7-2.5.7.1-linux64.tar.gz -``` - -Lastly, we need to inform our virtual environment where to find our newly installed package: - -```bash -echo /.venv/lib/python2.7/site-packages/pynaoqi-python2.7-2.5.7.1-linux64/lib/python2.7/site-packages/ > pynaoqi-python2.7.pth -``` - -That's it! Verify that it works with - -```bash -python -c "import qi; print(qi)" -``` - -You should now be able to run this project. - -### MacOS - -On ARM CPU's, pyenv doesn't want to install Python 2. You can download and install it from [the Python website](https://www.python.org/downloads/release/python-2718/). - -Create a virtual environment as described in the Linux section. - -Then build `portaudio` for x86_64 CPU's. - -Then follow the remaining installation instructions in the Linux section. - -## Running -Assuming you have the virtual environment activated (`source .venv/bin/activate` on Linux) and that you have a virtual robot running on localhost you should be able to run this project by typing - -```bash -python main.py --qi-url tcp://localhost: -``` - -where `` is the port on which your robot is running. -======= The robot interface is a high-level API for controlling the robot. It implements the API as designed: https://utrechtuniversity.youtrack.cloud/articles/N25B-A-14/RI-CB-Communication. This is an implementation for the Pepper robot, using the Pepper SDK and Python 2.7 as required by the SDK. @@ -216,4 +134,3 @@ If your commit fails its either: branch name != /description-of-branch , commit name != : description of the commit. : N25B-Num's ->>>>>>> origin/dev diff --git a/main.py b/main.py deleted file mode 100644 index db0f24e..0000000 --- a/main.py +++ /dev/null @@ -1,149 +0,0 @@ -import sys -import logging - -import argparse -import zmq -import json -import logging -import hashlib -import socket -import time - -from src.audio_streaming import AudioStreaming -from state import state -from urlparse import urlparse - - -def say(session, message): - tts = session.service("ALTextToSpeech") - tts.say(message) - -def listen_for_messages(session): - context = zmq.Context() - socket = context.socket(zmq.SUB) - socket.connect("tcp://localhost:5556") - socket.setsockopt_string(zmq.SUBSCRIBE, u"") # u because Python 2 shenanigans - - # Let the CB know we're connected. - pub = context.socket(zmq.PUB) - pub.bind("tcp://*:5555") - - time.sleep(1) - print("Now attempting to send connection data to CB.") - connection_data = { - "event": "robot_connected", - "id": state.__getattribute__("id"), - "name": state.__getattribute__("name"), - "port": state.__getattribute__("port") - } - - connection_json = json.dumps(connection_data) - pub.send_string(connection_json) - print("Send data: ", connection_json) - listening_loop(socket, pub) - -def listening_loop(socket, pub): - - print("Entered listening loop.") - poller = zmq.Poller() - poller.register(socket, zmq.POLLIN) - - logging.info("Listening for messages") - - while not state.exit_event.is_set(): - if not poller.poll(200): continue # At most 200 ms delay after CTRL+C - # We now know there's a message waiting for us - message = socket.recv_string() - logging.debug("Received message: {}".format(message)) - handle_message(message, pub) - -def handle_message(msg, pub): - """ - Parse the message and act accordingly to conditional statements. - """ - msgs = msg.split(",") # Let's split the attributes - if msgs[0] == "ping": - # return ping - ping_data = { - "event": "ping", - "id": state.__getattribute__("id"), - } - ping_json = json.dumps(ping_data) - pub.send_string(ping_json) - logging.debug("Returned ping.") - return - - # Other if statements such as `if msgs[0] == "say"` - return - -def get_session(): - if "--qi-url" not in sys.argv: - logging.info("No Qi URL argument given. Running in stand-alone mode.") - ip = resolve_local_ip() - port = -1 - return None, ip, port - - parser = argparse.ArgumentParser() - parser.add_argument("--qi-url", type=str, help="Qi URL argument") - parser.add_argument("--name", type=str, default="Robot without name", help="Optional robot name") - args = parser.parse_args() - - name = args.name - parsed = urlparse(args.qi_url) - ip = parsed.hostname - port = parsed.port - - # If URL uses localhost, get own ip instead - if ip in ("localhost", "127.0.0.1"): - ip = resolve_local_ip() - - try: - import qi - except ImportError: - logging.info("Unable to import qi. Running in stand-alone mode.") - return None, ip, port, name - - try: - app = qi.Application() - app.start() - return app.session, ip, port, name - except RuntimeError: - logging.info("Unable to connect to the robot. Running in stand-alone mode.") - return None, ip, port, name - - -def resolve_local_ip(): - """Return the actual local IP, not 127.0.0.1.""" - try: - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.connect(("8.8.8.8", 80)) # Use a public IP just to resolve interface - ip = s.getsockname()[0] - s.close() - return ip - except Exception as e: - logging.warning("Could not resolve local IP: {}".format(e)) - return "127.0.0.1" - -def main(): - session, ip, port, name = get_session() - - # hash ip, port into id - id_source = "{}:{}".format(ip, port) - unique_id = hashlib.md5(id_source).hexdigest() - - print("created unique id: ", unique_id) - - state.id = unique_id - state.port = port - state.ip = ip - state.name = name - - logging.info("Session ID: {} (from {})".format(unique_id, id_source)) - listen_for_messages(session) - -if __name__ == "__main__": - try: - state.initialize() - main() - finally: - state.deinitialize() diff --git a/requirements.txt b/requirements.txt index b0a20d8..f93c70d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,5 @@ pyzmq<16 -<<<<<<< HEAD -pyaudio<=0.2.11 -======= pyaudio<=0.2.11 pytest<5 pytest-mock<3.0.0 pytest-cov<3.0.0 ->>>>>>> origin/dev diff --git a/state.py b/state.py deleted file mode 100644 index cf33ca0..0000000 --- a/state.py +++ /dev/null @@ -1,53 +0,0 @@ -import logging -import signal -import threading - - -class State(object): - """ - Do not create an instance of this class directly: use the instance `state` below. This state must be initiated once, - probably when your program starts. - - This class is used to share state between threads. For example, when the program is quit, that all threads can - detect this via the `exit_event` property being set. - """ - def __init__(self): - self.is_initialized = False - self.exit_event = None - - def initialize(self): - if self.is_initialized: - logging.warn("Already initialized") - return - - self.exit_event = threading.Event() - def handle_exit(_, __): - logging.info("Exiting.") - self.exit_event.set() - signal.signal(signal.SIGINT, handle_exit) - signal.signal(signal.SIGTERM, handle_exit) - - self.is_initialized = True - - def deinitialize(self): - if not self.is_initialized: return - self.is_initialized = False - - def __getattribute__(self, name): - # Enforce that the state is initialized before accessing any property (aside from the basic ones) - if name in ("initialize", "deinitialize", "is_initialized", "__dict__", "__class__", "id", "name", "ip", "port"): - return object.__getattribute__(self, name) - - if not object.__getattribute__(self, "is_initialized"): - # Special case for the exit_event: if the event is set, return it without an error - if name == "exit_event": - exit_event = object.__getattribute__(self, "exit_event") - if exit_event and exit_event.is_set(): return exit_event - - raise RuntimeError("State must be initialized before accessing '%s'" % name) - - return object.__getattribute__(self, name) - - -# Must call `.initialize` before use -state = State() diff --git a/state.pyc b/state.pyc deleted file mode 100644 index 78f993d51d620683decea5a760d94e77ccb38c02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2301 zcmbtU!Ezf#5basXvZYu_$_4`=P;-FFQe~tnjzCdBa8fy-!^#(Q8LxIn(#oq{u``M- z%DG?)@}rzN@B#3;SGK5dGANn$Y)?=3o9@@$__N#jo~Ur|mp zy4@=psT+Mjqkz(YY=b6HHs}|kYoZ@UO|nhijdu9{Fl@qC_7{Ewzk}`2$KKvXRM32j zLe~CWNMLa4>e3*W-&HapV`aI z8~f50{)}BMZROW^TUJc9v%V)66Rr)f0P88|`3S-jT@e{66K_x;)HGzffs|T`{4CDl z=RTB~Gj+o9>?fOgCc~gCtnXm6MIra)(Aj(v;*3PNPq6FH%7yKZ=Vev&mv#xTn?K8Z zCv(8;NHO2X`EfR9neg_#KVSa_88*CYlpfkH{;U3+1jADSnS{&|F9i z6SG6Vk#IbqUx{8R@-3RTMDEg+qU(UvR<(DlYI6W1%`*%+@W35Hev@-$*Bc&5S`vnK zv)IOc2!T}3k!J(|D#jYnyuqC%5JR>fxIM@dR1>A^)%o9rCNHN`Xe6UqF)1TX1Re#? z*2_&i8Q?rSF-FoKaW92fbjPgU!q6wTx)MDkm;ZIIa()ArJ63rnPh#2Hd2?ppBEnI>)o_ z$;a+V$V_|#N5qpZdWQwGIeL!;7dd(#qHZ%zbUB`5wt6OsF;k1czRJccZ-JN3G5pYP zo(mPN3ZE_PNmZ4V41=1q;+dP}zp^0u0GB_)a?Do>_SM7S0P;W`&~9)Tgwl3