01234567890123456789012345678901234567890123456789012345678901234567890123456789
567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 286287288289290291292293294295296297298299300301302303304305 306307308309310311 312313314315316317318 319320 321322323324325326327328329330 331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 366367368369370371372373374375376377378379380381382383384385386387 636637638639640641642643644645646647648649650651652653654655 656657658659660661662663664665666667668669670671672673674675 689690691692693694695696697698699700701702703704705706707708 709710711712713714715716717718719720721722723724725726727728 12981299130013011302130313041305130613071308130913101311131213131314131513161317 13181319132013211322132313241325132613271328132913301331133213331334133513361337 |
<----SKIPPED LINES---->
import random
import struct
import subprocess
import sys
import termios
import time
import psutil
import serial
import serial.tools.list_ports
from pySerialTransfer import pySerialTransfer
from constants import (
RASPBERRY_PI, MESSAGEBOARD_PATH, WEBSERVER_PATH, SHUTDOWN_TEXT)
import messageboard
ARDUINO_LOG = 'arduino_log.txt'
ARDUINO_ROLLING_LOG = 'arduino_rolling_log.txt'
SERIALS_LOG = 'arduino_serials_log.txt'
VERBOSE = False # log additional fine-grained details into ARDUINO_LOG
LOG_SERIALS = False # log serial data sent from Arduino to ARDUINO_LOG
SIMULATE_ARDUINO = False
REMOTE_DISPLAY_MODE = 'display_mode.txt'
SERVO_SIMULATED_IN = 'servo_in.txt'
SERVO_SIMULATED_OUT = 'servo_out.txt'
REMOTE_SIMULATED_IN = 'remote_in.txt'
REMOTE_SIMULATED_OUT = 'remote_out.txt'
if RASPBERRY_PI:
ARDUINO_LOG = MESSAGEBOARD_PATH + ARDUINO_LOG
SERIALS_LOG = MESSAGEBOARD_PATH + SERIALS_LOG
SERVO_SIMULATED_OUT = MESSAGEBOARD_PATH + SERVO_SIMULATED_OUT
SERVO_SIMULATED_IN = MESSAGEBOARD_PATH + SERVO_SIMULATED_IN
REMOTE_SIMULATED_OUT = MESSAGEBOARD_PATH + REMOTE_SIMULATED_OUT
REMOTE_SIMULATED_IN = MESSAGEBOARD_PATH + REMOTE_SIMULATED_IN
REMOTE_DISPLAY_MODE = MESSAGEBOARD_PATH + REMOTE_DISPLAY_MODE
ARDUINO_ROLLING_LOG = WEBSERVER_PATH + ARDUINO_ROLLING_LOG
CONNECTION_FLAG_BLUETOOTH = 1
CONNECTION_FLAG_USB = 2
CONNECTION_FLAG_SIMULATED = 3
RASPBERRY_PI = psutil.sys.platform.title() == 'Linux'
SN_SERVO = '5583834303435111C1A0'
SERVO_CONNECTION = (CONNECTION_FLAG_BLUETOOTH, (2, '98:D3:11:FC:42:16', 1))
SN_REMOTE = '75835343130351802272'
REMOTE_CONNECTION = (CONNECTION_FLAG_BLUETOOTH, (1, '98:D3:91:FD:B3:C9', 1))
LASER_OFF = (False, False, False)
<----SKIPPED LINES---->
Args:
format_string: String of the form expected by struct.pack
bytes_read: if passed, the bytes that are read are appended to the list.
Returns:
Tuple of values matching that as identified in format_string.
"""
if self.connection_type == CONNECTION_FLAG_SIMULATED:
if (
self.__simulated_reads__ and
# time for next
time.time() - self.start_time > self.__simulated_reads__[0][0]):
next_line = self.__simulated_reads__.pop(0)
return next_line[1]
return ()
if not format_string:
format_string = self.read_format
try:
data = Read(self.link, format_string, bytes_read=bytes_read)
except OSError as e:
failure_message = 'Failed to read from %s: %s' % (self.name, e)
if self.error_pin:
self.to_parent_q.put(('pin', (self.error_pin, True, failure_message)))
self.Reopen(log_message=failure_message)
return self.Read(format_string=format_string)
self.last_read = time.time()
if data:
self.last_receipt = time.time()
if LOG_SERIALS:
ts = time.time() - self.start_time
str_data = str(
['%7.2f' % d if isinstance(d, float) else str(d) for d in data])
with open(SERIALS_LOG, 'a') as f:
f.write('%10.3f RECD@%s: %s\n' % (ts, self.name, str_data))
if (
self.read_timeout and
self.last_read - self.last_receipt > self.read_timeout):
failure_message = (
'Heartbeat not received in %.2f seconds (expected: %.2f) on %s' % (
self.last_read - self.last_receipt, self.read_timeout, self.name))
if self.error_pin:
self.to_parent_q.put(('pin', (self.error_pin, True, failure_message)))
self.Reopen(log_message=failure_message)
return self.Read(format_string=format_string)
return data
def Write(self, values, format_string=None):
"""Writes to an open serial.
Writes to an open serial values as identified in the format_string
provided here, or if not provided in this call, as saved on the
Serial instance. If an OSError exception is detected, this method
will attempt to reopen the connection.
Args:
values: tuple of values to send matching that as identified
in format_string.
format_string: String of the form expected by struct.pack
"""
ts = time.time() - self.start_time
str_values = str(
['%7.2f' % v if isinstance(v, float) else str(v) for v in values])
if self.connection_type == CONNECTION_FLAG_SIMULATED:
with open(self.connection_tuple[1], 'a') as f:
f.write('%10.3f: %s\n' % (ts, str_values))
return
if not format_string:
format_string = self.write_format
try:
Write(self.link, values, format_string)
except OSError as e:
failure_message = 'Failed to write: %s' % e
if self.error_pin:
self.to_parent_q.put(('pin', (self.error_pin, True, failure_message)))
self.Reopen(log_message=failure_message)
self.Write(values)
if LOG_SERIALS:
with open(SERIALS_LOG, 'a') as f:
f.write('%10.3f SENT@%s: %s\n' % (ts, self.name, str_values))
def HasReset(self):
"""Indicates exactly once whether serial has reset since last called."""
if self.connection_type == CONNECTION_FLAG_SIMULATED:
raise NotImplementedError('Not implemented for simulations')
flag = self.reset_flag
self.reset_flag = False
return flag
def RunCommand(cmd, sleep_seconds=1, log=True):
"""Runs shell command, checking if it completed within timeout."""
conn = subprocess.Popen(cmd, shell=True)
time.sleep(sleep_seconds)
conn.poll()
if conn.returncode is None:
Log('ERROR: %s did not complete within %d seconds'
% (cmd, sleep_seconds))
<----SKIPPED LINES---->
azimuth = angles['azimuth_degrees']
altitude = angles['altitude_degrees']
return (azimuth, altitude)
def DrainQueue(q):
"""Empties a queue, returning the last-retrieved value."""
value = None
while not q.empty():
value = q.get(block=False)
return value
def InitialMessageValues(q):
"""Initializes the arduino main processes with values from messageboard."""
v = DrainQueue(q)
if v:
return v
return {}, {}, {}, {}
def ServoTestOrdinal(link):
"""Point laser at each of 0, 90, 180, 270 and hold with different colors."""
link.Write((0, 0, *LASER_ALL))
time.sleep(1)
link.Write((90, 0, *LASER_RED))
time.sleep(1)
link.Write((180, 0, *LASER_GREEN))
time.sleep(1)
link.Write((270, 0, *LASER_BLUE))
time.sleep(1)
def ServoTestSweep(link, altitude=45):
"""Sweep red laser around 360 degrees."""
for azimuth in range(0, 360, 10):
link.Write((azimuth, altitude, *LASER_RED))
time.sleep(WRITE_DELAY_TIME)
def ServoMain(to_arduino_q, to_parent_q, shutdown):
<----SKIPPED LINES---->
to_parent_q.cancel_join_thread()
# write_format: azimuth, altitude, R, G, & B intensity
# read heartbeat: millis
link = Serial(
*SERVO_CONNECTION, read_timeout=60,
error_pin=messageboard.GPIO_ERROR_ARDUINO_SERVO_CONNECTION,
to_parent_q=to_parent_q,
read_format='l', write_format='ff???', name='Servo')
link.Open()
last_flight = {}
last_angles = (0, 0)
flight, json_desc_dict, configuration, additional_attr = InitialMessageValues(
to_arduino_q)
next_read = 0
next_write = 0
now = GetNow(json_desc_dict, additional_attr)
while not shutdown.value:
if not to_arduino_q.empty():
flight, json_desc_dict, configuration, additional_attr = to_arduino_q.get(
block=False)
if 'test_servos_ordinal' in configuration:
messageboard.RemoveSetting(configuration, 'test_servos_ordinal')
ServoTestOrdinal(link)
elif 'test_servos_sweep' in configuration:
messageboard.RemoveSetting(configuration, 'test_servos_sweep')
ServoTestSweep(link)
new_flight = DifferentFlights(flight, last_flight)
if new_flight:
Log('Flight changed from %s to %s' % (
messageboard.DisplayFlightNumber(last_flight),
messageboard.DisplayFlightNumber(flight)
), ser=link)
# Turn off laser so line isn't traced while it moves to new position
link.Write((*last_angles, *LASER_OFF))
<----SKIPPED LINES---->
*REMOTE_CONNECTION, read_timeout=60,
error_pin=messageboard.GPIO_ERROR_ARDUINO_REMOTE_CONNECTION,
to_parent_q=to_parent_q,
read_format=read_format_string, write_format=write_format_string,
name='Remote')
link.Open()
# Read in the saved display mode, if it exists
display_mode = messageboard.ReadFile(REMOTE_DISPLAY_MODE, log_exception=False)
if not display_mode:
display_mode = DISP_LAST_FLIGHT_NUMB_ORIG_DEST
else:
display_mode = int(display_mode)
flight, json_desc_dict, configuration, additional_attr = InitialMessageValues(
to_arduino_q)
next_read = 0
next_write = 0
while not shutdown.value:
if not to_arduino_q.empty():
to_arduino_message = to_arduino_q.get(block=False)
(flight, json_desc_dict,
configuration, additional_attr) = to_arduino_message
if 'test_remote' in configuration:
messageboard.RemoveSetting(configuration, 'test_remote')
def TestDisplayMode(m):
SendRemoteMessage(
flight, json_desc_dict, configuration, additional_attr,
m, write_keys, write_format_tuple, link)
time.sleep(1)
TestDisplayMode(DISP_LAST_FLIGHT_NUMB_ORIG_DEST)
TestDisplayMode(DISP_LAST_FLIGHT_AZIMUTH_ELEVATION)
TestDisplayMode(DISP_FLIGHT_COUNT_LAST_SEEN)
TestDisplayMode(DISP_RADIO_RANGE)
if time.time() >= next_write:
<----SKIPPED LINES---->
|
01234567890123456789012345678901234567890123456789012345678901234567890123456789
567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702 716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756 13261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366 |
<----SKIPPED LINES---->
import random
import struct
import subprocess
import sys
import termios
import time
import psutil
import serial
import serial.tools.list_ports
from pySerialTransfer import pySerialTransfer
from constants import (
RASPBERRY_PI, MESSAGEBOARD_PATH, WEBSERVER_PATH, SHUTDOWN_TEXT)
import messageboard
ARDUINO_LOG = 'arduino_log.txt'
ARDUINO_ROLLING_LOG = 'arduino_rolling_log.txt'
#SERIALS_LOG = 'arduino_serials_log.txt'
VERBOSE = False # log additional fine-grained details into ARDUINO_LOG
LOG_SERIALS = False # log serial data sent from Arduino to ARDUINO_LOG
SIMULATE_ARDUINO = False
REMOTE_DISPLAY_MODE = 'display_mode.txt'
SERVO_SIMULATED_IN = 'servo_in.txt'
SERVO_SIMULATED_OUT = 'servo_out.txt'
REMOTE_SIMULATED_IN = 'remote_in.txt'
REMOTE_SIMULATED_OUT = 'remote_out.txt'
if RASPBERRY_PI:
ARDUINO_LOG = MESSAGEBOARD_PATH + ARDUINO_LOG
#SERIALS_LOG = MESSAGEBOARD_PATH + SERIALS_LOG
SERVO_SIMULATED_OUT = MESSAGEBOARD_PATH + SERVO_SIMULATED_OUT
SERVO_SIMULATED_IN = MESSAGEBOARD_PATH + SERVO_SIMULATED_IN
REMOTE_SIMULATED_OUT = MESSAGEBOARD_PATH + REMOTE_SIMULATED_OUT
REMOTE_SIMULATED_IN = MESSAGEBOARD_PATH + REMOTE_SIMULATED_IN
REMOTE_DISPLAY_MODE = MESSAGEBOARD_PATH + REMOTE_DISPLAY_MODE
ARDUINO_ROLLING_LOG = WEBSERVER_PATH + ARDUINO_ROLLING_LOG
CONNECTION_FLAG_BLUETOOTH = 1
CONNECTION_FLAG_USB = 2
CONNECTION_FLAG_SIMULATED = 3
RASPBERRY_PI = psutil.sys.platform.title() == 'Linux'
SN_SERVO = '5583834303435111C1A0'
SERVO_CONNECTION = (CONNECTION_FLAG_BLUETOOTH, (2, '98:D3:11:FC:42:16', 1))
SN_REMOTE = '75835343130351802272'
REMOTE_CONNECTION = (CONNECTION_FLAG_BLUETOOTH, (1, '98:D3:91:FD:B3:C9', 1))
LASER_OFF = (False, False, False)
<----SKIPPED LINES---->
Args:
format_string: String of the form expected by struct.pack
bytes_read: if passed, the bytes that are read are appended to the list.
Returns:
Tuple of values matching that as identified in format_string.
"""
if self.connection_type == CONNECTION_FLAG_SIMULATED:
if (
self.__simulated_reads__ and
# time for next
time.time() - self.start_time > self.__simulated_reads__[0][0]):
next_line = self.__simulated_reads__.pop(0)
return next_line[1]
return ()
if not format_string:
format_string = self.read_format
try:
data = Read(self.link, format_string, bytes_read=bytes_read)
# on OSError, record a disconnection and attempt to reconnect & re-read
except OSError as e:
failure_message = 'Failed to read from %s: %s' % (self.name, e)
if self.error_pin:
self.to_parent_q.put(('pin', (self.error_pin, True, failure_message)))
self.Reopen(log_message=failure_message)
return self.Read(format_string=format_string)
self.last_read = time.time()
if data:
self.last_receipt = time.time()
if LOG_SERIALS:
ts = time.time() - self.start_time
str_data = str(
['%7.2f' % d if isinstance(d, float) else str(d) for d in data])
message = '%10.3f RECD@%s: %s\n' % (ts, self.name, str_data)
Log(message)
#with open(SERIALS_LOG, 'a') as f:
# f.write(message)
# If we haven't received data (despite reading) in more than the timeout,
# close and reopen.
if (
self.read_timeout and
self.last_read - self.last_receipt > self.read_timeout):
failure_message = (
'Heartbeat not received in %.2f seconds (expected: %.2f) on %s' % (
self.last_read - self.last_receipt, self.read_timeout, self.name))
if self.error_pin:
self.to_parent_q.put(('pin', (self.error_pin, True, failure_message)))
self.Reopen(log_message=failure_message)
return self.Read(format_string=format_string)
if self.read_timeout and VERBOSE:
Log('%s: last_read: %.1f; last_receipt: %.1f; '
'delta: %.1f; read_timeout: %.1f' % (
self.name, self.last_read, self.last_receipt,
self.last_read - self.last_receipt, self.read_timeout))
elif VERBOSE:
Log('%s: read_timeout: %s' % (self.name, self.read_timeout))
return data
def Write(self, values, format_string=None):
"""Writes to an open serial.
Writes to an open serial values as identified in the format_string
provided here, or if not provided in this call, as saved on the
Serial instance. If an OSError exception is detected, this method
will attempt to reopen the connection.
Args:
values: tuple of values to send matching that as identified
in format_string.
format_string: String of the form expected by struct.pack
"""
ts = time.time() - self.start_time
str_values = str(
['%7.2f' % v if isinstance(v, float) else str(v) for v in values])
if self.connection_type == CONNECTION_FLAG_SIMULATED:
with open(self.connection_tuple[1], 'a') as f:
f.write('%10.3f: %s\n' % (ts, str_values))
return
if not format_string:
format_string = self.write_format
try:
Write(self.link, values, format_string)
except OSError as e:
failure_message = 'Failed to write: %s' % e
if self.error_pin:
self.to_parent_q.put(('pin', (self.error_pin, True, failure_message)))
self.Reopen(log_message=failure_message)
self.Write(values)
if LOG_SERIALS:
message = '%10.3f SENT@%s: %s\n' % (ts, self.name, str_values)
Log(message)
#with open(SERIALS_LOG, 'a') as f:
# f.write(message)
def HasReset(self):
"""Indicates exactly once whether serial has reset since last called."""
if self.connection_type == CONNECTION_FLAG_SIMULATED:
raise NotImplementedError('Not implemented for simulations')
flag = self.reset_flag
self.reset_flag = False
return flag
def RunCommand(cmd, sleep_seconds=1, log=True):
"""Runs shell command, checking if it completed within timeout."""
conn = subprocess.Popen(cmd, shell=True)
time.sleep(sleep_seconds)
conn.poll()
if conn.returncode is None:
Log('ERROR: %s did not complete within %d seconds'
% (cmd, sleep_seconds))
<----SKIPPED LINES---->
azimuth = angles['azimuth_degrees']
altitude = angles['altitude_degrees']
return (azimuth, altitude)
def DrainQueue(q):
"""Empties a queue, returning the last-retrieved value."""
value = None
while not q.empty():
value = q.get(block=False)
return value
def InitialMessageValues(q):
"""Initializes the arduino main processes with values from messageboard."""
v = DrainQueue(q)
if v:
return v
return {}, {}, {}, {}
def SetLoggingGlobals(configuration):
"""Sets the logging globals based on values in the config file."""
global VERBOSE
VERBOSE = 'arduino_verbose' in configuration
global LOG_SERIALS
LOG_SERIALS = 'arduino_log_serials' in configuration
def ServoTestOrdinal(link):
"""Point laser at each of 0, 90, 180, 270 and hold with different colors."""
link.Write((0, 0, *LASER_ALL))
time.sleep(1)
link.Write((90, 0, *LASER_RED))
time.sleep(1)
link.Write((180, 0, *LASER_GREEN))
time.sleep(1)
link.Write((270, 0, *LASER_BLUE))
time.sleep(1)
def ServoTestSweep(link, altitude=45):
"""Sweep red laser around 360 degrees."""
for azimuth in range(0, 360, 10):
link.Write((azimuth, altitude, *LASER_RED))
time.sleep(WRITE_DELAY_TIME)
def ServoMain(to_arduino_q, to_parent_q, shutdown):
<----SKIPPED LINES---->
to_parent_q.cancel_join_thread()
# write_format: azimuth, altitude, R, G, & B intensity
# read heartbeat: millis
link = Serial(
*SERVO_CONNECTION, read_timeout=60,
error_pin=messageboard.GPIO_ERROR_ARDUINO_SERVO_CONNECTION,
to_parent_q=to_parent_q,
read_format='l', write_format='ff???', name='Servo')
link.Open()
last_flight = {}
last_angles = (0, 0)
flight, json_desc_dict, configuration, additional_attr = InitialMessageValues(
to_arduino_q)
next_read = 0
next_write = 0
now = GetNow(json_desc_dict, additional_attr)
while not shutdown.value:
SetLoggingGlobals(configuration)
if not to_arduino_q.empty():
flight, json_desc_dict, configuration, additional_attr = to_arduino_q.get(
block=False)
if 'test_servos_ordinal' in configuration:
messageboard.RemoveSetting(configuration, 'test_servos_ordinal')
ServoTestOrdinal(link)
elif 'test_servos_sweep' in configuration:
messageboard.RemoveSetting(configuration, 'test_servos_sweep')
ServoTestSweep(link)
new_flight = DifferentFlights(flight, last_flight)
if new_flight:
Log('Flight changed from %s to %s' % (
messageboard.DisplayFlightNumber(last_flight),
messageboard.DisplayFlightNumber(flight)
), ser=link)
# Turn off laser so line isn't traced while it moves to new position
link.Write((*last_angles, *LASER_OFF))
<----SKIPPED LINES---->
*REMOTE_CONNECTION, read_timeout=60,
error_pin=messageboard.GPIO_ERROR_ARDUINO_REMOTE_CONNECTION,
to_parent_q=to_parent_q,
read_format=read_format_string, write_format=write_format_string,
name='Remote')
link.Open()
# Read in the saved display mode, if it exists
display_mode = messageboard.ReadFile(REMOTE_DISPLAY_MODE, log_exception=False)
if not display_mode:
display_mode = DISP_LAST_FLIGHT_NUMB_ORIG_DEST
else:
display_mode = int(display_mode)
flight, json_desc_dict, configuration, additional_attr = InitialMessageValues(
to_arduino_q)
next_read = 0
next_write = 0
while not shutdown.value:
SetLoggingGlobals(configuration)
if not to_arduino_q.empty():
to_arduino_message = to_arduino_q.get(block=False)
(flight, json_desc_dict,
configuration, additional_attr) = to_arduino_message
if 'test_remote' in configuration:
messageboard.RemoveSetting(configuration, 'test_remote')
def TestDisplayMode(m):
SendRemoteMessage(
flight, json_desc_dict, configuration, additional_attr,
m, write_keys, write_format_tuple, link)
time.sleep(1)
TestDisplayMode(DISP_LAST_FLIGHT_NUMB_ORIG_DEST)
TestDisplayMode(DISP_LAST_FLIGHT_AZIMUTH_ELEVATION)
TestDisplayMode(DISP_FLIGHT_COUNT_LAST_SEEN)
TestDisplayMode(DISP_RADIO_RANGE)
if time.time() >= next_write:
<----SKIPPED LINES---->
|