Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adaptations to Eloquent [Again] #533

Merged
merged 10 commits into from
Sep 19, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
from __future__ import print_function
import rclpy
from rclpy.clock import ROSClock
import numpy as np
import array

from rosbridge_library.internal import ros_loader

Expand All @@ -47,11 +49,11 @@
import sys
if sys.version_info >= (3, 0):
type_map = {
"bool": ["bool"],
"bool": ["bool", "boolean"],
"int": ["int8", "byte", "uint8", "char",
"int16", "uint16", "int32", "uint32",
"int64", "uint64", "float32", "float64"],
"float": ["float32", "float64", "double"],
"float": ["float32", "float64", "double", "float"],
"str": ["string"]
}
primitive_types = [bool, int, float]
Expand All @@ -70,21 +72,24 @@
primitive_types = [bool, int, long, float]
python2 = True

list_types = [list, tuple]
list_types = [list, tuple, np.ndarray, array.array]
ros_time_types = ["builtin_interfaces/Time", "builtin_interfaces/Duration"]
ros_primitive_types = ["bool", "byte", "char", "int8", "uint8", "int16",
ros_primitive_types = ["bool", "boolean", "byte", "char", "int8", "uint8", "int16",
"uint16", "int32", "uint32", "int64", "uint64",
"float32", "float64", "double", "string"]
"float32", "float64", "float", "double", "string"]
ros_header_types = ["Header", "std_msgs/Header", "roslib/Header"]
ros_binary_types = ["uint8[]", "char[]"]
list_tokens = re.compile('<(.+?)>')
bounded_array_tokens = re.compile('(.+)\[.*\]')
ros_binary_types_list_braces = [("uint8[]", re.compile(r'uint8\[[^\]]*\]')),
("char[]", re.compile(r'char\[[^\]]*\]'))]

binary_encoder = None
binary_encoder_type = 'default'
bson_only_mode = False



# TODO(@jubeira): configure module with a node handle.
# The original code doesn't seem to actually use these parameters.
def configure(node_handle=None):
Expand Down Expand Up @@ -133,15 +138,13 @@ def extract_values(inst):
raise InvalidMessageException(inst=inst)
return _from_inst(inst, rostype)


def populate_instance(msg, inst):
""" Returns an instance of the provided class, with its fields populated
according to the values in msg """
inst_type = msg_instance_type_repr(inst)

return _to_inst(msg, inst_type, inst_type, inst)


def msg_instance_type_repr(msg_inst):
"""Returns a string representation of a ROS2 message type from a message instance"""
# Message representation: '{package}.msg.{message_name}({fields})'.
Expand Down Expand Up @@ -173,7 +176,11 @@ def _from_inst(inst, rostype):

# Check for time or duration
if rostype in ros_time_types:
return {"secs": inst.secs, "nsecs": inst.nsecs}
try:
return {"sec": inst.sec, "nanosec": inst.nanosec}
except AttributeError:
return {"secs": inst.secs, "nsecs": inst.nsecs}


if(bson_only_mode is None):bson_only_mode = rospy.get_param('~bson_only_mode', False)
# Check for primitive types
Expand All @@ -198,7 +205,10 @@ def _from_list_inst(inst, rostype):
return []

# Remove the list indicators from the rostype
rostype = re.search(list_tokens, rostype).group(1)
try:
rostype = re.search(list_tokens, rostype).group(1)
except AttributeError:
rostype = re.search(bounded_array_tokens, rostype).group(1)

# Shortcut for primitives
if rostype in ros_primitive_types and not rostype in type_map.get('float'):
Expand All @@ -217,7 +227,6 @@ def _from_object_inst(inst, rostype):
msg[field_name] = _from_inst(field_inst, field_rostype)
return msg


def _to_inst(msg, rostype, roottype, inst=None, stack=[]):
# Check if it's uint8[], and if it's a string, try to b64decode
for binary_type, expression in ros_binary_types_list_braces:
Expand Down Expand Up @@ -270,8 +279,8 @@ def _to_time_inst(msg, rostype, inst=None):
else:
return None

# Copy across the fields
for field in ["secs", "nsecs"]:
# Copy across the fields, try ROS1 and ROS2 fieldnames
for field in ["secs", "nsecs", "sec", "nanosec"]:
try:
if field in msg:
setattr(inst, field, msg[field])
Expand All @@ -283,6 +292,11 @@ def _to_time_inst(msg, rostype, inst=None):

def _to_primitive_inst(msg, rostype, roottype, stack):
# Typecheck the msg
if type(msg) == int and rostype in type_map['float']:
# propably wrong parsing,
# fix that by casting the int to the expected float
msg = float(msg)

msgtype = type(msg)
if msgtype in primitive_types and rostype in type_map[msgtype.__name__]:
return msg
Expand All @@ -300,14 +314,21 @@ def _to_list_inst(msg, rostype, roottype, inst, stack):
if len(msg) == 0:
return []

if type(inst) is np.ndarray:
return list(inst.astype(float))

# Remove the list indicators from the rostype
rostype = re.search(list_tokens, rostype).group(1)
try:
rostype = re.search(list_tokens, rostype).group(1)
except AttributeError:
rostype = re.search(bounded_array_tokens, rostype).group(1)

# Call to _to_inst for every element of the list
return [_to_inst(x, rostype, roottype, None, stack) for x in msg]


def _to_object_inst(msg, rostype, roottype, inst, stack):

# Typecheck the msg
if type(msg) is not dict:
raise FieldTypeMismatchException(roottype, stack, rostype, type(msg))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ def _splittype(typestring):
splits = [x for x in typestring.split("/") if x]
if len(splits) == 3:
return (splits[0], splits[2])
if len(splits) == 2:
return (splits[0], splits[1])
raise InvalidTypeStringException(typestring)


Expand Down
7 changes: 3 additions & 4 deletions rosbridge_server/scripts/rosbridge_websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def __init__(self):
RosbridgeWebSocket.authenticate = self.declare_parameter('authenticate', False).value

port = self.declare_parameter('port', 9090).value

address = self.declare_parameter('address', '').value

RosbridgeWebSocket.client_manager = ClientManager(self)
Expand Down Expand Up @@ -292,15 +292,14 @@ def __init__(self):
"Retrying in {}s.".format(e, retry_startup_delay))
time.sleep(retry_startup_delay)


def main(args=None):
if args is None:
args = sys.argv

rclpy.init(args=args)
rosbridge_websocket_node = RosbridgeWebsocketNode()

spin_callback = PeriodicCallback(lambda: rclpy.spin_once(rosbridge_websocket_node, timeout_sec=0.01), 100)
spin_callback = PeriodicCallback(lambda: rclpy.spin_once(rosbridge_websocket_node, timeout_sec=0.01), 1)
spin_callback.start()
start_hook()

Expand Down
5 changes: 5 additions & 0 deletions rosbridge_server/src/rosbridge_server/websocket_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,13 @@ def on_message(self, message):
self.close()
except:
# proper error will be handled in the protocol class
if type(message) is bytes:
message = message.decode('utf-8')
self.protocol.incoming(message)
else:
# no authentication required
if type(message) is bytes:
message = message.decode('utf-8')
self.protocol.incoming(message)

@log_exceptions
Expand All @@ -189,6 +193,7 @@ def send_message(self, message):

@coroutine
def prewrite_message(self, message, binary):
cls = self.__class__
# Use a try block because the log decorator doesn't cooperate with @coroutine.
try:
with self._write_lock:
Expand Down