Skip to content

Commit

Permalink
Add create3 usb0 subnet setting
Browse files Browse the repository at this point in the history
  • Loading branch information
hilary-luo committed Mar 26, 2024
1 parent 8ddae7b commit 4b0a568
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 17 deletions.
2 changes: 1 addition & 1 deletion etc/systemd/system/webserver.service
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ StartLimitIntervalSec=0
Type=simple
Restart=always
RestartSec=1
ExecStart=/usr/bin/socat TCP-LISTEN:8080,fork,reuseaddr tcp:192.168.186.2:80
ExecStart=/etc/turtlebot4/webserver.sh

[Install]
WantedBy=multi-user.target
2 changes: 1 addition & 1 deletion etc/turtlebot4/aliases.bash
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ TurtleBot 4 User Manual: https://turtlebot.github.io/turtlebot4-user-manual \n\
TurtleBot 4 Github: https://github.com/turtlebot/turtlebot4"'

# Restart ntpd on Create 3
alias turtlebot4-ntpd-sync='curl -X POST http://192.168.186.2/api/restart-ntpd'
alias turtlebot4-ntpd-sync='curl -X POST http://${CREATE3_IP:-192.1168.186.2}/api/restart-ntpd'

# Restart turtlebot4 service
alias turtlebot4-service-restart='sudo systemctl restart turtlebot4.service'
Expand Down
3 changes: 3 additions & 0 deletions etc/turtlebot4/webserver.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
source /etc/turtlebot4/setup.bash
/usr/bin/socat TCP-LISTEN:8080,fork,reuseaddr tcp:${CREATE3_IP:-192.1168.186.2}:80
3 changes: 2 additions & 1 deletion scripts/create_update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ done

echo "Image path: $1";

curl -X POST --data-binary @$1 http://192.168.186.2/api/firmware-update
source /etc/turtlebot4/setup.bash
curl -X POST --data-binary @$1 http://${CREATE3_IP:-192.1168.186.2}/api/firmware-update
65 changes: 60 additions & 5 deletions turtlebot4_setup/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ class BashOptions(str, Enum):
DIAGNOSTICS = 'TURTLEBOT4_DIAGNOSTICS'
WORKSPACE = 'WORKSPACE_SETUP'
SUPER_CLIENT = 'ROS_SUPER_CLIENT'
CREATE3_IP = 'CREATE3_IP'


class DiscoveryOptions(str, Enum):
ENABLED = 'ENABLED'
IP = 'IP'
PORT = 'PORT'
SERVER_ID = 'SERVER_ID'
SUBNET = 'CREATE3_USB0_SUBNET'


class Conf():
Expand Down Expand Up @@ -74,19 +76,22 @@ class Conf():
BashOptions.RMW: 'rmw_fastrtps_cpp',
BashOptions.DIAGNOSTICS: '1',
BashOptions.WORKSPACE: '/opt/ros/humble/setup.bash',
BashOptions.SUPER_CLIENT: False
BashOptions.SUPER_CLIENT: False,
BashOptions.CREATE3_IP: '192.168.186.2',
}

default_discovery_conf = {
DiscoveryOptions.ENABLED: False,
DiscoveryOptions.IP: '127.0.0.1',
DiscoveryOptions.PORT: '11811',
DiscoveryOptions.SERVER_ID: '0',
DiscoveryOptions.SUBNET: '186',
}

def __init__(self) -> None:
self.system_file = os.path.join(self.setup_dir, 'system')
self.setup_bash_file = os.path.join(self.setup_dir, 'setup.bash')
self.netplan_eth_file = os.path.join(self.netplan_dir, '40-ethernets.yaml')
self.netplan_wifis_file = os.path.join(self.netplan_dir, '50-wifis.yaml')
self.discovery_sh_file = os.path.join(self.setup_dir, 'discovery.sh')
self.hostname_file = '/etc/hostname'
Expand Down Expand Up @@ -133,15 +138,17 @@ def apply_default(self, conf):
self.discovery_conf = copy.deepcopy(self.default_discovery_conf)

def read(self):
self.read_system()
self.read_wifi()
self.read_bash()
self.read_discovery() # Must come after read_bash in order to have the discovery server envar
self.read_subnet()
self.read_system() # Must come after read_subnet in order to mask the USB0 IP address

def write(self):
self.write_system()
self.write_wifi()
self.write_discovery()
self.write_subnet()
self.write_bash()

def read_system(self):
Expand All @@ -151,9 +158,9 @@ def read_system(self):
if k in line:
self.system_conf[k] = line.split(':')[1].strip()

