Showing posts with label ROS. Show all posts
Showing posts with label ROS. Show all posts

Wednesday, October 31, 2018

ROS Service client

  • Terminal 1
roscore
  • Terminal 2
rosrun turtlesim turtlesim_node
  • Terminal 3
rosservice list /clear /kill /reset /rosout/get_loggers /spawn /turtle1/set_pen /turtle1/teleport_absolute /turtle1/teleport_relative /turtlesim/get_loggers

spawn service

Spawn another turtle with spawn service

  • rosservice info <service name>
rosservice info /spawn Node: /turtlesim URI: rosrpc://user-N56VM:43083 Type: turtlesim/Spawn Args: x y theta name
  • rossrv info <service type>
float32 x float32 y float32 theta string name --- string name

call / execute

#left down corner: 0,0 rosservice call /spawn "x: 3.0 y: 3.0 theta: 0.0 name: 't1'"

service client

  • rosservice info result show the the service implement in /turtlesim package

  • most simple service client (without error handler)

#!/usr/bin/env python import rospy from turtlesim.srv import Spawn def main(): service = rospy.ServiceProxy('/spawn', Spawn) service(x=3.0, y=3.0, theta=0.0, name="t1") if __name__ == "__main__": main()

Service client send Request and server answer with response

The service declare by service message that has tow parts request and response

request --- response
  • For example Spawn.srv file under turtlesim.srv folder
float32 x float32 y float32 theta string name --- string

When compile the packaged catkin build and install class file that contains the class for example:

  • Spawn
  • SpawnRequest
  • SpawnResponse
#!/usr/bin/env python import rospy from turtlesim.srv import Spawn, SpawnRequest def main(): service = rospy.ServiceProxy('/spawn', Spawn) req = SpawnRequest(x=3.0, y=3.0, theta=0.0, name="t1") res = service(req) print res.name if __name__ == "__main__": main

Saturday, October 27, 2018

ROSPy node templates

Spin and Rate

spin() and rate() are resposible to handle communication events, e.g. arriving messages. If you are subscribing messages, services or actions you must call them to process the events.

Using rospy.rate

  • rospy rate
