-
Notifications
You must be signed in to change notification settings - Fork 231
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2893 from JdeRobot/montecarlo_visual_loc
Montecarlo Visual Loc
- Loading branch information
Showing
33 changed files
with
770 additions
and
2,179 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes
47 changes: 0 additions & 47 deletions
47
exercises/static/exercises/montecarlo_visual_loc/launch/roomba_1_house_visual_loc.world
This file was deleted.
Oops, something went wrong.
14 changes: 0 additions & 14 deletions
14
exercises/static/exercises/montecarlo_visual_loc/launch/visual_loc_headless.launch
This file was deleted.
Oops, something went wrong.
137 changes: 137 additions & 0 deletions
137
exercises/static/exercises/montecarlo_visual_loc/python_template/ros2_humble/GUI.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
import json | ||
#import math | ||
#import matplotlib.pyplot as plt | ||
import threading | ||
import cv2 | ||
import base64 | ||
|
||
from gui_interfaces.general.measuring_threading_gui import MeasuringThreadingGUI | ||
from console_interfaces.general.console import start_console | ||
from map import Map | ||
from HAL import getPose3d | ||
|
||
# Graphical User Interface Class | ||
|
||
class GUI(MeasuringThreadingGUI): | ||
|
||
def __init__(self, host="ws://127.0.0.1:2303"): | ||
super().__init__(host) | ||
|
||
# Payload vars | ||
self.payload = {'image': '', 'map': '', 'user': '', 'particles': ''} | ||
self.init_coords = (171, 63) | ||
self.start_coords = (201, 85.5) | ||
self.map = Map(getPose3d) | ||
|
||
# Particles | ||
self.particles = [] | ||
# Image | ||
self.image = None | ||
self.image_lock = threading.Lock() | ||
self.image_updated = False | ||
# User position | ||
self.user_position = (0, 0) | ||
self.user_angle = (0, 0) | ||
|
||
self.start() | ||
|
||
# Prepares and sends a map to the websocket server | ||
def update_gui(self): | ||
|
||
# Payload Image Message | ||
payload_image = self.payloadImage() | ||
self.payload["image"] = json.dumps(payload_image) | ||
|
||
# Payload Map Message | ||
pos_message = self.map.getRobotCoordinates() | ||
if pos_message == self.init_coords: | ||
pos_message = self.start_coords | ||
ang_message = self.map.getRobotAngle() | ||
pos_message = str(pos_message + ang_message) | ||
self.payload["map"] = pos_message | ||
|
||
# Payload User Message | ||
pos_message_user = self.user_position | ||
ang_message_user = self.user_angle | ||
pos_message_user = pos_message_user + ang_message_user | ||
pos_message_user = str(pos_message_user) | ||
self.payload["user"] = pos_message_user | ||
|
||
# Payload Particles Message | ||
if self.particles: | ||
self.payload["particles"] = json.dumps(self.particles) | ||
else: | ||
self.payload["particles"] = json.dumps([]) | ||
|
||
message = json.dumps(self.payload) | ||
self.send_to_client(message) | ||
|
||
# Function to prepare image payload | ||
# Encodes the image as a JSON string and sends through the WS | ||
def payloadImage(self): | ||
with self.image_lock: | ||
image_updated = self.image_updated | ||
image_to_be_shown = self.image | ||
|
||
image = image_to_be_shown | ||
payload = {'image': '', 'shape': ''} | ||
|
||
if not image_updated: | ||
return payload | ||
|
||
shape = image.shape | ||
frame = cv2.imencode('.JPEG', image)[1] | ||
encoded_image = base64.b64encode(frame) | ||
|
||
payload['image'] = encoded_image.decode('utf-8') | ||
payload['shape'] = shape | ||
|
||
with self.image_lock: | ||
self.image_updated = False | ||
|
||
return payload | ||
|
||
def showPosition(self, x, y, angle): | ||
scale_y = 15; offset_y = 63 | ||
y = scale_y * y + offset_y | ||
|
||
scale_x = -30; offset_x = 171 | ||
x = scale_x * x + offset_x | ||
|
||
self.user_position = x, y | ||
self.user_angle = angle, | ||
|
||
def showParticles(self, particles): | ||
if particles: | ||
self.particles = particles | ||
scale_y = 15 | ||
offset_y = 63 | ||
scale_x = -30 | ||
offset_x = 171 | ||
for particle in self.particles: | ||
particle[1] = scale_y * particle[1] + offset_y | ||
particle[0] = scale_x * particle[0] + offset_x | ||
else: | ||
self.particles = [] | ||
|
||
# Function to set the next image to be sent | ||
def setImage(self, image): | ||
with self.image_lock: | ||
self.image = image | ||
self.image_updated = True | ||
|
||
host = "ws://127.0.0.1:2303" | ||
gui = GUI(host) | ||
|
||
# Redirect the console | ||
start_console() | ||
|
||
# Expose to the user | ||
def showImage(img): | ||
gui.setImage(img) | ||
|
||
def showPosition(x, y, angle): | ||
gui.showPosition(x, y, angle) | ||
|
||
def showParticles(particles): | ||
gui.showParticles(particles) |
52 changes: 52 additions & 0 deletions
52
exercises/static/exercises/montecarlo_visual_loc/python_template/ros2_humble/HAL.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import rclpy | ||
import threading | ||
import time | ||
|
||
from hal_interfaces.general.motors import MotorsNode | ||
from hal_interfaces.general.odometry import OdometryNode | ||
from hal_interfaces.general.camera import CameraNode | ||
|
||
# Hardware Abstraction Layer | ||
IMG_WIDTH = 320 | ||
IMG_HEIGHT = 240 | ||
|
||
freq = 30.0 | ||
|
||
print("HAL initializing", flush=True) | ||
if not rclpy.ok(): | ||
rclpy.init(args=None) | ||
|
||
### HAL INIT ### | ||
motor_node = MotorsNode("/cmd_vel", 4, 0.3) | ||
odometry_node = OdometryNode("/odom") | ||
camera_node = CameraNode("/camera/image_raw") | ||
|
||
# Spin nodes so that subscription callbacks load topic data | ||
executor = rclpy.executors.MultiThreadedExecutor() | ||
executor.add_node(odometry_node) | ||
executor.add_node(camera_node) | ||
def __auto_spin() -> None: | ||
while rclpy.ok(): | ||
executor.spin_once(timeout_sec=0) | ||
time.sleep(1/freq) | ||
executor_thread = threading.Thread(target=__auto_spin, daemon=True) | ||
executor_thread.start() | ||
|
||
# Pose | ||
def getPose3d(): | ||
return odometry_node.getPose3d() | ||
|
||
# Image | ||
def getImage(): | ||
image = camera_node.getImage() | ||
while image == None: | ||
image = camera_node.getImage() | ||
return image.data | ||
|
||
# Linear speed | ||
def setV(v): | ||
motor_node.sendV(float(v)) | ||
|
||
# Angular speed | ||
def setW(w): | ||
motor_node.sendW(float(w)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.