{"id":23268448,"url":"https://github.com/dimitriskatos/my_robot","last_synced_at":"2025-04-06T08:40:59.391Z","repository":{"id":224900599,"uuid":"738924476","full_name":"DimitrisKatos/my_robot","owner":"DimitrisKatos","description":"Two wheel robot with camera, lidar and differential drive.","archived":false,"fork":false,"pushed_at":"2024-01-17T10:33:46.000Z","size":729,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-12T14:17:36.254Z","etag":null,"topics":["differential-drive-robot","gazebo-plugins","gazebo-simulator","navigation-algorithms","ros2","ros2-humble","rviz2"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DimitrisKatos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-01-04T11:12:52.000Z","updated_at":"2024-12-31T14:06:02.000Z","dependencies_parsed_at":"2024-02-28T10:27:44.208Z","dependency_job_id":"41fe0318-7172-4ac5-94b0-79553e61c4bd","html_url":"https://github.com/DimitrisKatos/my_robot","commit_stats":null,"previous_names":["dimitriskatos/my_robot"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DimitrisKatos%2Fmy_robot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DimitrisKatos%2Fmy_robot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DimitrisKatos%2Fmy_robot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DimitrisKatos%2Fmy_robot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DimitrisKatos","download_url":"https://codeload.github.com/DimitrisKatos/my_robot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247457727,"owners_count":20941905,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["differential-drive-robot","gazebo-plugins","gazebo-simulator","navigation-algorithms","ros2","ros2-humble","rviz2"],"created_at":"2024-12-19T17:18:38.866Z","updated_at":"2025-04-06T08:40:59.338Z","avatar_url":"https://github.com/DimitrisKatos.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Differential drive controller robot with two sensors.\nIn this tutorial we will build a differential drive controller robot using xacro properties. We will add two sensors, a camera, lidar and finally we control the robot model by adding differential drive plugin. \n\nTotally, you will learn the following:\n- how to add lidar to robot and adding a new mesh file.\n- how to add a camera to robot.\n- how to add differential drive control to the robot.\n- Create a simple algorithm for obsackle avoidance.\n\nYou can find a presentation that will guide you through this tutorial. In the presentation, you can find information on how to build this robot.\n- [Create a differential drive controller robot](https://docs.google.com/presentation/d/1JCBwxNok0eC-tr-dRsIzfJUy-XPxEjk6/edit?usp=drive_web\u0026ouid=106628092038381749227\u0026rtpof=true) Greek language.\n- Create a differential drive controller robot. English language (comming soon).\n\nYou can find a project in the following link:\n- [Project]() Greek language.\n- [Project]() English language( Coming soon).\n\n## Create, build and setup a new package.\nCreate a new ROS 2 package for the differential drive control robot\n```\ncd ~/ros2_ws/src\nros2 pkg create --build-type ament-python my_robot\n```\n\nCreate some folders to the package for better organization.\n```\ncd ~/ros2_ws/src\nmkdir launch urdf meshes worlds\n```\n\nAfter creating the package and the folders, you need to modify the setup.py file of the package.\nAdd the following modules.\n```py\nfrom glob import glob\nimport os\n```\nIn the data_files list of the script add the following.\n```py\n        (os.path.join('share',package_name,'launch'),\n         glob(os.path.join('launch','*.launch.py'))),\n        (os.path.join('share',package_name,'urdf'),\n         glob(os.path.join('urdf','*.xacro'))),\n         (os.path.join('share',package_name,'urdf'),\n         glob(os.path.join('urdf','*.gazebo'))),\n        (os.path.join('share',package_name,'worlds'),\n         glob(os.path.join('worlds','*.world'))),\n        (os.path.join('share',package_name,'meshes'),\n         glob(os.path.join('meshes','*.dae'))),\n```\n\nThe next step is building the package using the colcon tool.\n```\ncd ~/ros2_ws/\ncolcon build --packages-select my_robot\n```\n\n## Two wheel robot with camera, lidar and differential drive controller.\nFirst of all we need to create the robot model. We will create two files which is the following\n - Create [myrobot.xacro](https://github.com/DimitrisKatos/my_robot/blob/master/urdf/myrobot.xacro) in the urdf folder of the package. This file is the two-wheeled robot.\n - Create [robot.gazebo](https://github.com/DimitrisKatos/my_robot/blob/master/urdf/robot.gazebo) in the urdf folder of the package. In this file we define all the Gazebo plugins. So far, we define colors for every link and attrition. \n\nNow the robot is ready. Let's move to some more interest staff. \n\n---\n## Add a camera to robotmodel.\nNow we will add a camera to robot model. For this reason we need to add a new link and joint to the robot model. Furthermore you need to add a new Gazebo plugin to the robot.gazebo file. \n- In the [myrobot.xacro](https://github.com/DimitrisKatos/my_robot/blob/master/urdf/myrobot.xacro) file we add a box link in front of the robot model.\n- In the robot.gazebo file we add the following xml code to enable the camera in the gazebo simulator.\n```xml\n\u003c!-- camera --\u003e\n  \u003cgazebo reference=\"camera\"\u003e\n    \u003csensor type=\"camera\" name=\"camera1\"\u003e\n      \u003cupdate_rate\u003e30.0\u003c/update_rate\u003e\n      \u003ccamera name=\"head\"\u003e\n        \u003chorizontal_fov\u003e1.3962634\u003c/horizontal_fov\u003e\n        \u003cimage\u003e\n          \u003cwidth\u003e800\u003c/width\u003e\n          \u003cheight\u003e800\u003c/height\u003e\n          \u003cformat\u003eR8G8B8\u003c/format\u003e\n        \u003c/image\u003e\n        \u003cclip\u003e\n          \u003cnear\u003e0.02\u003c/near\u003e\n          \u003cfar\u003e300\u003c/far\u003e\n        \u003c/clip\u003e\n      \u003c/camera\u003e\n      \u003cplugin name=\"camera_controller\" filename=\"libgazebo_ros_camera.so\"\u003e\n        \u003calwaysOn\u003etrue\u003c/alwaysOn\u003e\n        \u003cupdateRate\u003e0.0\u003c/updateRate\u003e\n        \u003ccameraName\u003emy_robot/camera1\u003c/cameraName\u003e\n        \u003cimageTopicName\u003eimage_raw\u003c/imageTopicName\u003e\n        \u003ccameraInfoTopicName\u003ecamera_info\u003c/cameraInfoTopicName\u003e\n        \u003cframeName\u003ecamera_link\u003c/frameName\u003e\n        \u003chackBaseline\u003e0.07\u003c/hackBaseline\u003e\n        \u003cdistortionK1\u003e0.0\u003c/distortionK1\u003e\n        \u003cdistortionK2\u003e0.0\u003c/distortionK2\u003e\n        \u003cdistortionK3\u003e0.0\u003c/distortionK3\u003e\n        \u003cdistortionT1\u003e0.0\u003c/distortionT1\u003e\n        \u003cdistortionT2\u003e0.0\u003c/distortionT2\u003e\n      \u003c/plugin\u003e\n    \u003c/sensor\u003e\n  \u003c/gazebo\u003e  \n```\n\nNow we can use the Gazebo Classic Simulator to see if the camera works properly. Also we will visualize the results from the camera to RVIZ. Now let's visualize the robot to Gazebo. Run the next commands.\n```\ncd ~/ros2_ws\ncolcon build --package-select my_robot\ncd src/my_robot # For WSL run the next command\nexport LIBGL_ALWAYS_SOFTWARE=1 LIBGL_ALWAYS_INDIRECT=0\nros2 launch my_robot my_robot_gazebo.launch.py\n```\n\n![Poll Mockup](./images/image3.png)\n\nAfter the robot spawn in gazebo we add to obstacles. Now let's visualize the data from the hokuyo laser to RVIZ 2. In a new terminal begin Rviz and you need to make some changes:\n- Add RobotModel and change the topic to /robot_descriptiion.\n- Add Camera from displays panel and change the topic.\n- Finally, change the Fixed Frame to base_link from the displays panel.\n\nIn the left bottom you can see what the camera's robot are watching.\n\n\n![Poll Mockup](./images/image4.png)\n\n\n## Add lidar to robot model.\n\nFirst of all, you need to add an new link and joint to robot model. The new link defines the lidar to your robot. Furthermore this link reads a mesh file and visualize a real lidar. In the meshes folder you need to save the [hokuyo.dae file](https://github.com/DimitrisKatos/my_robot/blob/master/meshes/hokuyo.dae).\nIn the robot model add the following. \n```xml\n  \u003cjoint name=\"hokuyo_joint\" type=\"fixed\"\u003e\n    \u003caxis xyz=\"0 1 0\" /\u003e\n    \u003corigin xyz=\".15 0 .1\" rpy=\"0 0 0\"/\u003e\n    \u003cparent link=\"base_link\"/\u003e\n    \u003cchild link=\"hokuyo\"/\u003e\n  \u003c/joint\u003e\n \n  \u003c!-- Hokuyo Laser --\u003e\n  \u003clink name=\"hokuyo\"\u003e\n    \u003ccollision\u003e\n      \u003corigin xyz=\"0 0 0\" rpy=\"0 0 0\"/\u003e\n      \u003cgeometry\u003e\n    \u003cbox size=\"0.1 0.1 0.1\"/\u003e\n      \u003c/geometry\u003e\n    \u003c/collision\u003e\n    \u003cvisual\u003e\n      \u003corigin xyz=\"0 0 0\" rpy=\"0 0 0\"/\u003e\n      \u003cgeometry\u003e\n           \u003cmesh filename=\"file://$(find my_robot)/meshes/hokuyo.dae\"/\u003e\n      \u003c/geometry\u003e\n    \u003c/visual\u003e\n    \u003cinertial\u003e\n      \u003cmass value=\"1e-5\" /\u003e\n      \u003corigin xyz=\"0 0 0\" rpy=\"0 0 0\"/\u003e\n      \u003cinertia ixx=\"1e-6\" ixy=\"0\" ixz=\"0\" iyy=\"1e-6\" iyz=\"0\" izz=\"1e-6\" /\u003e\n    \u003c/inertial\u003e\n  \u003c/link\u003e\n```\n\nAlso add a new gazebo plugin to robot.gazebo file. The XML code will enable lidar to the Gazebo simulator.\n```xml\n\u003c!-- hokuyo --\u003e\n      \u003cgazebo reference=\"hokuyo\"\u003e\n        \u003csensor name=\"laser\" type=\"ray\"\u003e\n            \u003cpose\u003e 0 0 0 0 0 0 \u003c/pose\u003e\n            \u003cvisualize\u003etrue\u003c/visualize\u003e\n            \u003cupdate_rate\u003e20\u003c/update_rate\u003e\n            \u003cray\u003e\n                \u003cscan\u003e\n                    \u003chorizontal\u003e\n                        \u003csamples\u003e360\u003c/samples\u003e\n                        \u003cmin_angle\u003e-1.57\u003c/min_angle\u003e\n                        \u003cmax_angle\u003e1.57\u003c/max_angle\u003e\n                    \u003c/horizontal\u003e\n                \u003c/scan\u003e\n                \u003crange\u003e\n                    \u003cmin\u003e0.2\u003c/min\u003e\n                    \u003cmax\u003e12\u003c/max\u003e\n                \u003c/range\u003e\n            \u003c/ray\u003e\n            \u003cplugin name=\"laser_controller\" filename=\"libgazebo_ros_ray_sensor.so\"\u003e\n                \u003cros\u003e\n                    \u003cargument\u003e~/out:=scan\u003c/argument\u003e\n                \u003c/ros\u003e\n                \u003coutput_type\u003esensor_msgs/LaserScan\u003c/output_type\u003e\n                \u003cframe_name\u003ehokuyo\u003c/frame_name\u003e\n            \u003c/plugin\u003e\n        \u003c/sensor\u003e\n    \u003c/gazebo\u003e\n```\nNow let's visualize the robot to Gazebo. Run the next commands.\n```\ncd ~/ros2_ws\ncolcon build --package-select my_robot\ncd src/my_robot # For WSL run the next command\nexport LIBGL_ALWAYS_SOFTWARE=1 LIBGL_ALWAYS_INDIRECT=0\nros2 launch my_robot my_robot_gazebo.launch.py\n```\n![Poll Mockup](./images/image.png)\n\nNow let's visualize the data from the hokuyo laser to RVIZ 2. In a new terminal begin Rviz and you need to make some changes:\n- Add RobotModel and change the topic to /robot_descriptiion.\n- Add /laser_scan from displays panel and change the topic.\n- Finally, change the Fixed Frame to base_link from the displays panel.\n\nYou will see that the obstacles have been detected by hokuyo lidar.\n![Poll Mockup](./images/image2.png)\n\n## Differential drive controller and obstacle avoidance algorithm. \n\nFor differential drive control we need to add an extra Gazebo plugin to robot.gazebo file. The XML code you need to add is the following:\n```xml\n    \u003c!--Differential Drive Controller for 2-wheel-robot--\u003e\n     \u003cgazebo\u003e\n        \u003cplugin name=\"diff_drive\" filename=\"libgazebo_ros_diff_drive.so\"\u003e\n            \u003c!-- Wheel Information --\u003e\n            \u003cleft_joint\u003eleft_wheel_hinge\u003c/left_joint\u003e\n            \u003cright_joint\u003eright_wheel_hinge\u003c/right_joint\u003e\n            \u003cwheel_separation\u003e0.4\u003c/wheel_separation\u003e\n            \u003cwheel_diameter\u003e0.1\u003c/wheel_diameter\u003e\n\n            \u003c!-- Limits --\u003e\n            \u003cmax_wheel_torque\u003e200\u003c/max_wheel_torque\u003e\n            \u003cmax_wheel_acceleration\u003e10.0\u003c/max_wheel_acceleration\u003e\n            \n            \u003c!-- Output --\u003e\n            \u003codometry_frame\u003eodom\u003c/odometry_frame\u003e\n            \u003crobot_base_frame\u003echassis\u003c/robot_base_frame\u003e\n            \u003cpublish_odom\u003etrue\u003c/publish_odom\u003e\n            \u003cpublish_odom_tf\u003etrue\u003c/publish_odom_tf\u003e\n            \u003cpublish_wheel_tf\u003etrue\u003c/publish_wheel_tf\u003e\n        \u003c/plugin\u003e\n    \u003c/gazebo\u003e \n```\n\nNow the differential drive is enable and we can send messages to the /cmd_vel topic. \n```\nros2 topic pub /cmd_vel geometry_msgs/msg/Twist '{linear:{x: 0.4}, angular:{z: 0.2}}'\n```\n\nThe following Python Script is a simple Publisher and Subscriber for ROS 2. We subcribe data from the lidar and we publish to /cmd_vel topic. Create a new file name [diff_drive.py](https://github.com/DimitrisKatos/my_robot/blob/master/my_robot/diff_drive.py) to my_robot folder.\n```py\nimport rclpy\nfrom rclpy.node import Node \n\nfrom geometry_msgs.msg import Twist\nfrom sensor_msgs.msg import LaserScan\n\nclass diff_drive(Node):\n    \n    def __init__(self):\n        super().__init__('obstacle_avoider')\n        # Create the publisher, define the type of message, the topic\n        # and the frame rate.\n        self.__publisher = self.create_publisher(Twist,'cmd_vel',1)\n\n        # Create the subscriber, define the type of message,\n        # the topic and the frame rate\n        self.subscription = self.create_subscription(\n            LaserScan,\n            '/scan',\n            self.listener_callback,\n            10)\n\n    # Create a method for the class. \n    def listener_callback(self,msg):\n        # Create a variable and Define the position of the scanner,\n        # which will subcribe the distance.\n        self.msg = min(msg.ranges[165:179]+msg.ranges[180:195])\n        # Print the measurment distance.\n        print(f\"The measurment distance is {msg}.\")\n\n        # Create a variable, and give him the type of Twist()\n        command_msg = Twist()\n\n        # Define the speed of the robot to 0.2 m/s in x axis\n        command_msg.linear.x = 0.2\n        \n        if self.msg \u003c 0.5:\n            # Define the speed of the robot, if the obstacle is in front.\n            command_msg.angular.z = 2.0\n            command_msg.linear.x = 0.0\n        \n        # Publish the speed.\n        self.__publisher.publish(command_msg)\n\ndef main(args=None):\n    rclpy.init(args=args)\n    # Create an instance\n    avoider = diff_drive()\n    # run the instance\n    rclpy.spin(avoider)\n\n    # End the programm with Cntr+C\n    avoider.destroy_node()\n    rclpy.shutdown()\n\n# Call the main function\nif __name__=='__main__':\n    main()\n```\n\nIn the setup.py file inform the entry_points dictionary to the following.\n```py\nentry_points={\n        'console_scripts': [\n            'diff_drive = my_robot_description.diff_drive:main'\n        ],\n    },\n```\n\nPut your robot to a building and run the next commands. \n```\ncd ~/ros2_ws\ncolcon build --packages-select my_robot\nros2 run my_robot diff_drive\n```\nYou will see your robot moving forward. When he detects an obstacle he tries to turn.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdimitriskatos%2Fmy_robot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdimitriskatos%2Fmy_robot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdimitriskatos%2Fmy_robot/lists"}