#! /usr/bin/env python import rospy from datetime import datetime NODE_NAME = "reading_laser" def my_shutdown(): rospy.loginfo("Shutdown node") def main(): rospy.init_node(NODE_NAME) rospy.loginfo("Init node: {}".format(NODE_NAME)) rospy.on_shutdown(my_shutdown) rate = rospy.Rate(1) while not rospy.is_shutdown(): rate.sleep() rospy.loginfo(datetime.now().strftime("%b %d %Y %H:%M:%S")) if __name__ == "__main__": main()
  • Loop run every one second (rate 1 Hz)
  • Run Node (don't forget to chmod)
[INFO] [1540546445.840602]: Init node: reading_laser [INFO] [1540546446.842748]: Oct 26 2018 12:34:06 [INFO] [1540546447.842572]: Oct 26 2018 12:34:07 [INFO] [1540546448.842655]: Oct 26 2018 12:34:08

Using rospy.spin

  • main thread wait for shutdown (ctrl-c)
  • Other event are invoked
#! /usr/bin/env python import rospy from datetime import datetime NODE_NAME = "reading_laser" def my_shutdown(): rospy.loginfo("Shutdown node") def main(): rospy.init_node(NODE_NAME) rospy.loginfo("Init node: {}".format(NODE_NAME)) rospy.on_shutdown(my_shutdown) while not rospy.is_shutdown(): rospy.spin() if __name__ == "__main__": main()

Friday, October 12, 2018

ROS Follow the line

Gazebo image topics

  • Terminal1 (gazebo turtlebot)
roslaunch turtlebot_gazebo turtlebot_world.launch
  • Terminal2
rostopic list
  • depth camera
  • rgb camera
    • raw: raw image
    • compress: compress image
    • theora: compress video

ROS sent image useing sensor_msgs/Image

Follower node

  • subscribe to /camera/rgb/image_raw topic receive Image msg
#!/usr/bin/env python import rospy from sensor_msgs.msg import Image def image_callback(msg): pass def main(): rospy.init_node("follower") rospy.loginfo("start node") sub = rospy.Subscriber("/camera/rgb/image_raw", Image, image_callback) while not rospy.is_shutdown(): rospy.spin() if __name__ == "__main__": main()
  • Set node permission (chmod +x)
  • Run in separated Terminal
rosrun <package_name> follower.py
  • Check that the node is running
  • Get node info with rosnode info /follower
  • Check message receive interval
rostopic hz /camera/rgb/image_raw subscribed to [/camera/rgb/image_raw] WARNING: may be using simulated time average rate: 30.208 min: 0.010s max: 0.060s std dev: 0.01642s window: 30 average rate: 28.061 min: 0.010s max: 0.060s std dev: 0.01638s window: 56

Setup follow the line

launch file and projects structure

  • launch file
    • worlds
  • gazebo resource
    • materials
├── launch │   └── follow.launch ├── materials │   ├── course.material │   └── course.png ├── models ├── scripts │   └── follower.py ├── src └── worlds └── course.world
<?xml version="1.0"?> <launch> <env name="GAZEBO_RESOURCE_PATH" value="$(find follow_bot)/materials:$(optenv GAZEBO_RESOURCE_PATH)" /> <include file="$(find gazebo_ros)/launch/empty_world.launch"> <arg name="world_name" value="$(find follow_bot)/worlds/course.world"/> </include> <include file="$(find turtlebot_gazebo)/launch/includes/kobuki.launch.xml"> <arg name="base" value="kobuki"/> <arg name="stacks" value="hexagons"/> <arg name="3d_sensor" value="kinect"/> </include> </launch>

Note: launch file set GAZEBO_RESOURCE_PATH environment variable using env tag

View image

#!/usr/bin/env python import rospy from sensor_msgs.msg import Image import cv2 import cv_bridge class Follower(object): def __init__(self): self._bridge = cv_bridge.CvBridge() sub = rospy.Subscriber("/camera/rgb/image_raw", Image, self.image_callback) def image_callback(self, msg): image = self._bridge.imgmsg_to_cv2(msg,desired_encoding='bgr8') cv2.imshow("window", image) cv2.waitKey(3) def on_shutdown(): rospy.loginfo("shutdown") cv2.destroyAllWindows() def main(): rospy.init_node("follower") rospy.loginfo("start node") rospy.on_shutdown(on_shutdown) while not rospy.is_shutdown(): follower = Follower() rospy.spin() if __name__ == "__main__": main()

Note: When we use the cv2.namedWindow Method the Window was freeze check the line solution

Detecting the line

  • Find the yellow line
lower_yellow = numpy.array([ 50, 50, 170]) upper_yellow = numpy.array([255, 255, 190]) mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
  • left: orignal
  • center: mask imaged (binary)
  • right: masked image (extrat only the line from orignal image)

Find line center

  • Mask image and take only relevant part (closer path front to the robot)

  • Find line center with cv2 moments method
  • For debug draw circle on line centroid
M = cv2.moments(mask) if M['m00'] > 0: cx = int(M['m10']/M['m00']) cy = int(M['m01']/M['m00']) cv2.circle(image, (cx, cy), 20, (0,0,255), -1)

- Public `Twist` message , calc z angular value ```python #delta/ error between line center to image center delta = cx - w/2 twist = Twist() twist.linear.x = 0.2 twist.angular.z = -float(delta) / 100 self._cmd_vel_pub.publish(twist)

Final demo

Reference

Tuesday, October 9, 2018

ROS OpenCV hello

ros kinetic work with openCV 3.1

sudo apt install ros-kinetic-opencv3
  • after install check with python
> import cv2 > cv2.__version__ '3.3.1-dev'
  • Install helper utils and packages
sudo apt install ros-kinetic-usb-cam sudo apt install ros-kinetic-image-view

CvBridge

Convert ROS image messages (sensor_msgs/Images) and OpenCv images (cv::Mat)

Demo

  • Use as Gazebo camera plugin post as Image source
  • Create package named cv_demo run the source code as rosnode cvnode.py package dependencies: sensor_msgs, opencv2, cv_bridge, rospy
  • The node create OpenCv image window
  • Use rqt to view publish image image_topic

Demo setup

  • Terminal 1 (gazebo as image source)
roslaunch gazebo_ros empty_world.launch
  • Terminal 2 (spawn camera)
rosrun gazebo_ros spawn_model -file camera.urdf -urdf -model bot
  • Termianl 3 (run our node)
rosrun cv_demo cvnode.py
  • Termianl 4 (rqt)
rqt

Reference

Source code

#!/usr/bin/env python import rospy import cv2 from cv_bridge import CvBridge, CvBridgeError import numpy as np from sensor_msgs.msg import Image, CameraInfo class CvBridgeDemo(object): NODE_NAME = "cv_demo" WIN_NAME = "cv_demo_win" def __init__(self): self._bridge = CvBridge() self.image_sub = rospy.Subscriber("/bot/camera/image_raw", Image, self.image_callback) self.image_pub = rospy.Publisher("image_topic", Image) rospy.loginfo("watting for image") def image_callback(self, ros_image): # Use cv_bridge() to convert the ROS image to OpenCV format bridge = self._bridge try: frame = bridge.imgmsg_to_cv2(ros_image, "bgr8") except CvBridgeError, e: rospy.logerr("fail convert ros image to cv: {}".format(e)) # Convert the image to a Numpy array for cv2 functions frame = np.array(frame, dtype=np.uint8) # Process the frame using the process_image() function display_image = self.process_image(frame) # Display the image. cv2.imshow(CvBridgeDemo.WIN_NAME, display_image) # Process any keyboard commands cv2.waitKey(3) try: self.image_pub.publish(self._bridge.cv2_to_imgmsg(display_image, "mono8")) except CvBridgeError as e: rospy.logerr("fail convert cv image to rosmsg: {}".format(e)) def process_image(self, frame): img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv2.LINE_AA) return img def on_shutdown(): print "Shutting down cvnode." cv2.destroyAllWindows() def main(): rospy.init_node(CvBridgeDemo.NODE_NAME) rospy.on_shutdown(on_shutdown) while not rospy.is_shutdown(): CvBridgeDemo() rospy.loginfo("wait for shutdown") #The spin() code simply sleeps until the is_shutdown() flag is True. # It is mainly used to prevent your Python Main thread from exiting. rospy.spin() if __name__ == '__main__': main()

Friday, September 7, 2018

ROS REP and CodeStyle

REP - ROS Enhancement Proposal 

  • REP-103: Standard Units of Measure and Coordinate Conventions
  • REP-144: ROS Package Naming


ROS  Code Style Guide

ROS Projects Tips 

Thursday, September 6, 2018

Gazebo and URDF model

source code

Catkin package

catkin_create_pkg demo_gazebo rospy cd demo_gazebo mkdir launch mkdir urdf

Minimal urdf file

The inertia matrix explained

<?xml version="1.0"?> <robot name="robot"> <link name="base_link"> <collision> <origin xyz="0 0 1" rpy="0 0 0"/> <geometry> <box size="2 2 2"/> </geometry> </collision> <visual> <origin xyz="0 0 1" rpy="0 0 0"/> <geometry> <box size="2 2 2"/> </geometry> <material name="orange"/> </visual> <inertial> <origin xyz="0 0 1" rpy="0 0 0"/> <mass value="1"/> <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/> </inertial>> </link> </robot>

Spawn models

  • Using launch file
<launch> <param name="robot_description" textfile="$(find demo_gazebo)/urdf/robot_description.urdf" /> <include file="$(find gazebo_ros)/launch/empty_world.launch"/> <node name="spawn_urdf" pkg="gazebo_ros" type="spawn_model" args="-param robot_description -urdf -model my_robot" /> </launch>
  • Using rosrun
rosrun gazebo_ros spawn_model -file `rospack find demo_gazebo`/urdf/robot_description.urdf -urdf -z 1 -model my_robot

Gazebo services

  • Check if mode loaded
rosservice call /gazebo/get_world_properties sim_time: 1155.376 model_names: [ground_plane, my_robot] rendering_enabled: True success: True
  • Delete model
rosservice call /gazebo/delete_model "model_name: 'my_robot'" success: True status_message: "DeleteModel: successfully deleted model"

ROS python node

  • Call service to insert model into
#! /usr/bin/env python import rospy from gazebo_msgs.srv import SpawnModel from geometry_msgs.msg import Pose rospy.init_node('insert_object',log_level=rospy.INFO) initial_pose = Pose() initial_pose.position.x = 1 initial_pose.position.y = 1 initial_pose.position.z = 1 f = open('/home/user/simulation_ws/src/demo_gazebo/urdf/robot_description.urdf','r') urdff = f.read() rospy.wait_for_service('gazebo/spawn_urdf_model') spawn_model_proxy = rospy.ServiceProxy('gazebo/spawn_urdf_model', SpawnModel) spawn_model_proxy("some_robot_name", urdff, "robotos_name_space", initial_pose, "world")

Tuesday, September 4, 2018

PX4 SITL mavros and gazebo

Setup and run

  • Terminal 1 Setting environment
cd <Firmware_clone> make posix_sitl_default gazebo source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/posix_sitl_default export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$(pwd) export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$(pwd)/Tools/sitl_gazebo
  • Terminal 1 (launch gazebo and SITL)
roslaunch px4 posix_sitl.launch
  • Terminal 2 (launch mavros)
roslaunch mavros px4.launch fcu_url:="udp://:14540@127.0.0.1:14557"
  • Terminal 3 (mavros commands: call services)
rosservice call /mavros/set_mode "base_mode: 0 custom_mode: 'OFFBOARD'" rosservice call /mavros/cmd/arming "value: true" rosservice call /mavros/cmd/takeoff "{min_pitch: 0.0, yaw: 0.0, latitude: 0.0, longitude: 0.0, altitude: 10.0}"

Sunday, September 2, 2018

Ardupilot and MAVROS

Install MAVROS

sudo apt-get install ros-kinetic-mavros ros-kinetic-mavros-extras
  • GCS — Ground Control Station
  • FCU — Flight Control Unit (pixhawk)
  • OBC — OnBoard Computer (your odroid or raspberry)

Run SITL and ROS

Terminal 1 (sitl)

sim_vehicle.py -v ArduCopter --console

Terminal 2 (launch)

udp://[bind_host][:port]@[remote_host[:port]][/?ids=sysid,compid] roslaunch mavros apm.launch fcu_url:=udp://127.0.0.1:14551@14555

rqt (Terminal 3)

Use GUI to control (call service, monitor and pub topics)

rqt
  • plugins -> robots tools -> runtime monitor

Set mode

  • plugins -> Services -> Service Caller
  • from service combo select /mavros/set_mode

Reference

Tuesday, August 28, 2018

ROS LIVE_CLASS

Start to follow and implement LIVE CLASS from "The Construct"
are a greate and funny guide

#13:ROS Navigation Stack How To

In this ROS LIVE-Class Ricardo show how to
making a differential drive robot create a map (SLAM), localize on that map (robot localization), and then navigate on the environment using the map (path planning and obstacle avoidance).

#14: How To Control Robot Joints With ROS

In this ROS LIVE-Class Ricardo show how to add ROS control to a joint in a simulated robot

#19: Let’s Use Gazebo Plugins

In this ROS LIVE-Class Ricardo show how to create a Gazebo plugin for a robot simulated world. The plugin will allow us to connect/disconnect the light of the world by means of a ROS topic .

Sunday, August 5, 2018

VSCode tips for ROS

Tip1 - Adding a file extension to a language

You can add new file extensions to an existing language with the files.associations setting, for example assign gazebo .world file to XML

"files.associations":{
 ".world": "xml"
}


Tip2 - use code runner to check urdf files

code runner:  Run code snippet or code file for multiple languages
  • install 'Code runner' extension into vscode 
  • install check_urdf (apt-get install liburdfdom-tools)
  • from settings append file extension into code runner mapping
"code-runner.executorMapByFileExtension": { 
".urdf": "check_urdf"

Tip3 - use code runner to check xacro files

ROS node xacro in package xacro convert xacro  file to urdf

rosrun xacro xacro <file_name.xacro>

The idea is to run the above command redirect the output to tmp file and then run check_urdf on it.

"files.associations":{
".xacro": "rosrun xacro xacro --inorder $fullFileName > /tmp/tmp.urdf && check_urdf /tmp/tmp.urdf"
}


code runner supported parameters
  • $workspaceRoot: The path of the folder opened in VS Code
  • $dir: The directory of the code file being run
  • $dirWithoutTrailingSlash: The directory of the code file being run without a trailing slash
  • $fullFileName: The full name of the code file being run
  • $fileName: The base name of the code file being run, that is the file without the directory
  • $fileNameWithoutExt: The base name of the code file being run without its extension

Monday, July 30, 2018

ROS in 5 mins

A series of 5 minutes (or more) videos about  different topics in ROS from "The Construct"

023 - Understanding ROS Coordinate Frame (Part 1 /2)

coordinate frames convention , linear and angular motion
Which X are forward, which direction are positive rotation

110 - How to launch two drones on a Single Gazebo Simulation

Show you how you can launch two drones (or more) in the same Gazebo simulation, each one having its own independent control system based on ROS. This procedure can be replicated to launch as many drones as required.

044 - How to convert quaternions to Euler angles

The following example can help you understand how to use the conversion from quaternions provided by an Odometry message to Euler angles Roll, Pitch and Yaw.

135 -How to rotate a robot to a desired heading using feedback from odometry

Rotate our robot based on data from odometry. We will subscribe to /odom topic to get the heading of our robot, process it, and then send a command over the
/cmd_vel_mux/input/teleop topic.

070 - Moving Joints in Gazebo Simple Example

Create URDF, add the ros control plugin, and include a config file to configure the plugin. launch and send commands (see README.md)

 

VSCode ROS extensions

List of nice VSCode extensions helping work with ROS

Special for ROS

Common but useful
  • Python (link)
  • XML Tools (link)
  • YAML Support by Red Hat (link)


Good ROS Tutorials



Here is a list of good ROS tutorials that i done


This project is about using a Two Wheeled Mobile Robot to explore features and tools provided by ROS (Robot Operating System). We start building the robot from the scratch, using URDF (Unified Robot Description Format) and RViz to visualize it. Further, we describe the inertia and show how to simplify the URDF using XACROS. Later, motion planning algorithms, such as Obstacle Avoidance and Bugs 0, 1 and 2 are developed to be used in the built robot. Some ROS packages, like robot_localization, are used to built a map and localize on it.
My source code
5 golden tutorials


My source code

Gaitech EDU is an educational website on robotics and in particular on Robot Operating System (ROS). The objective is to provide an easy-to-follow educational content that helps in better mastering the concepts of ROS and promoting its use for developing robotics software