====== ROS ====== ROS stands for Robot Operating System. It is a collection of libraries and utilities that make up a software framework that is a node based publisher-subscriber model. It allows developers to quickly write modular code for a robot that does a specifc task while providing a layer of useful libraries and introspection tools. The publisher-subscriber principal allows for minimal coupling by leaving it up to each node to subscribe and publish data as it wishes to a common bus that is accessible to all other nodes. The following are a set of notes I have taken while learning how to use ROS, and applying ROS to build an autonomous street robot name [[primo_robot|Primo]]. ===== ROS Package ===== [[http://wiki.ros.org/Packages|Official ROS package page]]. A package in ROS is the "software organization unit of ROS code". Think of a package as software project that does one task. It might contain multiple [[ros_nodes|nodes]], aka executable ROS processes, and a bunch of configuration information. For example, say we have a robot with a robotic arm that uses a motor that is connected to an output shaft via some gearing, and also cause we're fancy we have a torque transducers on the output shaft along with an encoder for position information. That is a good amount of stuff for just one arm joint, but this "arm joint stuff" perfect candidate for a package. We can boil it down to set of tasks relating to the joint and cease a package. On top of that we can create the package in such a way that it can be configurable, and applied to more of the similar joints. The package would be responsible for the following: **Sketch of package responsibilities** * Take in commands to control the joint in different ways * Position control to send the joint in a specific place * Force control to push against something or grip with a set force * Velocity control for a spinning joint such as a screwing task * Make sure the joint obeys within its limits of force, torque, velocity and position * Hold a set of configuration data such as position of the joint, name, etc * Have a driver interface to the motor controller which could be a serial, or CAN connection * Monitor any fault conditions and have a mechanism in place for what to do when bad things happen. With that sketch of responsibilities we can create engineering requirements that fully define the tasks and then go on to either try to find a package that does this already, or make our own. If we decide to make our own we'll build out our package and have nodes that handle each of those tasks that can easily talk to each other etc. Hope that gives you a good idea of what a ROS package is! ===== ROS Node ===== Nodes: A node is an executable that uses ROS to communicate with other nodes. Messages: ROS data type used when subscribing or publishing to a topic. Topics: Nodes can publish messages to a topic as well as subscribe to a topic to receive messages. Master: Name service for ROS (i.e. helps nodes find each other) rosout: ROS equivalent of stdout/stderr roscore: Master + rosout + parameter server (parameter server will be introduced later) Use the rosnode command to get information about currently running nodes. ===== Package Structure ===== The following is the simplest structure of a ROS package: my_package/ CMakeLists.txt package.xml The manifest is a file called ''%%package.xml%%'' and is a description of the package. A package in a catkin workspace looks like this: workspace_folder/ -- WORKSPACE src/ -- SOURCE SPACE CMakeLists.txt -- 'Toplevel' CMake file, provided by catkin package_1/ CMakeLists.txt -- CMakeLists.txt file for package_1 package.xml -- Package manifest for package_1 ... package_n/ CMakeLists.txt -- CMakeLists.txt file for package_n package.xml -- Package manifest for package_n ===== ROS Services ===== Services are another way nodes can communicate with each other. Services allow nodes to send a request and receive a response. You can look up the type of a service. Then using ''%%rossrv%%'' you can get more information on the that service. For example: rosservice type /spawn | rossrv show There is also such a thing as the ROS parameter server. It stores data. You can look at all this data by using the ''%%rosparam%%'' command. You can list the parameters, set them and even save and load them. Service files (srv) are just like msg files, except they contain two parts: a request and a response. The two parts are separated by a '---' line. Here is an example of a srv file: int64 A int64 B --- int64 Sum ==== Adding a ROS Service ==== Here are the steps to add a ROS service to a package. These are similar to adding a message. * Add a ''%%.srv%%'' file to the ''%%srv/%%'' directory of a package * Make sure ''%%message_generation%%'' and ''%%message_runtime%%'' build and runtime dependencies are enabled in the ''%%package.xml%%'' file. * Add message_generation to the find_package() function * Make sure the service is added to the add_service_files() function When this is done, running ''%%catkin_make install%%'' will build all the necessary stuff and also generate the header files required. ==== Building a ROS Service/Client ==== A service/client is another form of communication in ROS. Instead of relying on publisher/subscriber messages, which are asynchronous, you have a synchronous service based communication. A client calls a service and waits for a response. - First define the service you will use in the package. See [[ros#adding_a_ros_service|Adding a ROS service]]. - Write a server node in the ''%%srv/%%'' folder - Server node includes the generated header for the service - Server node has a function that returns a boolean and takes in the request and the response of the service. - Server node has a main function that: - calls ''%%ros::init%%'' - has a''%%ros::NodeHandle%%'' - advertises the service using ''%%ros::ServiceServer%%'' - ''%%ros::spin();%%'' - Write a client node in the ''%%src/%%'' folder - Has a main - ''%%ros::init()%%'' - ''%%ros::NodeHandle%%'' - ''%%ros::ServiceClient%%'' - calls ''%%client.call(srv)%%'' which acts as calling the service and gets returned with a response. Pretty neat. - Add the executables in the ''%%CMakeLists.txt%%'' files ===== Compiling Node With Multiple Source Files ===== ## Declare a cpp executable add_executable(executable_one src/source_one.cpp src/source_two.cpp src/source_n.cpp) To create multiple executables, you just add multiple instances of that line: ## Declare a cpp executable add_executable(executable_one src/source_one.cpp src/source_two.cpp src/source_n.cpp) add_executable(executable_two src/source_one.cpp src/source_two.cpp src/source_n.cpp) add_executable(executable_three src/source_one.cpp src/source_two.cpp src/source_n.cpp) ===== tf ===== tf keeps track of all these frames over time, and allows you to ask questions like: * Where was the head frame relative to the world frame, 5 seconds ago? * What is the pose of the object in my gripper relative to my base? * What is the current pose of the base frame in the map frame? * A ROS transform contains a pose (x,y,z) and a quaternion rotation (w, r, p, y) Transform is a deprecated package with tf2 being the new one. I did the tutorials where I created a broadcaster and a listener in c++. I also did some stuff where you can compute the transform between two frames and convert it to a velocity command to a robot. There are two things that you need to do to use tf. You have to listen and broadcast them. * Listen - Receive and buffer all coordinate frames that are broadcaster in the system, and query for specific transforms between frames * Broadcast - Send out the relative prose of coordinate frames to the rest of the system There is a REP that outlines lots of good best practice stuff when defining your robot [[http://www.ros.org/reps/rep-0105.html|link]]. ==== Quaternions ==== For learning about quaternions check out the [[http://www.ogre3d.org/tikiwiki/Quaternion+and+Rotation+Primer#Prerequisites|OGRE Quaternions intro]]. For conversions use this calculator [[http://www.energid.com/resources/orientation-calculator/|link]]. ==== Transform Debugging ==== You can use ''%%rosrun tf2_tools view_frames.py%%'' to show you information about the frames. You can use ''%%rosrun tf tf_monitor frame1 frame2%%'' to show you timing info. ==== tf::MessageFilter ==== ''%%tf::MessageFilter%%'' is a function that allows us to process stamped datatypes. turtle1 wants to know its position relative to itself * listen to the topic where turtle3's pose is being published * wait until transforms into the desired frame are ready * do its operations ==== tf::TransformListener ==== Convenient class that allows to do the following: * Create a listener for frames * Handle transforms such as points from one frame to another ==== robot_state_publisher ==== The robot state publisher helps you to broadcast the state of your robot to the tf transform library. It needs two things to run: * The URDF file * A source that publishes the joint positions as a ''%%sensor_msgs/JointState%%'' It subscribes to joint_states topic for joint position information. It uses the following parameters * robot_description(URDF map) * tf_prefix(string) * publish_frequency(double) ===== ROS Topic ===== The ''%%rostopic%%'' command lets you monitor all aspects of a ROS topic. You can also use ''%%rostopic%%'' to publish data of any message into a ROS topic. * ''%%rostopic hz %%'' : look at how often a message is being sent * ''%%rostopic pub %%'' : publish data to the topic When using ''%%rostopic pub%%'', make sure you do not have a ''%%/%%'' before the message name or else autocomplete won't work!!! ===== ROS Record ===== Recording and playing back data is really nice and easy with ROS. To record everything you run: rosbag record -a To play back a bag file you run: rosbag play ===== URDF ===== URDF is an XML file that stands for Unified Robot Description Format. Unfortunately the tutorials do not give you a step by step guide on how to make a URDF. Instead they just explain a sample URDF tutorial project, which leaves me guessing as to how integrate a URDF in an existing package. There is a Solidworks to URDF exporter but is old and does not work very well. Do not use it! You are much better off learning how to code your own URDF files. In a URDF there is a tree structure with one root link. The way you organize these links is with joints. You declare the links and then specify joints between them. If you have two links with no joint specified, RViz will give you an error. If there are any joints in a mesh, you need to run the joint_state_publisher and also the robot_state_publisher. That means in your launch file you will have the following: You specify meshes in a URDF with the following: You can use the command ''%%check_urdf%%'' to text the URDF file. [[#URDF_basic]] For URDF files to work in gazebo they need to have the following: * A header robot tag with an optional xml namespace. Essentially, the following: * ''%%%%'' element within each ''%%%%'' element. ==== Positioning ==== The link tab has an origin tag with rpy and xyz params. These only change the origin of the object. They do not change the position. To change the position you set up a joint. :URDF_basic: http://wiki.ros.org/urdf/Tutorials/Create%20your%20own%20urdf%20file :Gazebo_tut: http://gazebosim.org/tutorials/?tut=ros_urdf#Simplifycollisionmodel ==== Xacro ==== Xacro is a URDF macro scripting language that gives you functionality to create more powerful and dynamically generated URDF code. It is a bit tricky to learn but it is very helpful. The way it works is that you make a xacro file and then have the URDF get automatically generated. You need these two lines at the top of a xacro file. [[http://wiki.ros.org/urdf/Tutorials/Using%20Xacro%20to%20Clean%20Up%20a%20URDF%20File#CA-2595ee4c24086af97e963b00f75b8e9ddf9082b7_2|Here is a link to the best tutorial]]