self.system_conf[SystemOptions.IP] = subprocess.run(
shlex.split('hostname -I'),
capture_output=True).stdout.decode('ascii').replace('192.168.186.3', '').strip()
subnet = self.get(DiscoveryOptions.SUBNET)
output = subprocess.run(shlex.split('hostname -I'), capture_output=True).stdout
self.system_conf[SystemOptions.IP] = output.decode('ascii').replace(f'192.168.{subnet}.3', '').strip()

with open(self.hostname_file, 'r') as f:
self.set(SystemOptions.HOSTNAME, f.readline().strip())
Expand Down Expand Up @@ -307,6 +314,52 @@ def write_bash(self):
else:
os.environ[k] = str(v)

def read_subnet(self):
netplan = yaml.load(open(self.netplan_eth_file, 'r'), yaml.SafeLoader)
# wlan0 Config
usb0 = netplan['network']['ethernets']['usb0']
address = list(usb0['addresses'])[0]
subnet = address.split('.')[2]

# Get Subnet
self.set(DiscoveryOptions.SUBNET, subnet)
self.set(BashOptions.CREATE3_IP, f'192.168.{subnet}.2')

def write_subnet(self):
subnet = self.get(DiscoveryOptions.SUBNET)

# Update the usb0 subnet using netplan
netplan = {
'network': {
'ethernets': {
'eth0': {
'addresses': ['192.168.185.3/24'],
'dhcp4': True,
'optional': True,
},
'usb0': {
'addresses': [f'192.168.{subnet}.3/24'],
'dhcp4': False,
'optional': True,
},
},
'version': 2,
}
}

with open('/tmp' + self.netplan_eth_file, 'w') as f:
f.write('# This file was automatically created by the turtlebot4-setup tool and should not be manually modified\n\n')

yaml.dump(netplan,
stream=open('/tmp' + self.netplan_eth_file, 'a'),
Dumper=yaml.SafeDumper,
indent=4,
default_flow_style=False,
default_style=None)

subprocess.run(shlex.split(f'sudo mv /tmp{self.netplan_eth_file} {self.netplan_eth_file}'))


def read_discovery(self):
discovery_server = self.get(BashOptions.DISCOVERY_SERVER)
if discovery_server is None or discovery_server == '':
Expand Down Expand Up @@ -348,7 +401,9 @@ def write_discovery(self):
else:
self.set(BashOptions.DISCOVERY_SERVER, None)
self.set(BashOptions.SUPER_CLIENT, False)
self.set(DiscoveryOptions.SUBNET, self.default_discovery_conf[DiscoveryOptions.SUBNET])

self.write_subnet()
self.write_bash()

@staticmethod
Expand Down
14 changes: 14 additions & 0 deletions turtlebot4_setup/ros_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ def __init__(self, configs: Conf) -> None:
function=self.set_port),
MenuEntry(entry=self.format_entry('Server ID', DiscoveryOptions.SERVER_ID),
function=self.set_server_id),
MenuEntry(entry=self.format_entry('Create3 USB0 Subnet', DiscoveryOptions.SUBNET),
function=self.set_subnet),
MenuEntry('', None),
MenuEntry(entry='Apply Defaults', function=self.apply_defaults),
MenuEntry(entry='Save', function=self.save_settings)]
Expand Down Expand Up @@ -221,6 +223,18 @@ def set_server_id(self):
server_id = max(0, min(int(server_id), 255))
self.conf.set(DiscoveryOptions.SERVER_ID, server_id)

def set_subnet(self):
p = Prompt(prompt='Create3 Subnet [{0}]: '.format(self.conf.get(DiscoveryOptions.SUBNET)),
default_response=self.conf.get(DiscoveryOptions.SUBNET),
response_type=int,
note='Create3 Subnet (0-184, 186-255)')
subnet = p.show()
subnet = max(0, min(int(subnet), 255))
if (subnet == 185): # Avoid Pi Ethernet subnet (prevent potential routing issues)
subnet = 184
self.conf.set(DiscoveryOptions.SUBNET, subnet)
self.conf.set(BashOptions.CREATE3_IP, f'192.168.{subnet}.2')

def apply_defaults(self):
self.conf.apply_default(self.conf.discovery_conf)

