Package: rosonic
rosonicThis is the library to make you as fast as Sonic in developing python-based ROS
packages. The name does not actually come from Sonic, but "ROS (made pyth)onic"
since the main motivation is making ROS nodes, well, more pythonic. Doing this
allows for a more comfortable workflow, the code becomes more "natural" and
easier to understand.To alleviate some of the issues described inMotivationrosonictries to gently "force" the user to follow a design pattern. Namely,rosonicconceptualizes a ROS node as a class in a simple, pythonic way with
reasonable default behaviours.Requirementsrosonichas been developed for ROS Melodic and above, i.e Python 2.7,
Python 3.6 and above. However, at writing moment only Python 3.6 has been
tested. As soon as I'm transitioning my other projects to Noetic then I will
drop any support for Python 2.7.InstallationThis package is available on PyPI and can be installed as a normal pip package.pip install rosonicUsageCreating a NodeTherosonicbarebones, do-nothing ROS node now looks like this#! /usr/bin/env pythonfromrosonicimportNodeclassmy_node(Node):passif__name__=='__main__':my_node()The default behaviour of arosonic.Nodewill be to callrospy.spin. This is
useful for the "Subscriber" and "Pub-Sub" patterns inMotivation, then we only need to implement initialization
and callbacks. For the initialization, just create a normal__init__for the
class that doesn't take any arguments. Any resources, e.g.pub, can be set as
object fields (self.pub) and callbacks can be implemented as methods.classmy_node(Node):def__init__(self):self.pub=rospy.Publisher(...)rospy.Subscriber(...,self.callback)defcallback(self):self.pub.publish(...)When callingmy_node()you (in order) initialize the ROS node with
the class name, load parameters, create themy_nodeinstance and callmy_node.main. The defaultmainmethod will call thespinwhich in turn,
by default, callsrospy.spin.defmain(self):whileself.keep_alive():self.spin()self.shutdown()defspin(self):rospy.spin()The added bonus of these defaults is that it is very easy to do the "Publisher"
pattern as well. You specify arate, write__init__as before and overload
thespinmethod. If, however, you want completely different still then you
need to overloadmain, which is fairly simple in itself!fromrosonicimportNode,Rateclassmy_node(Node):rate=10def__init__(self):...defspin(self):...Parameters as class attributesIt isn't the mountain ahead that wears you out - it's the grain of sand in
your shoeWhat's the easiest way to declare a parameter? Maybe like this...#! /usr/bin/env pythonfromrosonicimportNode,Parameterclassmy_node(Node):IMAGE1=Parameter('~image1','image1')IMAGE2=Parameter('~image2','image2')USE_FILTER=Parameter('~use_filter',True)...if__name__=='__main__':my_node()That's therosonicway at least! You don't have to care about asserting
existence or managing scoping rules. Since they are class fields you have them
available all the time. IfParameteris not given a default value nor is theoptionalargument set, thenParameterchecks for existence at load time.A very slim implementationrosonictries to be very slim. There is some complexity regarding class
fields. However, it takes 5 minutes to look through the ROS relevant parts. So,
see the implementation as the real documentation!