-
Notifications
You must be signed in to change notification settings - Fork 0
Using the Python ROS_API
The purpose of the ros_api is to make interfacing with ROS easier. It contains classes that make it so you do very little in order to communicate between nodes.
You can see a reference of all classes/functions implemented at the ROS_API Ref page.
The ROS_API is contained inside the folder igvc_ws/src/ros_api/
and is not inside any package. It will, however, be used in every package. The way this works is that inside every package (node) we create there will by what is called a symbolic link to the ros_api folder. This will make the API seem like it is in the same folder as the package you write, but the actual files are elsewhere.
Thus, in order to use the ros_api, you must create this symbolic link inside of your package's src folder. You can create this link simply by running this command when in the igvc_ws/src/<package_name>/src/
directory in the terminal: ln -sf ../../ros_api ros_api
Make sure that you are in the correct directory (igvc_ws/src/<package_name>/src/
) or else it will not work. So, for example, if I was creating a new package all of the following commands would create and set up the package:
I am starting in the igvc_ws/src/
directory.
catkin_create_pkg test_package
cd test_package
mkdir src
cd src
ln -sf ../../ros_api ros_api
If you experience issues later on trying to import the ros_api module (eg not found the error) then the error is likely somewhere in these steps.
You can test to see if it is working by opening terminal in the igvc_ws/src/<package_name>/src/
directory and running:
python
import ros_api
If there are no errors, everything is configured correctly (don't forget when making a package to run catkin_make
in the root directory of the workspace, igvc_ws
).
This assumes that the ros_api symbolic link has been created and is working properly.
I have already created two test packages called test_pkg and test_recieve to demonstrate using the ROS_API. Here I will briefly explain how to send and receive data using the ROS_API.
Things you should have (at the top) in every script that is interacting with ROS:
import std_msgs.msg as std_msgs # this gets the default message (data) object
import custom_msgs.msg as msgs # this gets any custom messages that we have made
import ros_api as ros # this imports the ros_api module
from ros_api import println # this is a custom way to print and view data that mimicks Python3 syntax
In every script you must also intialize a node for communication. This is done as follows:
ros.init_node(<name_of_node>)
This name must be unique, if you would like it to be based off of the same prefix you can pass a keyword argument anonymous. This is common practice for a subsriber node, but is not necessary if you manually make the nodes different.
ros.init_node(<name_of_node>, anonymous=True)
You create an object that will send data in a single line:
pub = ros.ROS_Publisher(<topic>, <message>)
where
Parameter | Usage |
---|---|
<topic> | the name of the topic, essentially the 'channel' it will talk on, must match the receiver |
<message> | the data structure to send, you can read more about messages here |
An example of this would be:
pub = ros.ROS_Publisher('this_must_match', msgs.coord)
You would then send data by using:
pub.send(<args>)
You can send data either sequentially or by keyword argument. Here is an example of each, where the coord
message has 3 integer data types x, y, and z.
pub.send(32,10,500)
pub.send(x=10,y=32,z=40)
In actual practice these messages should be in a loop, to continually update. You can see this in the examples/src/example_subscriber.py
file.
Similar to sending data, you create an object to receive the data (don't forget the other lines that belong at the top):
sub = ros.ROS_Subscriber(<topic>, <message>, call=<function>)
where the arguments are the same as above, but call=<function>
is new. The call parameter expects the name a callback function to execute whenever data is received. (You could leave call
out and the default callback will simply print the data it receives, this is good just for a quick test).
So we would create another function, for example:
def custom_callback(data):
println('Recieved custom callback: {}'.format(data))
# do absolutely amazing things here with this lovely data
An example of this would be:
sub = ros.ROS_Subscriber('this_must_match', msgs.coord, call=custom_callback)
This would print out any data it receives (same as if you left call
out). It should also be noted that this should also be in a loop since it is consistently just waiting to receive data. If you didn't loop then it would exit the program.
I hope this was helpful, if you have questions just ask me (Isaac) or also take a look at the examples I wrote for a test publisher (sending) and subscriber (receiving).