Skip to content

Instantly share code, notes, and snippets.

@awesmubarak
Created December 13, 2024 09:33
Show Gist options
  • Save awesmubarak/649f1868fd700932e41d06c73640a9f4 to your computer and use it in GitHub Desktop.
Save awesmubarak/649f1868fd700932e41d06c73640a9f4 to your computer and use it in GitHub Desktop.

ROS 2 Simple Calculator - Minimal Version

Step 1: Create workspace and package

mkdir -p ~/ros2_simple_calc/src
cd ~/ros2_simple_calc/src
ros2 pkg create simple_calc_pkg --build-type ament_python --dependencies rclpy std_msgs

colcon build

source install/setup.bash

Step 2: Create calculator server node

Create file: simple_calc_pkg/simple_calc_pkg/calc_server.py

import rclpy
from rclpy.node import Node
from std_msgs.msg import Int32

class CalcServer(Node):
   def __init__(self):
       super().__init__('calc_server')
       # Subscribe to input numbers
       self.subscription = self.create_subscription(
           Int32,
           'number',
           self.number_callback,
           10)
       # Publisher for results
       self.publisher = self.create_publisher(Int32, 'result', 10)
       self.numbers = []

   def number_callback(self, msg):
       self.numbers.append(msg.data)
       if len(self.numbers) == 2:
           result = Int32()
           result.data = self.numbers[0] + self.numbers[1]
           self.publisher.publish(result)
           self.numbers = []  # Reset for next calculation

def main():
   rclpy.init()
   calc_server = CalcServer()
   print('Calculator server is running...')
   rclpy.spin(calc_server)
   rclpy.shutdown()

if __name__ == '__main__':
   main()

Step 3: Create calculator client node

Create file: simple_calc_pkg/simple_calc_pkg/calc_client.py

import rclpy
from rclpy.node import Node
from std_msgs.msg import Int32
import sys

class CalcClient(Node):
   def __init__(self):
       super().__init__('calc_client')
       self.publisher = self.create_publisher(Int32, 'number', 10)
       self.subscription = self.create_subscription(
           Int32,
           'result',
           self.result_callback,
           10)

   def send_numbers(self, a, b):
       # Send first number
       msg1 = Int32()
       msg1.data = int(a)
       self.publisher.publish(msg1)
       
       # Send second number
       msg2 = Int32()
       msg2.data = int(b)
       self.publisher.publish(msg2)

   def result_callback(self, msg):
       print(f'Result: {msg.data}')
       rclpy.shutdown()  # Exit after getting result

def main():
   rclpy.init()
   calc_client = CalcClient()
   
   if len(sys.argv) != 3:
       print('Usage: ros2 run simple_calc_pkg calc_client <num1> <num2>')
       return
       
   calc_client.send_numbers(sys.argv[1], sys.argv[2])
   rclpy.spin(calc_client)

if __name__ == '__main__':
   main()

Step 4: Update setup.py

Replace content in simple_calc_pkg/setup.py with:

from setuptools import setup

package_name = 'simple_calc_pkg'

setup(
   name=package_name,
   version='0.0.0',
   packages=[package_name],
   data_files=[
       ('share/ament_index/resource_index/packages',
           ['resource/' + package_name]),
       ('share/' + package_name, ['package.xml']),
   ],
   install_requires=['setuptools'],
   zip_safe=True,
   maintainer='your_name',
   maintainer_email='[email protected]',
   description='Simple calculator package',
   license='Apache License 2.0',
   tests_require=['pytest'],
   entry_points={
       'console_scripts': [
           'calc_server = simple_calc_pkg.calc_server:main',
           'calc_client = simple_calc_pkg.calc_client:main',
       ],
   },
)

Step 5: Update package.xml

Replace content in simple_calc_pkg/package.xml with:

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
 <name>simple_calc_pkg</name>
 <version>0.0.0</version>
 <description>Simple calculator package</description>
 <maintainer email="[email protected]">your_name</maintainer>
 <license>Apache License 2.0</license>

 <depend>rclpy</depend>
 <depend>std_msgs</depend>

 <test_depend>ament_copyright</test_depend>
 <test_depend>ament_flake8</test_depend>
 <test_depend>ament_pep257</test_depend>
 <test_depend>python3-pytest</test_depend>

 <export>
   <build_type>ament_python</build_type>
 </export>
</package>

Final directory structure should look like:

~/ros2_simple_calc/
├── src/
   └── simple_calc_pkg/
       ├── simple_calc_pkg/
       │   ├── __init__.py
       │   ├── calc_server.py
       │   └── calc_client.py
       ├── resource/
       │   └── simple_calc_pkg
       ├── package.xml
       ├── setup.cfg
       └── setup.py

Build and run commands:

# Navigate to workspace root
cd ~/ros2_simple_calc

# Build the package
colcon build

# Source the setup files
source install/setup.bash

# Right click server.py, and select 'run python'

# Copy and paste the command that ran in the terminal into another terminal, chaning to client.py

Note: Make sure you have ROS 2 properly installed and sourced in your environment before starting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment