{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Communication Pipeline\n", "\n", "In this unit we will gain understanding and practice on how information is passed between different components of the drone such as the onboard computer (Aero Compute Board) and the flight controller (AeroFC).\n", "\n", "You should have already been exposed to the basic concepts of the Robot Operating System (ROS) during the online portion of this class. These concepts including things like nodes, topics, messages, services, etc. If you are unsure/uncomfortable with what these concepts imply, there are great tutorials online for walking you through the basics of ROS. Please see:\n", "\n", "- [Intro to ROS](ros_introduction.html)\n", "- https://erlerobotics.com/blog/ros-introduction/\n", "- http://wiki.ros.org/ROS/Tutorials" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Talker - Listener\n", "\n", "We are going to put some of basic tools of ROS into practice on the Intel RTF Drone. We are going to start by creating and sending a simple message in one ROS node (i.e. talker) and receiving it in another. This portion relates to [this ROS tutorial](http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28python%29), but adapted to our needs.\n", "\n", "First make sure you have the most recent codebase on the drone.\n", "\n", "_On drone:_\n", "\n", "```\n", "cd ~/bwsi-uav/catkin_ws/src/aero_control\n", "git pull upstream master\n", "cd ~/bwsi-uav/catkin_ws/src/aero_control/communication_pipeline\n", "```\n", "\n", "If you try to run `simple_talker.py` and or `simple_listener.py` you will receive an error stating \n", "\n", "`Exception: CODE INCOMPLETE! Delete this exception and replace with your own code`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 1: Complete Talker\n", "\n", "In your preferred text editor, open `simple_talker.py` and replace/fill in the following code block with your own code:\n", "\n", "```\n", "'''TODO-START: FILL IN CODE HERE \n", "* create a string message that contains \"Hello World\" and the iteration number i\n", "'''\n", "raise Exception(\"CODE INCOMPLETE! Delete this exception and replace with your own code\")\n", "'''TODO-END '''\n", "```\n", "\n", "Once complete, you can run the talker node\n", "\n", "_Terminal 1:_\n", "```\n", "roscore\n", "```\n", "\n", "_Terminal 2:_\n", "```\n", "python simple_talker.py\n", "```\n", "\n", "After answering the following questions, you can kill the processes by hitting `Ctrl-c` in each terminal\n", "\n", "#### Questions Set 1:\n", "\n", "1. List all rosnodes that exist after running talker.py\n", "2. List all rostopics that are being present after running talker.py\n", "3. What command do I run to see what is being published to the `/chatter` topic?\n", "4. What would I change in `simple_talker.py` to make it publish messages more frequently?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 2: Complete Listener\n", "\n", "Now we will incorporate a second rosnode to subscribe to the topic created by `simple_talker.py` and listen to the messages passed. Open `simple_listener.py` and replace/fill in the appropriate code block.\n", "\n", "Once complete, you can run the talker and listener nodes\n", "\n", "_Terminal 1:_\n", "```\n", "roscore\n", "```\n", "\n", "_Terminal 2:_\n", "```\n", "python simple_talker.py\n", "```\n", "\n", "_Terminal 3:_\n", "```\n", "python simple_listener.py\n", "```\n", "\n", "After answering the following questions, you can kill these processes by hitting `Ctrl-C` in each terminal. You will also want to commit the progress you have made so you can later push it to your team's MIT GitHub repositories:\n", "\n", "```\n", "cd ~/bwsi-uav/catkin_ws/src/aero_control/communication_pipeline/src\n", "git add -u\n", "git commit -m \"filling in code for talker and listener\"\n", "```\n", "\n", "#### Questions Set 2:\n", "\n", "1. List all rosnodes that exist after running simple_talker.py and simple_listener.py\n", "2. List all rostopics that are being present after running simple_talker.py and simple_listener.py\n", "3. In terminal I ran simple_listener.py I see information being printed. Does this mean simple_listner.py is publishing to a topic?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 3: Launch Talker and Listener\n", "\n", "It's a cumbersome to be opening a different terminal for every different rosnode you want to start. Instead of doing this, we can use launch files.\n", "\n", "#### Create Package\n", "\n", "Before we make a launch file, we need to more properly set up our catkin workspace by turning `aero_control` into a ROS Package and indicate it's dependencies on `std_msgs` and `rospy`\n", "\n", "```\n", "cd ~/bwsi-uav/catkin_ws/src\n", "catkin_create_pkg aero_control std_msgs rospy\n", "```\n", "\n", "
\n", "\n", "**Note:** \n", "\n", "Your Intel drone may already have `aero_control` as a package. If you receive the error: `catkin_create_pkg: error: File exists: ~/bwsi-uav/catkin_ws/src/aero_control/package.xml`, then you can skip ahead to [Make Executables](communication_pipeline.html#Make-Executables)\n", "\n", "
\n", "\n", "This will create files `~/bwsi-uav/catkin_ws/src/aero_control/CMakeLists.txt` and `~/bwsi-uav/catkin_ws/src/aero_control/package.xml`. You'll want to track these new files on github, so add and commit them so you can later push them to your team's MIT GitHub:\n", "\n", "```\n", "cd ~/bwsi-uav/catkin_ws/src/aero_control\n", "git add CMakeLists.txt package.xml\n", "git commit -m \"starting aero_control as a package\"\n", "```\n", "\n", "#### Make Executables\n", "\n", "Next you need to make sure that `simple_talker.py` and `simple_listener.py` are _executable_ in order for the launch file to properly access them. This can be done as follows:\n", "\n", "```\n", "cd ~/bwsi-uav/catkin_ws/src/aero_control/communication_pipeline/src/\n", "chmod +x simple_talker.py\n", "chmod +x simple_listener.py\n", "```\n", "\n", "#### Launch File\n", "\n", "Now you are almost ready to run the launch file that starts `roscore`, `simple_talker.py`, and `simple_listener.py` simultaneously. We've given you part of the launch file in `aero_control/communication_pipeline/launch/simnple_talk_listen.launch`, but it's incomplete. Can you figure out what is missing and add it yourself?\n", "\n", "Once you've filled in the missing part of the launch file, follow these steps to run it\n", "\n", "```\n", "cd ~/bwsi-uav/catkin_ws/\n", "catkin_make\n", "source devel/setup.bash\n", "roslaunch aero_control simple_talk_listen.launch\n", "```\n", "\n", "You should see the print statement from `simple_listener.py` in your terminal.\n", "\n", "A useful tool for visualizing how information is being passed by ROS is `rqt_graph` (see references [here](http://wiki.ros.org/ROS/Tutorials/UnderstandingTopics#Using_rqt_graph) and [here](http://wiki.ros.org/rqt_graph) for more information. With `simple_talk_listen.launch` still running, open a new terminal and run:\n", "\n", "```\n", "rosrun rqt_graph rqt_graph\n", "```\n", "\n", "#### Question Set 3:\n", "\n", "1. What needed to be added the launch file?\n", "2. With `rqt_graph` open, use the button in upper right corner to save an image of the graph and include it in this report. Which components in the graph indicates rosnodes and which indicate rostopics?\n", "2. Why do we need to run the command `source devel/setup.bash` before running `roslaunch`?\n", "3. Were there any steps that didn't work or were particularly confusing? How did you work around them?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 4: Document and Push\n", "\n", "Congratulations! You have implemented one of the basic building blocks of ROS! Now that you have this demo complete, you will want to push your code changes to your team's MIT GitHub.\n", "\n", "First double check that the repository you are working with on your drone or laptop points to the correct remote repository. \n", "\n", "```\n", "cd ~/bwsi-uav/catkin_ws/src/aero_control\n", "git remote -v\n", "```\n", "\n", "should return 4 lines of information, the two lines that start with `origin` and end with `(fetch)` and `(push)` should contain the URL of your team's MIT GitHub repository for `aero_control`. If not, let one of the instructors know so we can sort it out.\n", "\n", "If that's all set and you ran the commit commands in the previous steps, you should now be able to push those changes to to your team's remote repositories with:\n", "\n", "```\n", "git push origin master\n", "```\n", "\n", "Finally, document the answers to question sets 1-3 and push those to your teams `documents` repository. You can write up the answers any way you want, but the easiest is probably to create a file called `communication_pipeline_answers.md`, and write a bullet point or paragraph for each question." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## MAVROS \n", "\n", "In the last section we passed basic messages between two nodes in ROS. This was done entirely in Ubuntu on the Aero Compute Board (or perhaps your laptop); it had no direct communication with the NuttX operating system that was running PX4 firmware on the Aero Flight Controller hardware. It we want our drones to fly autonomously, we need to be able to send commands to and receive sensor information from the flight controller.\n", "\n", "Communication with the PX4 Firmware running on the AeroFC board is managed with a service called [MAVLink](https://mavlink.io/en/). Similar to how ROS messages pass information between nodes on Ubuntu, MAVLink messages pass information between ROS/Ubuntu/Aero Compute Board and PX4/NuttX/AeroFC.\n", "\n", "The MAVLink protocol is low-level, which makes it powerful, extensible, but also complicated to use. To simplify our lives we will make use of [MAVROS](https://github.com/mavlink/mavros/tree/master/mavros). MAVROS can be thought of as a \"wrapper\" for MAVLink that simplifies the communication with ROS.\n", "\n", "\n", "### Step 1: Running MAVROS\n", "\n", "Let's start by getting MAVROS running. On the drone, use multiple terminals to run the following commands:\n", "\n", "_Terminal 1:_\n", "```\n", "roscore\n", "```\n", "\n", "_Terminal 2:_\n", "```\n", "rosrun mavros mavros_node _fcu_url:=tcp://127.0.0.1:5760 _system_id:=2\n", "```\n", "\n", "After answering the following questions you can kill these processes with `Ctrl-C`\n", "\n", "#### Question Set 1:\n", "\n", "1. What rosnodes are running?\n", "2. In a separate terminal run `rosnode info mavros`. Look through the list of `mavros` Subscriptions and Publications. Can you guess which topics could be used to send commands that control the drone? Which ones?\n", "3. Some of the topics that `mavros` subscribes and publishes to have similar sounding names because they serve related, but distinct, purpose. For example, can you guess what is the functional difference between Publication: `/mavros/local_position/velocity` and Subscription `/mavros/setpoint_velocity/cmd_vel_unstamped`?\n", "4. Inspect the messages being sent on the topic `mavros/extended_state`. Roughly how often do you get a new message? Do you think these messages originate from the Aero Compute Board or the AeroFC?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 2. Sending Commands\n", "\n", "Next we are going to use the `mavros` node to send commands to PX4 and receive information about the state of the quadrotor. Since we are only learning the communication structure of the drone, we won't actually be flying it with these commands, just observing that they get passed correctly.\n", "\n", "In `aero_control/communication_pipeline/src` you should find two other files `dispatcher.py` and `command_generator.py`. As with the previous section, these files are missing a block of code that you need to fill in; see the code for instructions on what needs to be completed.\n", "\n", "Once you have completed writing your code, let's test it out. On the drone in multiple terminals run:\n", "\n", "_Terminal 1:_\n", "```\n", "roscore\n", "```\n", "\n", "_Terminal 2:_\n", "```\n", "rosrun mavros mavros_node _fcu_url:=tcp://127.0.0.1:5760 _system_id:=2\n", "```\n", "\n", "_Terminal 3:_\n", "```\n", "cd ~/bwsi-uav/catkin_ws/src/aero_control/communication_pipeline/src\n", "python dispatcher.py\n", "```\n", "\n", "_Terminal 4:_\n", "```\n", "cd ~/bwsi-uav/catkin_ws/src/aero_control/communication_pipeline/src\n", "python command_generator.py\n", "```\n", "\n", "Assuming you got no errors, answer the following questions (if you did get errors, are you able to debug them?)\n", "\n", "#### Question Set 2:\n", "\n", "1. What new nodes and topics were created by running dispatcher.py and command_generator.py that weren't present when just running mavros?\n", "2. Inspect the messages being sent on `/velocity_command` and `/mavros/setpoint_velocity/cmd_vel_unstamped`. Do they appear to be the same? Are the being passed at roughly the same rate? Which one is actually being sent to the PX4/AeroFC?\n", "3. Why would we want to impose a limit on the velocity command sent to the flight controller?\n", "4. As with the previous section, it is cumbersome to run each command in a separate terminal. To this end we have included a partial launch file in `aero_control/communication_pipeline/launch/mavros.launch`. Can you complete the launch file and run it in order to kick off mavros, dispatcher, and command_generator simultaneously?\n", "5. When all nodes are running, use rqt_graph to generate an image of the nodes and topics.\n", "\n", "### Step 3: Document and Push\n", "\n", "As before, document the answers to the preceeding question sets and push them to your team's `documents` repository" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Advanced Topics: uORB\n", "\n", "So far we have only seen communication on the Aero Compute Board and how to pass messages to the Aero Flight Controller. We haven't actually looked at message passing that occurs onboard the Aero Flight Controller in the PX4 firmware. The Aero Flight Controller uses a different system known as \"uORB\". We will cover this in a later lecture but you can learn more uORB in the link below:\n", "\n", " - [uORB Messaging](https://dev.px4.io/en/middleware/)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.8" } }, "nbformat": 4, "nbformat_minor": 2 }