It looks like the namespace can be set programmatically in ROS 1 by setting ROS_NAMESPACE
prior to importing rospy
. With the code below, the node will have the namespace /my/custom/namespace
unless the user running the node sets ROS_NAMESPACE
or passes the command line argument __ns:=/some/other/ns
.
import os
import sys
if 'ROS_NAMESPACE' not in os.environ:
# Default namespace if not set
# Note, didn't need to check sys.argv for `__ns:=...`,
# it seems __ns:= takes precidence over ROS_NAMESPACE
os.environ['ROS_NAMESPACE'] = '/my/custom/namespace'
# Must set `os.environ['ROS_NAMESPACE']` BEFORE importing `rospy`
import rospy
from std_msgs.msg import String
rospy.init_node('listener_default_ns')
rospy.Subscriber("chatter", String, lambda m: rospy.loginfo(m.data))
rospy.spin()
I tested this using ROS Melodic, but I would expect it to work in ROS Noetic as well.
EDIT @gvdhoorn has a good point. While the above answers the literal question, the preferred approach is to set the namespace when starting the nodes. The code of a node should only focus on its purpose; it shouldn't have to be concerned about whether there is one or many robots in different namespaces using that node. The awareness of how the node is integrated into a larger system should only be with the tools that launch the node.
You already discovered it can be set using the ns
attribute in launch files. The namespace can be set one node at a time, or on a whole group of nodes at once. I took this example from the ROS wiki and simplified it for this answer.
<launch>
<!-- Start a single node in the namespace foo -->
<node ns="foo" name="listener1" pkg="rospy_tutorials" type="listener"/>
<!-- Start a group of nodes in the namespace bar-->
<group ns="bar">
<node pkg="rospy_tutorials" type="listener" name="listener"/>
<node pkg="rospy_tutorials" type="talker" name="talker"/>
</group>
</launch>