1. Home
  2. Docs
  3. Yonohub
  4. Tutorials
  5. Create ROS-Based Block

Create ROS-Based Block

In this tutorial, you will be able to develop a ROS-based YonoArc block that is written in C++. This block splits the flow of incoming images into two flows such that the message rate at each output port is half the message rate at the input port. The output pipeline should look like:

    1. Start the Terminal at Jupyter Notebook.
      1. Click the Jupyter Notebook icon on Yonohub’s main view.
      2. Select the YonoCommons – CPU environment. Any environment that is built using YonoEBuilder already contains ROS Melodic and that is all what you need for this tutorial.
      3. Under the General tab, select C1 since we only need Jupyter Notebook to develop the block.
      4. Click Launch or Express Launch. Wait until Jupyter Notebook finishes loading.
      5. Once Jupyter Notebook is running, click its icon then click the Web UI URL.
      6. Start the Terminal by clicking New >> Terminal.
    2. Set up a catkin workspace as follows. For more information about setting up a catkin workspace, check this tutorial.
      mkdir -p /splitter_ws/src
      cd /splitter_ws/
      catkin_make
      source devel/setup.bash
    3. Create a ROS package.
      • Execute these commands to create a splitter package that depends on both roscpp and sensor_msgs.
        cd /splitter_ws/src/
        catkin_create_pkg splitter roscpp sensor_msgs
      • Add the dependency between the splitter package and the sensor_msgs package. The sensor_msgs package is added for you, but you need to add the dependency by adding these lines at the end of this file: /splitter_ws/src/splitter/CMakeLists.txt. Please double check that the three lines are copied and pasted correctly since some editors (e.g., nano) may not be able to paste correctly. You can use Vim.
        add_executable(splitter src/splitter.cpp)
        target_link_libraries(splitter ${catkin_LIBRARIES})
        add_dependencies(splitter sensor_msgs_generate_messages_cpp)
      • For more information about creating a package, check this tutorial.
    4. Develop the ROS node representing the Splitter block by creating a new file at /splitter_ws/src/splitter/src/splitter.cpp with the following code. For more information about writing ROS nodes, check this C++ tutorial.
      • Use Jupyter to navigate to the path /splitter_ws/src/splitter/src/
      • Click New >> Text File to create a new file. The file opens in a new tab.
      • Rename the file from untitled.txt to splitter.cpp by clicking its name at the top.
      • Paste the following source code into the file.
#include "ros/ros.h"
#include "sensor_msgs/Image.h"

// The two publishers for the two output topics.
ros::Publisher publisher1;
ros::Publisher publisher2;

// An integer indicating on which publisher to publish the next image.
int turn = 0;

void callback(const sensor_msgs::Image::ConstPtr& image)
{
    // Use the first (or second) publisher for an even (or odd) turn.
    if (turn % 2 == 0) {
        publisher1.publish(image);
    } else {
        publisher2.publish(image);
    }
    turn++;
}

int main(int argc, char **argv)
{
    // Initialize the ROS node.
    ros::init(argc, argv, "splitter");

    // NodeHandle is the main access point to communications with the ROS system.
    ros::NodeHandle n;
    
    // Define the two publishers for the two output topics.
    publisher1 = n.advertise<sensor_msgs::Image>("image1", 100);
    publisher2 = n.advertise<sensor_msgs::Image>("image2", 100);

    // Subscribe to the input topic.
    ros::Subscriber sub = n.subscribe("image", 1000, callback);

    // This will enter a loop, pumping callbacks.
    ros::spin();

    return 0;
}
  1. Move your workspace to YonoDrive. When you start Jupyter Notebook, your YonoDrive folders are mounted on /MyDrive, /MyTeams, /Keys, and /YonoStoreDatasets. Anything you modify under these folders will be persisted in YonoDrive, but beware that this is a slow type of storage. For a fast SSD, you can use the root directory, but beware that this is not persisted in YonoDrive. That is why you need to move your workspace from the SSD to YonoDrive.
    • mv /splitter_ws/ /MyDrive/
  2. Stop Jupyter Notebook by clicking Stop above its icon on Yonohub’s main view.
  3. Create a YonoArc project.
    • Click the YonoArc icon on Yonohub’s main view.
    • Click the + button at the upper-left corner then click Block Manager.
    • Click Create project. Set the attributes of the project as follows:
      • Name: Splitter
      • Type: ROS Nodes (C++ or Python 2)
      • Environment: YonoCommons – CPU. Any environment that is built using YonoEBuilder already contains ROS Melodic and that is all what you need for this project.
      • Source Code Folder Path: YonoDrive Path: /MyDrive/splitter_ws
      • Git Repositories of Messages: You can leave the default message repos because the ros-common-msgs repository has the sensor_msgs package which contains the Image message. The ros-std-msgs repository has the std_msgs package which contains the Header message that is used in the sensor_msgs/Image message.
        • URL: https://gitlab.yonohub.com/YonoTeam/ros-common-msgs.git – Branch/Tag: 1.12.6
        • URL: https://gitlab.yonohub.com/YonoTeam/ros-std-msgs.git – Branch/Tag: 0.5.11
      • Click Create.
    • Select the project and click Build. Select C1 as the resource model and Click Build. Wait until the status of the project becomes Release Ready.
  4. Configure the Splitter block.
    • Navigate to the Blocks tab and select the Splitter project from the drop-down list.
    • Select “Unreleased” from the project version drop-down since this new version has not been released yet.
    • Click the “splitter /splitter” entry that appears in the left sidebar to select the block we created.
    • Click Invert to select all other blocks, except the one we are interested in.
    • Click Delete to delete all the other blocks.
    • Select your block again to set its attributes:
      • Name: Splitter
      • Description: This block splits the flow of incoming images into two flows such that the message rate at each output port is half the message rate at the input port.
      • Toolbox: My Blocks
      • Minimum Resources: C0.1 x 1
      • Input Ports: A single port with the following attributes:
        • Name: Input Image
        • Message: sensor_msgs/Image.
        • Key: image
        • ROS Name: image. This is the name of the topic used in the ROS node.
        • Description: An image from the flow that will be split into two flows
      • Output Ports: The first port has the following attributes:
        • Name: Flow 1
        • Message: sensor_msgs/Image.
        • Key: image1.
        • ROS Name: image1. This is the name of the topic used in the ROS node.
        • Description: An image from the first output flow
      • Output Ports: The second port has the following attributes:
        • Name: Flow 2
        • Message: sensor_msgs/Image.
        • Key: image2.
        • ROS Name: image2. This is the name of the topic used in the ROS node.
        • Description: An image from the second output flow
    • Click Save at the upper-left corner of the block information. You can see that the name of the block has changed on the left sidebar to Splitter, the block name you specified.
  5. Release the project.
    • Navigate to the Projects tab.
    • Select the project and click Release.
    • Set the version to 0.1.0 and click Release.
  6. Use the block in YonoArc. The Splitter block should be listed in My Blocks toolbox. Use your knowledge from the Hello YonoArc tutorial to build and launch the Splitter pipeline shown above.
    • Verify the results while the pipeline is running.
      • Check the two videos in the dashboard as shown below.
      • Hover over the input connection to the Splitter block. You would see a message rate of 10 messages/sec.
      • Hover over any output connection from the Splitter block. You would see a message rate of 5 messages/sec.
    • Click Terminate to terminate the pipeline and release the resources.