diff --git a/software/reference/design_reference/UI Design/maps_loading.svg b/software/reference/design_reference/UI Design/maps_loading.svg
new file mode 100644
index 0000000..6d792c6
--- /dev/null
+++ b/software/reference/design_reference/UI Design/maps_loading.svg
@@ -0,0 +1,4382 @@
+
+
+
+
diff --git a/software/ros_packages/ground_station/src/Framework/MapSystems/RoverMap.py b/software/ros_packages/ground_station/src/Framework/MapSystems/RoverMap.py
index d33a124..2321b34 100644
--- a/software/ros_packages/ground_station/src/Framework/MapSystems/RoverMap.py
+++ b/software/ros_packages/ground_station/src/Framework/MapSystems/RoverMap.py
@@ -26,8 +26,12 @@ from io import StringIO, BytesIO
import os
import time
import PIL.ImageDraw
+import PIL.Image
+import PIL.ImageFont
import signing
import RoverMapHelper as MapHelper
+import cv2
+import numpy as np
#####################################
# Constants
@@ -36,7 +40,8 @@ _KEYS = []
# Number of pixels in half the earth's circumference at zoom = 21
_EARTHPIX = 268435456
# Number of decimal places for rounding coordinates
-_DEGREE_PRECISION = 4
+_DEGREE_PRECISION = 6
+_PRECISION_FORMAT = '%.' + str(_DEGREE_PRECISION) + 'f'
# Larget tile we can grab without paying
_TILESIZE = 640
# Fastest rate at which we can download tiles without paying
@@ -113,14 +118,14 @@ class GMapsStitcher(object):
# Make the url string for polling
# GET request header gets appended to the string
urlbase = 'https://maps.googleapis.com/maps/api/staticmap?'
- urlbase += 'center=%.4f,%.4f&zoom=%d&maptype=%s'
+ urlbase += 'center=' + _PRECISION_FORMAT + ',' + _PRECISION_FORMAT + '&zoom=%d&maptype=%s'
urlbase += '&size=%dx%d&format=png&key=%s'
# Fill the formatting
specs = (self.helper.fast_round(latitude, _DEGREE_PRECISION),
self.helper.fast_round(longitude, _DEGREE_PRECISION),
self.zoom, self.maptype, _TILESIZE, _TILESIZE, _KEYS[0])
- filename = 'Resources/Maps/' + ('%.4f_%.4f_%d_%s_%d_%d_%s' % specs)
+ filename = 'Resources/Maps/' + ((_PRECISION_FORMAT + '_' + _PRECISION_FORMAT + '_%d_%s_%d_%d_%s') % specs)
filename += '.png'
# Tile Image object
@@ -165,10 +170,10 @@ class GMapsStitcher(object):
"""
# Magic Lines
return math.degrees(math.pi / 2 - 2 * math.atan(math.exp(((lat_pixels +
- self.helper.pixels_to_degrees(
- (iterator - self.num_tiles /
- 2) * _TILESIZE, self.zoom)) -
- _EARTHPIX) / _PIXRAD)))
+ self.helper.pixels_to_degrees(
+ (iterator - self.num_tiles /
+ 2) * _TILESIZE, self.zoom)) -
+ _EARTHPIX) / _PIXRAD)))
def fetch_tiles(self):
"""
@@ -188,14 +193,14 @@ class GMapsStitcher(object):
# latitude to desired radius in meters
if self.radius_meters is not None:
self.num_tiles = (int(
- round(2 * self.helper.pixels_to_meters(
- self.latitude, self.zoom) /
- (_TILESIZE / 2. / self.radius_meters))))
+ round(2 * self.helper.pixels_to_meters(
+ self.latitude, self.zoom) /
+ (_TILESIZE / 2. / self.radius_meters))))
lon_pixels = _EARTHPIX + self.longitude * math.radians(_PIXRAD)
sin_lat = math.sin(math.radians(self.latitude))
- lat_pixels = _EARTHPIX - _PIXRAD * math.log((1+sin_lat)/(1-sin_lat))/2
+ lat_pixels = _EARTHPIX - _PIXRAD * math.log((1 + sin_lat) / (1 - sin_lat)) / 2
self.big_size = self.num_tiles * _TILESIZE
big_image = self.helper.new_image(self.big_size, self.big_size)
@@ -231,7 +236,7 @@ class GMapsStitcher(object):
new_value = self.left_x - diff
if ((not new_value > 0) and
- (new_value < self.big_image.size[0] - self.width)):
+ (new_value < self.big_image.size[0] - self.width)):
return self.left_x
else:
return new_value
@@ -243,7 +248,7 @@ class GMapsStitcher(object):
new_value = self.upper_y - diff
if ((not new_value > 0) and
- (new_value < self.big_image.size[1] - self.height)):
+ (new_value < self.big_image.size[1] - self.height)):
return self.upper_y
else:
return new_value
@@ -266,8 +271,8 @@ class GMapsStitcher(object):
Function to move the object/rover
"""
x, y = self._get_cartesian(lat, lon)
- self._constrain_x(self.center_x-x)
- self._constrain_y(self.center_y-y)
+ self._constrain_x(self.center_x - x)
+ self._constrain_y(self.center_y - y)
self.update()
def _get_cartesian(self, lat, lon):
@@ -309,9 +314,9 @@ class GMapsStitcher(object):
x, y = self._get_cartesian(lat, lon)
draw = PIL.ImageDraw.Draw(self.big_image)
if shape is "ellipsis":
- draw.ellipsis((x-size, y-size, x+size, y+size), fill)
+ draw.ellipsis((x - size, y - size, x + size, y + size), fill)
else:
- draw.rectangle([x-size, y-size, x+size, y+size], fill)
+ draw.rectangle([x - size, y - size, x + size, y + size], fill)
self.update()
def center_display(self, lat, lon):
@@ -322,8 +327,8 @@ class GMapsStitcher(object):
self.center_x = x
self.center_y = y
- self.left_x = (self.center_x - (self.width/2))
- self.upper_y = (self.center_y - (self.height/2))
+ self.left_x = (self.center_x - (self.width / 2))
+ self.upper_y = (self.center_y - (self.height / 2))
self.update()
# def update_rover_map_location(self, lat, lon):
@@ -348,7 +353,9 @@ class OverlayImage(object):
self.width = width
self.height = height
self.big_image = None
+ self.big_image_copy = None
self.display_image = None
+ self.display_image_copy = None
self.indicator = None
self.helper = MapHelper.MapHelper()
@@ -356,12 +363,19 @@ class OverlayImage(object):
self.center_x = x
self.center_y = y
- self.left_x = (self.center_x - (self.width/2))
- self.upper_y = (self.center_y - (self.height/2))
+ self.left_x = (self.center_x - (self.width / 2))
+ self.upper_y = (self.center_y - (self.height / 2))
self.generate_image_files()
self.write_once = True
+ # Text Drawing Variables
+ self.font = cv2.FONT_HERSHEY_TRIPLEX
+ self.font_thickness = 1
+ self.font_baseline = 0
+
+ self.nav_coordinates_text_image = None
+
def generate_image_files(self):
"""
Creates big_image and display image sizes
@@ -370,8 +384,14 @@ class OverlayImage(object):
"""
self.big_image = self.helper.new_image(self.big_width, self.big_height,
True)
+
+ self.big_image_copy = self.big_image.copy()
+
self.display_image = self.helper.new_image(self.width, self.height,
True)
+
+ self.display_image_copy = self.display_image.copy()
+
self.generate_dot_and_hat()
self.indicator.save("location.png")
@@ -404,45 +424,65 @@ class OverlayImage(object):
return int(x), int(y)
- def update_new_location(self, latitude, longitude,
+ def update_new_location(self, latitude, longitude,
compass, navigation_list, landmark_list):
+ self.big_image = self.big_image_copy.copy()
+ self.display_image = self.display_image_copy.copy()
+
size = 5
draw = PIL.ImageDraw.Draw(self.big_image)
for element in navigation_list:
x, y = self._get_cartesian(float(element[2]), float(element[1]))
- draw.ellipse((x-size, y-size, x+size, y+size), fill="red")
+ draw.ellipse((x - size, y - size, x + size, y + size), fill="red")
# for element in landmark_list:
# x, y = self._get_cartesian(element[1], element[2])
# draw.ellipsis((x-size, y-size, x+size, y+size), fill="blue")
- self._draw_rover(longitude, latitude, compass)
- self.update()
+ self._draw_rover(latitude, longitude, compass)
+ self._draw_coordinate_text(latitude, longitude)
+ self.update(latitude, longitude)
return self.display_image
def generate_dot_and_hat(self):
- self.indicator = self.helper.new_image(100, 100, True)
- draw = PIL.ImageDraw.Draw(self.indicator)
- draw.ellipse((50-12, 50-12, 50+12, 50+12), fill="red")
- draw.line((25, 40, 50, 12), fill="red", width=7)
- draw.line((50, 12, 75, 40), fill="red", width=7)
+ self.indicator = PIL.Image.open("Resources/Images/rover.png").resize((50, 50))
+ # self.indicator = self.helper.new_image(100, 100, True)
+ # draw = PIL.ImageDraw.Draw(self.indicator)
+ # draw.ellipse((50 - 12, 50 - 12, 50 + 12, 50 + 12), fill="red")
+ # draw.line((25, 40, 50, 12), fill="red", width=7)
+ # draw.line((50, 12, 75, 40), fill="red", width=7)
+
+ def _draw_coordinate_text(self, latitude, longitude):
+ location_text = "LAT: %+014.9f\nLON: %+014.9f" % (latitude, longitude)
+ # location_text = "LAT: " + str(latitude) + "\nLON: " + str(longitude)
+
+ font = PIL.ImageFont.truetype("UbuntuMono-R", size=20)
+
+ new_image = PIL.Image.new('RGBA', (200, 45), "black")
+
+ draw = PIL.ImageDraw.Draw(new_image)
+
+ draw.multiline_text((5, 0), location_text, font=font)
+
+ self.display_image.paste(new_image, (0, 0))
def _draw_rover(self, lat, lon, angle=0):
x, y = self._get_cartesian(lat, lon)
- # print x,y
- # Center of the circle on the indicator is (12.5, 37.5)
- x = x - 50
- y = y - 50
+
+ x -= 25
+ y -= 25
+
rotated = self.indicator.copy()
- rotated = rotated.rotate(angle, expand=True)
- rotated.save("rotated.png")
+ rotated = rotated.rotate(angle, resample=PIL.Image.BICUBIC)
+ # rotated.save("rotated.png")
self.big_image.paste(rotated, (x, y), rotated)
if self.write_once:
- self.display_image.save("Something.png")
+ # self.display_image.save("Something.png")
self.write_once = False
- def update(self):
+ def update(self, latitude, longitude):
+
self.display_image.paste(self.big_image, (-self.left_x, -self.upper_y))
+ self._draw_coordinate_text(latitude, longitude)
def connect_signals_and_slots(self):
pass
-
diff --git a/software/ros_packages/ground_station/src/Framework/MapSystems/RoverMapCoordinator.py b/software/ros_packages/ground_station/src/Framework/MapSystems/RoverMapCoordinator.py
index bd45b33..5a86027 100644
--- a/software/ros_packages/ground_station/src/Framework/MapSystems/RoverMapCoordinator.py
+++ b/software/ros_packages/ground_station/src/Framework/MapSystems/RoverMapCoordinator.py
@@ -47,18 +47,20 @@ class RoverMapCoordinator(QtCore.QThread):
self.google_maps_object = None
self.map_image = None
+ self.map_image_copy = None
self.overlay_image = None
self.overlay_image_object = None
- self.map_pixmap = None
+ self.map_pixmap = QtGui.QPixmap.fromImage(ImageQt(Image.open("Resources/Images/maps_loading.png").resize((1280, 720), Image.BICUBIC)))
self.last_map_pixmap_cache_key = None
self.longitude = None
self.latitude = None
+ self.last_heading = 0
def run(self):
self.logger.debug("Starting Map Coordinator Thread")
-
+ self.pixmap_ready_signal.emit() # This gets us the loading map
while self.run_thread_flag:
if self.setup_map_flag:
self._map_setup()
@@ -83,7 +85,7 @@ class RoverMapCoordinator(QtCore.QThread):
720,
44.5675721667,
-123.2750535,
- 20, # FIXME: Used to be 18
+ 18, # FIXME: Used to be 18
'satellite',
None, 20)
self.overlay_image_object = (
@@ -97,12 +99,17 @@ class RoverMapCoordinator(QtCore.QThread):
def _get_map_image(self):
while self.map_image is None:
self.map_image = self.google_maps_object.display_image
+
+ if self.map_image:
+ self.map_image_copy = self.map_image.copy()
# self.overlay_image_object.update_new_location(44.567161,
# -123.278432,
# .7,
# [],
# [])
self.update_overlay()
+
+ self.map_image = self.map_image_copy.copy()
self.map_image.paste(self.overlay_image_object.display_image,
(0, 0),
self.overlay_image_object.display_image)
@@ -147,9 +154,8 @@ class RoverMapCoordinator(QtCore.QThread):
def update_overlay(self):
if self.latitude and self.longitude:
if not numpy.isnan(self.latitude) and not numpy.isnan(self.longitude):
-
- longitude = self.latitude
- latitude = self.longitude
+ latitude = float(self.latitude)
+ longitude = float(self.longitude)
navigation_list = self._get_table_elements(self.navigation_label)
# landmark_list = self._get_table_elements(self.landmark_label)
@@ -157,9 +163,10 @@ class RoverMapCoordinator(QtCore.QThread):
self.overlay_image = self.overlay_image_object.update_new_location(
latitude,
longitude,
- 70,
+ self.last_heading,
navigation_list,
landmark_list)
+ self.last_heading = (self.last_heading + 5) % 360
# self.overlay_image.save("something.png")
def gps_position_updated_callback(self, data):
diff --git a/software/ros_packages/ground_station/src/Resources/Images/maps_loading.png b/software/ros_packages/ground_station/src/Resources/Images/maps_loading.png
new file mode 100644
index 0000000..3e8ae52
Binary files /dev/null and b/software/ros_packages/ground_station/src/Resources/Images/maps_loading.png differ
diff --git a/software/ros_packages/ground_station/src/Resources/Images/rover.png b/software/ros_packages/ground_station/src/Resources/Images/rover.png
new file mode 100644
index 0000000..fa76398
Binary files /dev/null and b/software/ros_packages/ground_station/src/Resources/Images/rover.png differ
diff --git a/software/ros_packages/ground_station/src/Resources/Ui/left_screen.ui b/software/ros_packages/ground_station/src/Resources/Ui/left_screen.ui
index 7fb73dc..e55878d 100644
--- a/software/ros_packages/ground_station/src/Resources/Ui/left_screen.ui
+++ b/software/ros_packages/ground_station/src/Resources/Ui/left_screen.ui
@@ -1392,226 +1392,10 @@ N/A
0
-
+
- Science Readouts
+ SSH Console
-
- -
-
-
-
-
-
-
- 12
- 75
- true
-
-
-
- Soil Probe
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
-
- Soil Temperature:
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
- -
-
-
- N/A
-
-
-
- -
-
-
- Soil PH:
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
- -
-
-
- N/A
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
-
-
- Read Soil Probe
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- -
-
-
-
-
-
-
- 12
- 75
- true
-
-
-
- Dust Sensor
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
-
- Small Dust Present:
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
- -
-
-
- Large Dust Present:
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
- -
-
-
- False
-
-
-
- -
-
-
- False
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
diff --git a/software/ros_packages/rover_control/src/control_coordinators/drive_coordinator.py b/software/ros_packages/rover_control/src/control_coordinators/drive_coordinator.py
index c0e92f0..15df4cb 100755
--- a/software/ros_packages/rover_control/src/control_coordinators/drive_coordinator.py
+++ b/software/ros_packages/rover_control/src/control_coordinators/drive_coordinator.py
@@ -83,7 +83,7 @@ class DriveCoordinator(object):
try:
self.process_drive_commands()
except Exception, error:
- print "Error occurred:", error
+ print "COORDINATOR: Error occurred:", error
time_diff = time() - start_time
diff --git a/software/ros_packages/rover_control/src/iris_controller/iris_controller.py b/software/ros_packages/rover_control/src/iris_controller/iris_controller.py
index 3266206..1b0849c 100755
--- a/software/ros_packages/rover_control/src/iris_controller/iris_controller.py
+++ b/software/ros_packages/rover_control/src/iris_controller/iris_controller.py
@@ -121,7 +121,7 @@ class IrisController(object):
self.iris_last_seen_time = time()
except Exception, error:
- print "Error occurred:", error
+ print "IRIS: Error occurred:", error
return
if (time() - self.iris_last_seen_time) > IRIS_LAST_SEEN_TIMEOUT:
diff --git a/software/ros_packages/rover_odometry/msg/odom.msg b/software/ros_packages/rover_odometry/msg/odom.msg
new file mode 100644
index 0000000..e69de29