Writing a Python ROS Node
In order to write a python node, you must make a folder in the cobot_python directory. This is because of manifest files that are shared by c++ code but not by python code. You can copy the manifest.xml file from cobot_dialog and change the description to your own name.
For the python file, you have some set up to do first. The code snippet is below
# setup ROS stuff NODE_NAME = 'cobot_dialog' import roslib; roslib.load_manifest(NODE_NAME) from std_msgs.msg import * import rospy import sys import time from cobot_msgs.srv import * from cobot_msgs.msg import * from sensor_msgs.msg import * class Cobot2Dialog(): def __init__(self): rospy.init_node(NODE_NAME, disable_signals = True) rospy.Subscriber('Cobot/Status', CobotStatusMsg, \ self.__update_status, queue_size=1) rospy.Subscriber('Cobot/TalkerStatus', CobotTalkerMsg, \ self.__update_talker_status, queue_size=1) self.__publish = rospy.Publisher('Cobot/TaskPlannerStatus',CobotTaskPlannerMsg) rospy.Service('Cobot/TPTransport',CobotTPTransportSrv,self.__init_new_transport)
- Define a NODE_NAME for your program and add the lines below it.
- Make a class of functions for your code, including an __init__
function that subscribes and publishes to different messages and creates services (functions that other Nodes can call). Our example does each - see the Topics and Services page to understand how to use them.
- To look up the messages that you should subscribe or publish to, go to the cobot_msgs/msg/ folder and search through the defined messages. To make services, use cobot_msgs/srv
- Finally, to run your python node, make sure you have a main method. If you are receiving messages, make sure it runs forever.
if __name__ == "__main__":
Cobot2Dialog() while True: time.sleep(1.0)
Writing a C++ ROS Node
Source Code
New C++ modules should be created in a new folder under cobot_linux/src folder:
mkdir myNewModule
You first need a main function where the new node is defined. In this main function you can specify the topics that your new node publishes and those that it subscribes.
You can find a template with all the necessary includes and initializations at cobot_linux/src/cobot/cobot_node_template.cpp. You just need to copy it into your folder (probably changing the name)
cp cobot_linux/src/cobot/cobot_node_template.cpp cobot_linux/src/myNewModule/myModuleMain.cpp
and edit it according to your needs. For example, to add a subscription:
void myTopicCallBackFunction([msg type] myMessage){ //does whatever you want to do when you receive the topic ... } ... int main(int argc, char **argv) { ... ros::NodeHandle n; ros::Subscriber sub = n.subscribe("myTopic", 1, myTopicCallBackFunction); ... }
Compiling
To compile your code you need 2 things: first to update the cobot_linux/manifest.xml to include your dependencies. Then to add your new node as a target at the CMakeLists.txt.
So, if your node depends on another package from cobot or from ros (e.g. the opencv package), you just need to the line in the cobot_linux/manifest.xml
<depend package=opencv/>
Then you edit the CMakeLists.txt in 2 places (assuming that there is no dependency in external libraries). First add the path for the header files in your node. You will find a list of such entries more or less around line 85
include_directories(${PROJECT_SOURCE_DIR}/src/pathToHeaderFiles)
You add one of such lines for each directory you would add in front of a -I in a normal gcc command
Second add your node as a target. You will find similar declarations more or less at line 332
set (target yourModule) rosbuild_add_executable(${target} src/myNewModule/myModuleMain.cpp src/myNewModule/OtherCppFile1.cpp src/myNewModule/OtherCppFile2.cpp) add_dependencies(${target} shared_libraries) target_link_libraries(${target} shared_libraries)
where the add_dependencies line adds all the packages and libraries that should be compiled before your node and in the target_link_libraries you should add everything that you would put in front of a -L in a normal gcc command.
If you have extra libraries you should add their header files using the include_directories and linking them using target_link_libraries.
Topics and Services in Python
- The rospy.Subscriber
function takes a message name and type (from the msg folder), a function to call when the message is received, and the number of these messages to keep in a queue if your code is slower than the message rate. (see the msg folder)
- The rospy.Publisher
function takes a message name and type. Later, you can publish messages by instantiating a new message of the correct type and including all the arguments self.__publish.publish(CobotTaskPlannerMsg(self.__currentTask,self.__stack[0],"",self.__currentFrom, self.__current
To, self.__currentObj, False, False, False))
- The rospy.Service
function takes a name, service type (from the srv folder), and a function to call when the service is called. To use someone else's service, you must create a ServiceProxy, which returns a function pointer and then call that function with the necessary arguments (defined in the srv file) speaker_call = rospy.ServiceProxy('/Cobot/Talker',
CobotTalkerSrv) result = speaker_call(str(words))
Topics and Services in C++
Refer to the ROS C++ Tutorials:
http://www.ros.org/wiki/ROS/Tutorials/WritingPublisherSubscriber(c++) http://www.ros.org/wiki/ROS/Tutorials/WritingServiceClient(c++)
Running Nodes
You will need to start the nodes that your program depends on and then your own program.
- If those nodes are found in the cobot_linux directory:
In the cobot_linux directory, run ./bin/nameOfTheNode for each of the nodes that you need.
For example, ./bin/cobot_manager to get the status of the robot and ./bin/cobot_talker to get the last thing cobot said.
- If those nodes are found in the cobot_python directory:
In your directory, run python nodename.py