Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,63 @@
# surface
Surface code 2020-21

Setting the static ip

On the Ubuntu Desktop
Note: This is for Ubuntu desktop. The interface for Mate may be different

On the computer, which is connected to the Internet, click the network icon in the panel and go to "Edit Connections..." at the bottom of the menu.

Edit Connection...

Double click your Wired Connection (Leave your wireless connection untouched, the one connected to Internet and the one you want to share, as I understand).

Network Connections Dialog

On the "IPv4 Settings tab", select Method: "Shared to other computers"

Editing Wired Connection

Reconnect by clicking on the Wired Network, so it gets a new IP address. (The two computers must be connected by an ethernet cable for this step, so connect them now if you haven't already.)

Click on "Connection Information" in the network menu and write down the IP address and network mask (in my case it was assigned 10.42.0.1/255.255.255.0 but I do not know if that will always be the case).

Connection Information

On the Raspberry Pi
Assign static IP to the Ethernet connection

In Pi the WiFi device is called wlan but the ethernet device name is hard to guess. To find the device names use the command:

$ ip link show

The output will show your Ethernet device in Pi enxb827eb3d64cc

Next we need to find the current IP addresses assigned to enxb827eb3d64cc:

$ ip -4 addr show dev enxb827eb3d64cc | grep inet

I get something like this, yours may be different:

inet 10.42.0.211/24 brd 10.42.0.255 scope global enxb827eb3d64cc
You can keep the assigned IP address or choose a different one in the same subnet. Add the following lines at the end of /etc/dhcpcd.conf by:

$ sudo nano /etc/dhcpcd.conf

With the following content to make the assigned IP address static:

# Custom static IP address for enxb827eb3d64cc
interface enxb827eb3d64cc
static ip_address=10.42.0.211/24
static routers=10.42.0.255
static domain_name_servers=10.42.0.255
Change 10.42.0.211 above to 10.42.0.x where x is a number between 2 and 254 if you want to assign a different IP address.

Reboot Pi to make the new IP address take effect:

$ sudo reboot now

Now you should be able to ssh from the desktop to the Pi with the following command:

$ ssh pi@10.42.0.211
Hope this helps
9 changes: 5 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
import setuptools

# Fetch the root folder to specify absolute paths to the "include" files
ROOT = os.path.normpath(os.path.dirname(__file__))
ASSETS_DIR = os.path.join(os.path.normpath(os.path.dirname(__file__)), "surface", "assets")

# Specify which files should be added to the installation
PACKAGE_DATA = [
os.path.join(ROOT, "surface", "res", "metadata.json"),
os.path.join(ROOT, "surface", "log", ".keep")
os.path.join(ASSETS_DIR, "metadata.json"),
os.path.join(ASSETS_DIR, "log-config.json"),
os.path.join(ASSETS_DIR, "log", ".keep")
]

with open(os.path.join(ROOT, "surface", "res", "metadata.json")) as f:
with open(os.path.join(ASSETS_DIR, "metadata.json")) as f:
metadata = json.load(f)

setuptools.setup(
Expand Down
19 changes: 19 additions & 0 deletions surface/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
"""
Surface control station package.
"""
import os
import json
from . import control, networking, vision, athena
from .exceptions import SurfaceException
from .constants.common import ASSETS_DIR

with open(os.path.join(ASSETS_DIR, "metadata.json")) as f:
metadata = json.load(f)

__title__ = metadata["__title__"]
__description__ = metadata["__description__"]
__version__ = metadata["__version__"]
__lead__ = metadata["__lead__"]
__email__ = metadata["__email__"]
__url__ = metadata["__url__"]

__all__ = [
"control",
"networking",
"vision",
"athena",
"SurfaceException",
"__title__",
"__description__",
"__version__",
"__lead__",
"__email__",
"__url__",
]
26 changes: 26 additions & 0 deletions surface/__main__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
"""
Surface control station execution file.
"""
import os
import sys
import time

# Make sure a local surface package can be found and overrides any installed versions
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

# pylint: disable = wrong-import-position
from surface.networking import Connection
from surface.control import ControlManager, ManualController
from surface.enums import ConnectionStatus

if __name__ == '__main__':
control_manager_pid = ControlManager().start()
manual_controller_pid = ManualController().start()
connection = Connection()

while True:
status = connection.status

if status == ConnectionStatus.DISCONNECTED:
connection.connect()
elif status == ConnectionStatus.IDLE:
connection.reconnect()

time.sleep(1)
File renamed without changes.
File renamed without changes.
File renamed without changes.
17 changes: 13 additions & 4 deletions surface/constants/athena.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
}
# Data received from Raspberry Pi
DATA_RECEIVED = {
"A_O": False,
"A_I": False,
"S_O": 0,
"S_I": 0
"A_A": False,
"A_B": False,
"S_A": 0,
"S_B": 0
}
# Data that will be sent to Raspberry Pi
DATA_TRANSMISSION = {
Expand All @@ -50,18 +50,27 @@
CONTROL_MANAGER_NAME + "-sway": CONTROL_NORM_IDLE,
CONTROL_MANAGER_NAME + "-surge": CONTROL_NORM_IDLE,
CONTROL_MANAGER_NAME + "-heave": CONTROL_NORM_IDLE,
CONTROL_MANAGER_NAME + "-cord": CONTROL_NORM_IDLE,
CONTROL_MANAGER_NAME + "-gripper": CONTROL_NORM_IDLE,
CONTROL_MANAGER_NAME + "-micro": CONTROL_NORM_IDLE,
CONTROL_MANUAL_NAME + "-yaw": CONTROL_NORM_IDLE,
CONTROL_MANUAL_NAME + "-pitch": CONTROL_NORM_IDLE,
CONTROL_MANUAL_NAME + "-roll": CONTROL_NORM_IDLE,
CONTROL_MANUAL_NAME + "-sway": CONTROL_NORM_IDLE,
CONTROL_MANUAL_NAME + "-surge": CONTROL_NORM_IDLE,
CONTROL_MANUAL_NAME + "-heave": CONTROL_NORM_IDLE,
CONTROL_MANUAL_NAME + "-cord": CONTROL_NORM_IDLE,
CONTROL_MANUAL_NAME + "-gripper": CONTROL_NORM_IDLE,
CONTROL_MANUAL_NAME + "-micro": CONTROL_NORM_IDLE,
CONTROL_AUTONOMOUS_NAME + "-yaw": CONTROL_NORM_IDLE,
CONTROL_AUTONOMOUS_NAME + "-pitch": CONTROL_NORM_IDLE,
CONTROL_AUTONOMOUS_NAME + "-roll": CONTROL_NORM_IDLE,
CONTROL_AUTONOMOUS_NAME + "-sway": CONTROL_NORM_IDLE,
CONTROL_AUTONOMOUS_NAME + "-surge": CONTROL_NORM_IDLE,
CONTROL_AUTONOMOUS_NAME + "-heave": CONTROL_NORM_IDLE,
CONTROL_AUTONOMOUS_NAME + "-cord": CONTROL_NORM_IDLE,
CONTROL_AUTONOMOUS_NAME + "-gripper": CONTROL_NORM_IDLE,
CONTROL_AUTONOMOUS_NAME + "-micro": CONTROL_NORM_IDLE,
RK_CONTROL_DRIVING_MODE: DrivingMode.MANUAL.value
}
# Other, un-classified data
Expand Down
8 changes: 4 additions & 4 deletions surface/constants/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
# Declare paths to relevant folders - tests folder shouldn't be known here
ROOT_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", ".."))
SURFACE_DIR = os.path.join(ROOT_DIR, "surface")
RES_DIR = os.path.join(SURFACE_DIR, "res")
LOG_DIR = os.path.join(SURFACE_DIR, "log")
ASSETS_DIR = os.path.join(SURFACE_DIR, "assets")
LOG_DIR = os.path.join(ASSETS_DIR, "log")

# Load the environment variables from the root folder and/or the resources folder
dotenv.load_dotenv(dotenv_path=os.path.join(ASSETS_DIR, ".env"))
dotenv.load_dotenv(dotenv_path=os.path.join(ROOT_DIR, ".env"))
dotenv.load_dotenv(dotenv_path=os.path.join(RES_DIR, ".env"))

# Declare logging config - use .env file to override the defaults
LOG_CONFIG_PATH = os.getenv("LOG_CONFIG_PATH", os.path.join(RES_DIR, "log-config.json"))
LOG_CONFIG_PATH = os.getenv("LOG_CONFIG_PATH", os.path.join(ASSETS_DIR, "log-config.json"))
LOGGER_NAME = os.getenv("LOGGER_NAME", "surface")
6 changes: 5 additions & 1 deletion surface/constants/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,20 @@
THRUSTER_MAX = 1900
THRUSTER_IDLE = 1500
THRUSTER_MIN = 1100
GRIPPER_MAX = 1600
GRIPPER_IDLE = 1500
GRIPPER_MIN = 1400
CORD_MAX = 1600
CORD_IDLE = 1500
CORD_MIN = 1400

# Joystick control boundary - any values below are considered 0
DEAD_ZONE = 1025

# Hardware and the expected min/max values
HARDWARE_AXIS_MAX = 32767
HARDWARE_AXIS_MIN = -32768
HARDWARE_TRIGGER_MAX = 255
HARDWARE_TRIGGER_MAX = 1023
HARDWARE_TRIGGER_MIN = 0
INTENDED_AXIS_MAX = CONTROL_NORM_MAX
INTENDED_AXIS_MIN = CONTROL_NORM_MIN
Expand Down
39 changes: 38 additions & 1 deletion surface/control/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"""
from typing import Dict
from .common import normalise
from ..constants.control import CONTROL_NORM_IDLE, CONTROL_NORM_MAX, CONTROL_NORM_MIN, THRUSTER_MAX, THRUSTER_MIN
from ..constants.control import CONTROL_NORM_IDLE, CONTROL_NORM_MAX, CONTROL_NORM_MIN
from ..constants.control import THRUSTER_MAX, THRUSTER_MIN, GRIPPER_MAX, GRIPPER_MIN, CORD_MAX, CORD_MIN


class Converter:
Expand All @@ -25,6 +26,9 @@ def convert(motions: Dict[str, float]) -> Dict[str, int]:
"T_VFS": Converter._thruster_vfs(motions),
"T_VAP": Converter._thruster_vap(motions),
"T_VAS": Converter._thruster_vas(motions),
"T_M": Converter._thruster_micro(motions),
"M_C": Converter._cord(motions),
"M_G": Converter._gripper(motions),
}

@staticmethod
Expand Down Expand Up @@ -227,6 +231,39 @@ def _thruster_vas(motions: Dict[str, float]) -> int:

return Converter._to_thruster_value(value)

@staticmethod
def _thruster_micro(motions: Dict[str, float]) -> int:
"""
Hierarchical control for micro ROV thruster.
"""
micro = motions["micro"]

value = micro if micro else CONTROL_NORM_IDLE

return Converter._to_thruster_value(value)

@staticmethod
def _cord(motions: Dict[str, float]) -> int:
"""
Hierarchical control for cord control.
"""
cord = motions["cord"]

value = cord if cord else CONTROL_NORM_IDLE

return int(normalise(value, CONTROL_NORM_MIN, CONTROL_NORM_MAX, CORD_MIN, CORD_MAX))

@staticmethod
def _gripper(motions: Dict[str, float]) -> int:
"""
Hierarchical control for gripper control.
"""
gripper = motions["gripper"]

value = gripper if gripper else CONTROL_NORM_IDLE

return int(normalise(value, CONTROL_NORM_MIN, CONTROL_NORM_MAX, GRIPPER_MIN, GRIPPER_MAX))

@staticmethod
def _to_thruster_value(value: float) -> int:
"""
Expand Down
42 changes: 41 additions & 1 deletion surface/control/manual.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ def hat_x(self, value: int):
Set state of joystick's horizontal hat.
"""
self._hat_x = value
self._update_cord()

@property
def hat_y(self) -> int:
Expand All @@ -204,6 +205,7 @@ def hat_y(self, value: int):
Set state of joystick's vertical hat.
"""
self._hat_y = value
self._update_micro_thruster()

@property
def button_a(self) -> bool:
Expand All @@ -218,6 +220,7 @@ def button_a(self, value: bool):
Set state of joystick's button A.
"""
self._button_a = value
self._update_gripper()

@property
def button_b(self) -> bool:
Expand Down Expand Up @@ -262,6 +265,7 @@ def button_y(self, value: bool):
Set state of joystick's button Y.
"""
self._button_y = value
self._update_gripper()

@property
def button_lb(self) -> bool:
Expand Down Expand Up @@ -402,6 +406,39 @@ def _update_heave(self):
else:
self.heave = CONTROL_NORM_IDLE

def _update_cord(self):
"""
Cord is determined by the horizontal hat value.
"""
if self.hat_x > 0:
self.cord = CONTROL_NORM_MAX
elif self.hat_x < 0:
self.cord = CONTROL_NORM_MIN
else:
self.cord = CONTROL_NORM_IDLE

def _update_gripper(self):
"""
Gripper is determined by the buttons Y and A.
"""
if self.button_y:
self.gripper = CONTROL_NORM_MAX
elif self.button_a:
self.gripper = CONTROL_NORM_MIN
else:
self.gripper = CONTROL_NORM_IDLE

def _update_micro_thruster(self):
"""
Micro ROV thruster is determined by the vertical hat value.
"""
if self.hat_y < 0:
self.micro = CONTROL_NORM_MAX
elif self.hat_y > 0:
self.micro = CONTROL_NORM_MIN
else:
self.micro = CONTROL_NORM_IDLE

def _update_mode(self):
"""
Mode can be switched between manual and assisted only.
Expand All @@ -417,7 +454,10 @@ def _update_mode(self):
"roll": CONTROL_NORM_IDLE,
"sway": CONTROL_NORM_IDLE,
"surge": CONTROL_NORM_IDLE,
"heave": CONTROL_NORM_IDLE
"heave": CONTROL_NORM_IDLE,
"cord": CONTROL_NORM_IDLE,
"gripper": CONTROL_NORM_IDLE,
"micro": CONTROL_NORM_IDLE,
}
elif self.button_select:
self.mode = DrivingMode.ASSISTED
Expand Down
Loading