Implementing world
Creating the node
Most nodes will share basic boilerplate which can be copied from the examples ROS gives:
$ cp /opt/ros/$ROS_DISTRO/share/launch_testing_ros/examples/talker.py src/world/world/world.py
Now rename your node World
and add the following lines:
class World(Node):
def __init__(self):
super().__init__('world')
self.generate_waypoints()
def generate_waypoints(self):
self.waypoints = []
WIDTH = 200
HEIGHT = 100
for i in range(30):
angle = i * 2 * math.pi / 30
x = math.cos(angle) * WIDTH
y = math.sin(angle) * HEIGHT
self.waypoints.append(Waypoint(x=x, y=y, idx=i))
This code generates the waypoints that the car will follow. As you can see, we are just drawing an ellipse (that you can resize by tweaking with the WIDTH
and HEIGHT
values), but the shape can be any shape you want.
However, if you tried to execute this code, you’d face an error because Waypoint
is a custom message that we haven’t defined yet.
Defining the Waypoint
message
We need to create a message to represent a point in space. If you have read the previous chapters, you know that messages are defined in the um_msgs
directory. In said package, create a directory msg
and a file called Waypoint.msg
inside that directory, such that the structure of the package is:
src/um_msgs/
├── CMakeLists.txt
├── include
│ └── um_msgs
├── msg
│ └── Waypoint.msg
├── package.xml
└── src
If you’re not sure how to implement this, check the reference .
A waypoint is defined as such:
float64 x
float64 y
uint16 idx
And since we’re at it, we can also define Waypoints.msg
like this:
Waypoint[] waypoints
Publishing the waypoints
After importing the message (from um_msgs.msg import Waypoint
), we can already execute our world
node. All it does is generate the waypoints, but we don’t do anything with them. Let’s publish them.
In the __init__
method, include the following lines:
def __init__(self):
...
self.waypoints_publisher = self.create_publisher(Waypoints, '/world_waypoints', 10)
self.waypoints_publisher_timer = self.create_timer(3.0, self.publish_waypoints)
These lines of code create a ROS publisher object and a timer object that periodically calls a callback function to publish messages to a specific ROS topic. Note that you can’t rename this topic because qt_interface
reads from it.
Next, define the callback function:
def publish_waypoints(self):
msg = Waypoints(msg=self.waypoints)
self.waypoints_publisher.publish(msg)
Note that this is also a method in our node and should be indented to the same height as __init__
.
Executing the code
Finally, if we execute this code and the interface, we should already see our waypoints being rendered into the canvas.