Expand Down
32 changes: 23 additions & 9 deletions turtlebot4_setup/turtlebot4_setup
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Turtlebot4Setup():
if self.conf.get(option) == '' and self.initial_conf.get(option) == None or \
self.conf.get(option) == None and self.initial_conf.get(option) == '':
pass
elif (self.conf.get(option) != self.initial_conf.get(option)):
elif (str(self.conf.get(option)) != str(self.initial_conf.get(option))):
diff.append(option)

return diff
Expand Down Expand Up @@ -128,6 +128,7 @@ class Turtlebot4Setup():
menu_entries=['Okay'])
options.show()
return
self.apply_pi_network_settings()
self.initial_conf = copy.deepcopy(self.conf)

def apply_ros_settings(self):
Expand All @@ -149,6 +150,9 @@ class Turtlebot4Setup():
reinstall_job = True

if update_create3:
initial_subnet = self.initial_conf.get(DiscoveryOptions.SUBNET)
new_subnet = self.conf.get(DiscoveryOptions.SUBNET)

ros_domain_id = 'ros_domain_id=' + os.environ[BashOptions.DOMAIN_ID]
ros_namespace = '&ros_namespace=' + os.environ[BashOptions.NAMESPACE]
rmw_implementation = '&rmw_implementation=' + os.environ[BashOptions.RMW]
Expand All @@ -157,7 +161,7 @@ class Turtlebot4Setup():
port = self.conf.get(DiscoveryOptions.PORT)
ip = self.conf.get(DiscoveryOptions.IP)
if ip == '127.0.0.1':
ip = f'192.168.186.3'
ip = f'192.168.{new_subnet}.3'
discovery_server = f'&fast_discovery_server_value={self.conf.get_discovery_str(id, ip, port)}'

if self.conf.get(DiscoveryOptions.ENABLED):
Expand All @@ -171,17 +175,27 @@ class Turtlebot4Setup():
rmw_implementation,
discovery_server,
discovery_server_enabled)) + \
shlex.split('-X POST http://192.168.186.2/ros-config-save-main')
shlex.split(f'-X POST http://192.168.{initial_subnet}.2/ros-config-save-main')

result = subprocess.run(command, capture_output=True)

# If the curl command fails then return and do not set any more settings.
if (result.returncode != 0):
return (result.returncode, "Error writing ROS settings to Create3\n\n" + result.stderr.decode("utf-8"))

# Set subnet on Create3
new_wired_subnet = f'new_wired_subnet={self.conf.get(DiscoveryOptions.SUBNET)}'
command = shlex.split(f'curl -d "{new_wired_subnet}" -X POST http://192.168.{initial_subnet}.2/beta-wired-subnet-save')

result = subprocess.run(command, capture_output=True)

# If the curl command fails then return and do not set any more settings.
if (result.returncode != 0):
return (result.returncode, "Error writing subnet settings to Create3\n\n" + result.stderr.decode("utf-8"))

# Set time syncing to Raspberry PI
config = f'config=server 192.168.186.3 prefer iburst minpoll 4 maxpoll 6 # Use RPi4 server'
command = shlex.split(f'curl -d "{config}" -X POST http://192.168.186.2/beta-ntp-conf-save')
config = f'config=server 192.168.{new_subnet}.3 prefer iburst minpoll 4 maxpoll 6 # Use RPi4 server'
command = shlex.split(f'curl -d "{config}" -X POST http://192.168.{initial_subnet}.2/beta-ntp-conf-save')

result = subprocess.run(command, capture_output=True)

Expand All @@ -190,7 +204,7 @@ class Turtlebot4Setup():
return (result.returncode, "Error writing NTP settings to Create3\n\n" + result.stderr.decode("utf-8"))

# Reboot the Create3
result = subprocess.run(shlex.split('curl -X POST http://192.168.186.2/api/reboot'), capture_output=True)
result = subprocess.run(shlex.split(f'curl -X POST http://192.168.{initial_subnet}.2/api/reboot'), capture_output=True)

# If the curl command fails then return and indicate the error.
if (result.returncode != 0):
Expand All @@ -202,9 +216,9 @@ class Turtlebot4Setup():

return (0, "Success")

def apply_wifi_settings(self):
# Run netplan apply if WiFi options have changed
if len(self.get_settings_diff(WifiOptions)) > 0:
def apply_pi_network_settings(self):
if len(self.get_settings_diff(WifiOptions)) > 0 or len(self.get_settings_diff(DiscoveryOptions)) > 0:
# Run netplan apply if WiFi options or Discovery options (for subnet) have changed
subprocess.run(shlex.split('sudo netplan apply'))
os.system('sudo reboot')

Expand Down

0 comments on commit 4b0a568

Please sign in to comment.