-
Notifications
You must be signed in to change notification settings - Fork 14
Atlas control over ROS with python
This tutorial will demonstrate how to control the Atlas robot with a joint trajectory controller. In the course of this tutorial we're going to make the Atlas robot try to take a step. It will fall down, and that's OK, because our trajectory is incredibly simple and not at all reactive. You're welcome to extend the example here to make the robot walk or go through other motions.
We're using the ROS topics demonstrated in the previous tutorial that used C++. This general-purpose controller can be used to make a set of joints follow a desired trajectory specified as joint angles. The controller is executed as part of a Gazebo plugin. This arrangement allows the controller to run in-line with the simulation, approximating the on-robot situation in which the controller runs in a real-time environment.
Important note: The approach to robot control described here is not the best or only way to control the Atlas robot. It is provided for demonstration purposes. DRC participants should be aware that we expect the control system in simulation to change substantially as more sophisticated controller become available.
Click to see the instructions for installing the DRC simulator and associated utilities.
If you haven't already, create a ros directory in your home directory and add it to your $ROS_PACKAGE_PATH. From the command line
mkdir ~/ros
echo "export ROS_PACKAGE_PATH=${HOME}/ros:${ROS_PACKAGE_PATH}" >> ~/.bashrc
source ~/.bashrc
Use roscreate-pkg to create a ROS package for this tutorial, depending on a ROS package called osrf_msgs:
cd ~/ros
roscreate-pkg tutorial_atlas_control osrf_msgs
Move to the directory tutorial_atlas_control
roscd tutorial_atlas_control
Copy the file traj_yaml.py into it:
#!/usr/bin/env python
import roslib; roslib.load_manifest('tutorial_atlas_control')
import rospy, yaml, sys
from osrf_msgs.msg import JointCommands
from sensor_msgs.msg import JointState
from numpy import zeros, array, linspace
from math import ceil
atlasJointNames = [
'atlas::back_lbz', 'atlas::back_mby', 'atlas::back_ubx', 'atlas::neck_ay',
'atlas::l_leg_uhz', 'atlas::l_leg_mhx', 'atlas::l_leg_lhy', 'atlas::l_leg_kny', 'atlas::l_leg_uay', 'atlas::l_leg_lax',
'atlas::r_leg_uhz', 'atlas::r_leg_mhx', 'atlas::r_leg_lhy', 'atlas::r_leg_kny', 'atlas::r_leg_uay', 'atlas::r_leg_lax',
'atlas::l_arm_usy', 'atlas::l_arm_shx', 'atlas::l_arm_ely', 'atlas::l_arm_elx', 'atlas::l_arm_uwy', 'atlas::l_arm_mwx',
'atlas::r_arm_usy', 'atlas::r_arm_shx', 'atlas::r_arm_ely', 'atlas::r_arm_elx', 'atlas::r_arm_uwy', 'atlas::r_arm_mwx']
currentJointState = JointState()
def jointStatesCallback(msg):
global currentJointState
currentJointState = msg
if __name__ == '__main__':
# first make sure the input arguments are correct
if len(sys.argv) != 3:
print "usage: traj_yaml.py YAML_FILE TRAJECTORY_NAME"
print " where TRAJECTORY is a dictionary defined in YAML_FILE"
sys.exit(1)
traj_yaml = yaml.load(file(sys.argv[1], 'r'))
traj_name = sys.argv[2]
if not traj_name in traj_yaml:
print "unable to find trajectory %s in %s" % (traj_name, sys.argv[1])
sys.exit(1)
traj_len = len(traj_yaml[traj_name])
# Setup subscriber to atlas states
rospy.Subscriber("/atlas/joint_states", JointState, jointStatesCallback)
# initialize JointCommands message
command = JointCommands()
command.name = list(atlasJointNames)
n = len(command.name)
command.position = zeros(n)
command.velocity = zeros(n)
command.effort = zeros(n)
command.kp_position = zeros(n)
command.ki_position = zeros(n)
command.kd_position = zeros(n)
command.kp_velocity = zeros(n)
command.i_effort_min = zeros(n)
command.i_effort_max = zeros(n)
# now get gains from parameter server
rospy.init_node('tutorial_atlas_control')
for i in xrange(len(command.name)):
name = command.name[i]
command.kp_position[i] = rospy.get_param('atlas_controller/gains/' + name[7::] + '/p')
command.ki_position[i] = rospy.get_param('atlas_controller/gains/' + name[7::] + '/i')
command.kd_position[i] = rospy.get_param('atlas_controller/gains/' + name[7::] + '/d')
command.i_effort_max[i] = rospy.get_param('atlas_controller/gains/' + name[7::] + '/i_clamp')
command.i_effort_min[i] = -command.i_effort_max[i]
# set up the publisher
pub = rospy.Publisher('/atlas/joint_commands', JointCommands, queue_size=1)
# for each trajectory
for i in xrange(0, traj_len):
# get initial joint positions
initialPosition = array(currentJointState.position)
# get joint commands from yaml
y = traj_yaml[traj_name][i]
# first value is time duration
dt = float(y[0])
# subsequent values are desired joint positions
commandPosition = array([ float(x) for x in y[1].split() ])
# desired publish interval
dtPublish = 0.02
n = ceil(dt / dtPublish)
for ratio in linspace(0, 1, n):
interpCommand = (1-ratio)*initialPosition + ratio * commandPosition
command.position = [ float(x) for x in interpCommand ]
pub.publish(command)
rospy.sleep(dt / float(n))
Then download the Traj_data2.yaml YAML file of a few trajectories, and place it in the same directory (~/ros/tutorial_atlas_control).
If you haven't brought down your previous instance of the DRC simulator, kill the process by pressing Control + C in it's terminal. Now launch the robot
roslaunch drcsim_gazebo atlas.launch
You should see the Atlas standing in an empty world. It will likely sway back and forth; that's an artifact of the controllers holding position on the joints.
In a separate terminal, put Atlas in User mode:
rostopic pub /atlas/control_mode std_msgs/String -- "User"
In a separate terminal, run the node that you just built:
roscd tutorial_atlas_control
python traj_yaml.py Traj_data2.yaml step_and_fall
You should see the robot try to take a step with its right leg and then fall down.
Here is another trajectory, since it's football season:
python traj_yaml.py Traj_data2.yaml touchdown
Then, just for fun:
python traj_yaml.py Traj_data2.yaml touchdown_exhausted
To try it again, go to the Gazebo "Edit" menu and click on "Reset Model Poses" (you might need to do this several times, use Shift+Ctrl+R for convenience). That will teleport the robot back to its initial pose, from where you can run a trajectory again. In this way, you can iterate, making changes to the program sending the trajectory and checking the effect in simulation, without shutting everything down.
#!/usr/bin/env python
import roslib; roslib.load_manifest('tutorial_atlas_control')
import rospy, yaml, sys
from osrf_msgs.msg import JointCommands
from sensor_msgs.msg import JointState
from numpy import zeros, array, linspace
from math import ceil
Specify the names of the joints in the correct order.
atlasJointNames = [
'atlas::back_lbz', 'atlas::back_mby', 'atlas::back_ubx', 'atlas::neck_ay',
'atlas::l_leg_uhz', 'atlas::l_leg_mhx', 'atlas::l_leg_lhy', 'atlas::l_leg_kny', 'atlas::l_leg_uay', 'atlas::l_leg_lax',
'atlas::r_leg_uhz', 'atlas::r_leg_mhx', 'atlas::r_leg_lhy', 'atlas::r_leg_kny', 'atlas::r_leg_uay', 'atlas::r_leg_lax',
'atlas::l_arm_usy', 'atlas::l_arm_shx', 'atlas::l_arm_ely', 'atlas::l_arm_elx', 'atlas::l_arm_uwy', 'atlas::l_arm_mwx',
'atlas::r_arm_usy', 'atlas::r_arm_shx', 'atlas::r_arm_ely', 'atlas::r_arm_elx', 'atlas::r_arm_uwy', 'atlas::r_arm_mwx']
Create a ROS callback for reading the JointState message published on /atlas/joint_states
currentJointState = JointState()
def jointStatesCallback(msg):
global currentJointState
currentJointState = msg
Import the files that we need.
if __name__ == '__main__':
# first make sure the input arguments are correct
if len(sys.argv) != 3:
print "usage: traj_yaml.py YAML_FILE TRAJECTORY_NAME"
print " where TRAJECTORY is a dictionary defined in YAML_FILE"
sys.exit(1)
traj_yaml = yaml.load(file(sys.argv[1], 'r'))
traj_name = sys.argv[2]
if not traj_name in traj_yaml:
print "unable to find trajectory %s in %s" % (traj_name, sys.argv[1])
sys.exit(1)
traj_len = len(traj_yaml[traj_name])
Set up the joint states subscriber.
# Setup subscriber to atlas states
rospy.Subscriber("/atlas/joint_states", JointState, jointStatesCallback)
Initialize the joint command message.
# initialize JointCommands message
command = JointCommands()
command.name = list(atlasJointNames)
n = len(command.name)
command.position = zeros(n)
command.velocity = zeros(n)
command.effort = zeros(n)
command.kp_position = zeros(n)
command.ki_position = zeros(n)
command.kd_position = zeros(n)
command.kp_velocity = zeros(n)
command.i_effort_min = zeros(n)
command.i_effort_max = zeros(n)
Get the current controller gains from the parameter server.
# now get gains from parameter server
rospy.init_node('tutorial_atlas_control')
for i in xrange(len(command.name)):
name = command.name[i]
command.kp_position[i] = rospy.get_param('atlas_controller/gains/' + name[7::] + '/p')
command.ki_position[i] = rospy.get_param('atlas_controller/gains/' + name[7::] + '/i')
command.kd_position[i] = rospy.get_param('atlas_controller/gains/' + name[7::] + '/d')
command.i_effort_max[i] = rospy.get_param('atlas_controller/gains/' + name[7::] + '/i_clamp')
command.i_effort_min[i] = -command.i_effort_max[i]
Set up the joint command publisher.
# set up the publisher
pub = rospy.Publisher('/atlas/joint_commands', JointCommands, queue_size=1)
Read in each line from the yaml file as a trajectory command, and the current joint states from the ROS topic. Publish trajectory commands that interpolate between the initial state and the desired position to generate a smooth motion.
# for each trajectory
for i in xrange(0, traj_len):
# get initial joint positions
initialPosition = array(currentJointState.position)
# get joint commands from yaml
y = traj_yaml[traj_name][i]
# first value is time duration
dt = float(y[0])
# subsequent values are desired joint positions
commandPosition = array([ float(x) for x in y[1].split() ])
# desired publish interval
dtPublish = 0.02
n = ceil(dt / dtPublish)
for ratio in linspace(0, 1, n):
interpCommand = (1-ratio)*initialPosition + ratio * commandPosition
command.position = [ float(x) for x in interpCommand ]
pub.publish(command)
rospy.sleep(dt / float(n))
-
Robot Simulators
-
Build a Robot
- Model structure and requirements
- How to contribute a model
- Make a model
- Make a Mobile Robot
- The relationship among Link, Joint and Axis
- Import Meshes
- Attach Meshes
- Add a Sensor to a Robot
- Make a Simple Gripper
- Attach Gripper to Robot
- Nested model
- Model Editor
- Animated Box
- Make an animated model(actor)
- Inertial parameters of triangle meshes
- Visibility layers
-
Model Editor
-
Build a World
-
Tools and utilities
-
Write a plugin
-
Plugins
-
Sensors
-
User input
-
Transport Library
-
Rendering Library
-
Connect to ROS
-
Ros Control - Advanced
-
DRCSIM for ROS Kinetic (Ubuntu16.04)
-
DRCSIM
- DRC Simulator installation
- Launchfile options
- Spawn Atlas into a custom world
- Animate joints
- Atlas Keyboard Teleoperation over ROS
- Teleoperate atlas with a music mixer
- Visualization and logging
- Atlas MultiSense SL head
- How to use the Atlas Sim Interface
- Atlas fake walking
- Grasp with Sandia hands
- DRC vehicle tele-operation
- DRC vehicle tele operation with Atlas
- Sending joint commands with ROS
- Atlas control over ROS with python
- Modify environment
- Atlas switching control modes
- Atlas Controller Synchronization over ROS Topics
- Changing Viscous Damping Coefficients Over ROS Service
- Running BDI controller demo
- Using the RobotiQ 3 Finger Adaptive Robot Gripper
- BDI Atlas Robot Interface 3.0.0 Stand In Example
-
HAPTIX
- HAPTIX software install and update
- HAPTIX C API
- HAPTIX Matlab and Octave API
- HAPTIX Simulation World API
- HAPTIX Teleoperation
- HAPTIX environment setup
- HAPTIX Optitrack Control
- HAPTIX Tactor Glove
- HAPTIX Simulation World API with Custom World Example
- HAPTIX logging
- HAPTIX DEKA Luke hand installation
- HAPTIX Simulation Scoring Plugin Example
-
MoveIt!
-
Rviz & rqt & ROSBAG
- Control Theory
- TroubleShooting
- Solidworks model to URDF
- ROS-Gazebo with MATLab
- MATLab installation in Linux
- [Gazebo simulation with MATLab]