├── .gitattributes
├── README.md
├── ati_sensor
├── CMakeLists.txt
├── include
│ └── ft_sensor.h
├── launch
│ └── ft_sensor.launch
├── package.xml
└── src
│ ├── ft_sensor.cpp
│ └── ft_sensor_node.cpp
├── ur5_admittance_control
├── CMakeLists.txt
├── config
│ └── admittance_params.yaml
├── include
│ └── AdmittanceController.h
├── launch
│ └── admittance_controller.launch
├── msg
│ └── PoseTwist.msg
├── package.xml
└── src
│ ├── AdmittanceController.cpp
│ └── admittance_controller_node.cpp
├── ur5_bringup
├── CMakeLists.txt
├── config
│ └── initial_pose.yaml
├── controllers
│ ├── joint_state_controller.yaml
│ └── ur5_vel_controller.yaml
├── launch
│ ├── init_pose_start_controllers.launch
│ ├── robot_bringup.launch
│ ├── ur5_bringup.launch
│ └── ur_force_control.launch
├── package.xml
├── rviz
│ └── admittance_fake_wrench.rviz
├── src
│ ├── fake_wrench.py
│ ├── init_pose_start_controllers.py
│ └── timed_roslaunch.sh
├── urdf
│ ├── ur5.urdf.xacro
│ └── ur5_description.urdf.xacro
└── worlds
│ ├── bifurcation.world
│ └── empty.world
└── ur5_cartesian_velocity_control
├── CMakeLists.txt
├── config
└── controllers.yaml
├── include
└── ur5_cartesian_velocity_control
│ ├── cartesian_state_controller.h
│ ├── cartesian_velocity_controller.h
│ └── kinematic_chain_controller_base.h
├── launch
└── load_controller.launch
├── package.xml
├── src
├── cartesian_state_controller.cpp
└── cartesian_velocity_controller.cpp
└── ur5_cartesian_velocity_control_plugin.xml
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Compliation and build
2 |
3 | You also need the following ros packages
4 | ```bash
5 | $ sudo apt-get install ros-indigo-ridgeback-*
6 | $ sudo apt-get install ros-indigo-universal-robot
7 | ```
8 | if you are getting error for broken packages (most probably due to a wrong version of gazebo), you can use 'aptitude' instead of 'apt-get' which propose a solution and resolve the conflict.
9 |
10 |
11 | Finally complie
12 | ```bash
13 | $ cd ~/catkin_ws
14 | $ catkin_make
15 | $ source devel/setup.bash
16 | $ catkin_make
17 | ```
18 | * you might need the source the bash file and compie again if the first compliation could not find some of in house dependencies.
19 |
20 |
21 | For simulator, you can use gazebo7
22 | ```bash
23 | $ sudo apt-get install ros-indigo-gazebo7-*
24 | ```
25 | You might need to follow [these instructions](http://gazebosim.org/tutorials?tut=install_ubuntu#Alternativeinstallation:step-by-step).
26 |
27 | ---
28 | ---
29 |
30 |
31 |
32 | # Control Architecture
33 |
34 | ## Kinematics and transformations
35 |
36 | Here is a short list of important frames and their usage.
37 |
38 | | frame id | Usage |
39 | |---------------|-----------------------------------|
40 | | world | Odometry and navigation |
41 | | ur5_arm_base_link | Arm pose and twist |
42 | | base_link | Platform pose and twist |
43 | | robotiq_force_torque_frame_id | External force applied to the end-effector |
44 |
45 |
46 |
47 |
48 |
49 | ## Adamittance dynamics
50 | The following figure shows the controller architecture for the admittance control on the robot.
51 |
52 | 
53 |
54 | The two equations in the center describe the admittance dynamics which compute the desired accelaration for the arm and the platform. These accelerations are integrated in time to acheive the desired velocities for the robot. The low-level velocity controller fullfills these velocities. In the case of platform, the computed velocities can be modified accroding to obstacle avoidance node.
55 |
56 |
57 |
58 | The admittance parameters (shown in purple) are as follows:
59 |
60 | | Variable | Parameter |
61 | |---------------|-----------------------------------|
62 | | Ma | Desired mass of the arm |
63 | | Da | Desired damping of the arm |
64 | | Dc | Desired damping of the coupling |
65 | | Kc | Desired Stiffness of the coupling |
66 | | Mp | Desired mass of the platform |
67 | | Dp | Desired damping of the platform |
68 |
69 | These parameters are load from a yaml through the launch file.
70 |
71 |
72 | ### External force
73 | The external is initially measured by the force/torque sensor in its own frame reference. In admittance controller this force is transformed to "ur5_arm_base_link" where the control of arm takes place. To avoid reacting to small forces a deadzone is considered. Moreover, a low-pass filter is used to smooth the measurements. The parameters of the deadzone and the filter can be set from the launch file.
74 |
75 | ### Higher-level control (Motion planning )
76 | Through a higher level controller, the position of the equilibrium can be can be changed to acheive a desired behavior. Also, Fc can be used for control purposes; e.g., to compensate for the mass of an object carried by the arm.
77 |
78 | [](https://youtu.be/7BjHhV-BkwE)
79 |
80 |
81 |
82 | # 这里面的用的controller其实和UR之前下载的controller没有什么本质的区别,仅仅是控制模式不一样而已,一个是velocity,而另一个是joint_trajectory,以后需要用到cartesian space的速度可以考虑用这个包!
83 |
84 |
85 | # 仿真程序
86 | roslaunch ur5_admittance_control admittance_controller.launch
87 |
88 | # 真实程序
89 | roslaunch ur5_admittance_control admittance_controller.launch sim:=false F/T_sensor:=true
90 |
91 | # 安装错误
92 | 因为这个包很多ur的东西,所以很容易产生错误,如果错误无法解决,controller之类的错误,就把catkin_ws环境下的其他包移除,只留force_control的几个包然后,catkin_make就可以了
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/ati_sensor/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.2)
2 | project(ati_sensor)
3 |
4 | find_package(catkin REQUIRED COMPONENTS
5 | roscpp
6 | std_srvs
7 | std_msgs
8 | geometry_msgs
9 | rospy
10 | )
11 |
12 | catkin_package(
13 | CATKIN_DEPENDS geometry_msgs std_msgs
14 | INCLUDE_DIRS include
15 | LIBRARIES ati_sensor
16 | )
17 |
18 | include_directories(include
19 | ${catkin_INCLUDE_DIRS}
20 | )
21 |
22 | add_library(ati_sensor src/ft_sensor.cpp)
23 |
24 | find_package(LibXml2 REQUIRED)
25 | include_directories(${LIBXML2_INCLUDE_DIR})
26 | target_link_libraries(ati_sensor ${LIBXML2_LIBRARIES} ${XENOMAI_RTDM_LIBRARIES})
27 |
28 | add_executable(ft_sensor_node src/ft_sensor_node.cpp)
29 | target_link_libraries(ft_sensor_node ati_sensor ${catkin_LIBRARIES})
30 |
31 |
--------------------------------------------------------------------------------
/ati_sensor/include/ft_sensor.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | #define MAX_XML_SIZE 35535
18 | #define RDT_RECORD_SIZE 36
19 |
20 | namespace ati{
21 | static const std::string default_ip = "192.168.1.1";
22 | static const int current_calibration=-1;
23 | // 数据相应结构体
24 | typedef struct response_struct {
25 | uint32_t rdt_sequence;
26 | uint32_t ft_sequence;
27 | uint32_t status;
28 | int32_t Fx;
29 | int32_t Fy;
30 | int32_t Fz;
31 | int32_t Tx;
32 | int32_t Ty;
33 | int32_t Tz;
34 | uint32_t cpt;
35 | uint32_t cpf;
36 | } response_s;
37 |
38 | // 发送指令
39 | typedef struct command_struct{
40 | static const uint16_t command_header = 0x1234;
41 | uint16_t command;
42 | uint32_t sample_count;
43 | static const uint16_t STOP = 0x0000;
44 | static const uint16_t REALTIME = 0x0002;
45 | static const uint16_t BUFFERED = 0x0003;
46 | static const uint16_t MULTIUNIT = 0x0004;
47 | static const uint16_t RESET_THRESHOLD_LATCH = 0x0041;
48 | static const uint16_t SET_SOFWARE_BIAS = 0x0042;
49 | static const int DEFAULT_PORT = 49152;
50 | } command_s;
51 |
52 | class FTSensor{
53 | public:
54 | FTSensor();
55 | ~FTSensor();
56 |
57 | enum settings_error_t
58 | {
59 | NO_SETTINGS_ERROR,
60 | SETTINGS_REQUEST_ERROR,
61 | CALIB_PARSE_ERROR,
62 | GAUGE_PARSE_ERROR,
63 | RDTRATE_PARSE_ERROR
64 | };
65 |
66 | // 初始化,从XML中读取配置参数
67 | bool init(std::string ip, int calibration_index = ati::current_calibration,
68 | uint16_t cmd = ati::command_s::REALTIME, int sample_count = -1);
69 |
70 | // 读取力和力矩counts数据值
71 | const double getCountsperForce(){return resp_.cpf;};
72 | const double getCountsperTorque(){return resp_.cpt;};
73 |
74 | // 读取真实数据值
75 | template
76 | void getMeasurements(T measurements[6])
77 | {
78 | doComm();
79 |
80 | measurements[0]=static_cast( resp_.Fx ) / static_cast(resp_.cpf);
81 | measurements[1]=static_cast( resp_.Fy ) / static_cast(resp_.cpf);
82 | measurements[2]=static_cast( resp_.Fz ) / static_cast(resp_.cpf);
83 |
84 | measurements[3]=static_cast( resp_.Tx ) / static_cast(resp_.cpt);
85 | measurements[4]=static_cast( resp_.Ty ) / static_cast(resp_.cpt);
86 | measurements[5]=static_cast( resp_.Tz ) / static_cast(resp_.cpt);
87 | }
88 |
89 |
90 | template
91 | void getMeasurements(T measurements[6],uint32_t& rdt_sequence)
92 | {
93 | getMeasurements(measurements);
94 | rdt_sequence = resp_.rdt_sequence;
95 | }
96 |
97 | template
98 | void getMeasurements(T measurements[6],uint32_t& rdt_sequence,uint32_t& ft_sequence)
99 | {
100 | getMeasurements(measurements,rdt_sequence);
101 | ft_sequence = resp_.ft_sequence;
102 | }
103 |
104 | // 写入IP地址
105 | const std::string getIP(){return this->ip;}
106 | const uint16_t getPort(){return this->port;}
107 | std::string message_header(){
108 | std::stringstream ss;
109 | ss << "[ft_sensor " << this->ip << ":" << this->port << "] ";
110 | return ss.str();
111 | }
112 |
113 | // 数据传输频率
114 | const int getRDTRate(){return this->rdt_rate_;}
115 |
116 | // 归零
117 | void setBias();
118 | void setTimeout(float sec);
119 | bool isInitialized();
120 | bool getCalibrationData();
121 | settings_error_t getSettings();
122 | bool setRDTOutputRate(unsigned int rate);
123 | std::vector getGaugeBias();
124 | bool setGaugeBias(unsigned int gauge_idx, int gauge_bias);
125 | bool setGaugeBias(std::map &gauge_map);
126 | bool setGaugeBias(std::vector &gauge_vect);
127 |
128 |
129 | protected:
130 | // 套接字信息
131 | bool startRealTimeStreaming(uint32_t sample_count=1);
132 | bool startBufferedStreaming(uint32_t sample_count=100);
133 | bool startMultiUnitStreaming(uint32_t sample_count=100);
134 | bool resetThresholdLatch();
135 | bool setSoftwareBias();
136 | bool stopStreaming();
137 | bool startStreaming();
138 | bool startStreaming(int nb_samples);
139 | bool openSockets();
140 | void openSocket(int& handle, const std::string ip, const uint16_t port, const int option);
141 | bool closeSockets();
142 | int closeSocket(const int& handle);
143 | void setCommand(uint16_t cmd);
144 | void setSampleCount(uint32_t sample_count);
145 | bool sendCommand();
146 | bool sendCommand(uint16_t cmd);
147 | bool getResponse();
148 | bool sendTCPrequest(std::string &request_cmd);
149 | void doComm();
150 | std::string ip;
151 | uint16_t port;
152 | int calibration_index;
153 | int rdt_rate_;
154 | int *setbias_;
155 | int socketHandle_;
156 | int socketHTTPHandle_;
157 | struct sockaddr_in addr_;
158 | socklen_t addr_len_;
159 | struct hostent *hePtr_;
160 |
161 | // 通信协议
162 | response_s resp_;
163 | command_s cmd_;
164 | unsigned char request_[8];
165 | unsigned char response_[RDT_RECORD_SIZE];
166 | bool initialized_;
167 | bool timeout_set_;
168 | struct timeval timeval_;
169 | int response_ret_;
170 | char xml_c_[MAX_XML_SIZE];
171 | std::string xml_s_;
172 |
173 | };
174 | }
175 |
--------------------------------------------------------------------------------
/ati_sensor/launch/ft_sensor.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/ati_sensor/package.xml:
--------------------------------------------------------------------------------
1 |
2 | ati_sensor
3 | 1.1.0
4 | The package for FT sensors using the ATI net box.
5 |
6 | Antoine Hoarau
7 |
8 | CeCILL-C
9 |
10 | catkin
11 | roscpp
12 | rospy
13 | std_srvs
14 | std_msgs
15 | geometry_msgs
16 | tf
17 | libxml2
18 |
19 | roscpp
20 | libxml2
21 | std_srvs
22 | geometry_msgs
23 | std_msgs
24 | tf
25 | rospy
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/ati_sensor/src/ft_sensor.cpp:
--------------------------------------------------------------------------------
1 | #include "ft_sensor.h"
2 | #include
3 | #include
4 |
5 | // XML 相关的库
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #define rt_dev_socket socket
15 | #define rt_dev_setsockopt setsockopt
16 | #define rt_dev_bind bind
17 | #define rt_dev_recvfrom recvfrom
18 | #define rt_dev_sendto sendto
19 | #define rt_dev_close close
20 | #define rt_dev_connect connect
21 | #define rt_dev_recv recv
22 | #define rt_dev_send send
23 | #define RT_SO_TIMEOUT SO_RCVTIMEO
24 |
25 | static std::string getStringInXml(const std::string& xml_s,const std::string& tag)
26 | {
27 | const std::string tag_open = "<"+tag+">";
28 | const std::string tag_close = ""+tag+">";
29 | const std::size_t n_start = xml_s.find(tag_open);
30 | const std::size_t n_end = xml_s.find(tag_close);
31 | return xml_s.substr(n_start+tag_open.length(),n_end);
32 | }
33 | template
34 | static T getNumberInXml(const std::string& xml_s,const std::string& tag)
35 | {
36 | const std::string num = getStringInXml(xml_s,tag);
37 | double r = ::atof(num.c_str());
38 | return static_cast(r);
39 | }
40 | template
41 | static bool getArrayFromString(const std::string& str,const char delim,T *data,size_t len)
42 | {
43 | size_t start = str.find_first_not_of(delim), end=start;
44 | size_t idx = 0;
45 | while (start != std::string::npos && idx < len){
46 | end = str.find(delim, start);
47 | std::string token = str.substr(start, end-start);
48 | if (token.empty())
49 | token = "0.0";
50 | double r = ::atof(token.c_str());
51 | data[idx] = static_cast(r);
52 | ++idx;
53 | start = str.find_first_not_of(delim, end);
54 | }
55 | return (idx == len);
56 | }
57 | template
58 | static bool getArrayFromXml(const std::string& xml_s,const std::string& tag,const char delim,T *data,size_t len)
59 | {
60 | const std::string str = getStringInXml(xml_s,tag);
61 | return getArrayFromString(str,delim,data,len);
62 | }
63 |
64 |
65 | using namespace ati;
66 |
67 | FTSensor::FTSensor()
68 | {
69 | // 初始化参数
70 | initialized_ = false;
71 | ip = ati::default_ip;
72 | port = command_s::DEFAULT_PORT;
73 | cmd_.command = command_s::STOP;
74 | cmd_.sample_count = 1;
75 | calibration_index = ati::current_calibration;
76 | socketHandle_ = -1;
77 | resp_.cpf = 1000000;
78 | resp_.cpt = 1000000;
79 | rdt_rate_ = 0;
80 | timeval_.tv_sec = 2;
81 | timeval_.tv_usec = 0;
82 | xml_s_.reserve(MAX_XML_SIZE);
83 | setbias_ = new int[6];
84 | }
85 |
86 | FTSensor::~FTSensor()
87 | {
88 | stopStreaming();
89 | if(!closeSockets())
90 | std::cerr << message_header() << "Sensor did not shutdown correctly" << std::endl;
91 | delete setbias_;
92 | }
93 |
94 | bool FTSensor::startStreaming(int nb_samples)
95 | {
96 | if (nb_samples < 0) {
97 | // use default sample_count
98 | return startStreaming();
99 | }
100 | else {
101 | // use given sample count
102 | uint32_t sample_count = static_cast(nb_samples);
103 | switch(cmd_.command){
104 | case command_s::REALTIME:
105 | //std::cout << "Starting realtime streaming" << std::endl;
106 | return startRealTimeStreaming(sample_count);
107 | case command_s::BUFFERED:
108 | //std::cout << "Starting buffered streaming" << std::endl;
109 | return startBufferedStreaming(sample_count);
110 | case command_s::MULTIUNIT:
111 | //std::cout << "Starting multi-unit streaming" << std::endl;
112 | return startMultiUnitStreaming(sample_count);
113 | default:
114 | std::cout << message_header() << cmd_.command << ": command mode not allowed" << std::endl;
115 | return false;
116 | }
117 | }
118 | }
119 |
120 | // Initialization read from XML file
121 | bool FTSensor::startStreaming()
122 | {
123 | switch(cmd_.command){
124 | case command_s::REALTIME:
125 | //std::cout << "Starting realtime streaming" << std::endl;
126 | return startRealTimeStreaming();
127 | case command_s::BUFFERED:
128 | //std::cout << "Starting buffered streaming" << std::endl;
129 | return startBufferedStreaming();
130 | case command_s::MULTIUNIT:
131 | //std::cout << "Starting multi-unit streaming" << std::endl;
132 | return startMultiUnitStreaming();
133 | default:
134 | std::cout << message_header() << cmd_.command<< ": command mode not allowed" << std::endl;
135 | return false;
136 | }
137 | }
138 |
139 | bool FTSensor::init(std::string ip, int calibration_index, uint16_t cmd, int sample_count)
140 | {
141 | // Re-Initialize parameters
142 | initialized_ = true;
143 | this->ip = ip;
144 | this->port = command_s::DEFAULT_PORT;
145 | cmd_.command = command_s::STOP;
146 | cmd_.sample_count = 1;
147 | this->calibration_index = calibration_index;
148 |
149 | // Open Socket
150 | if(!ip.empty() && openSockets())
151 | {
152 | if(!stopStreaming()) // if previously launched
153 | std::cerr << "\033[33m" << message_header() << "Could not stop streaming\033[0m" << std::endl;
154 | setCommand(cmd); // Setting cmd mode
155 |
156 | initialized_ &= startStreaming(sample_count); // Starting streaming
157 |
158 | if (!initialized_)
159 | {
160 | std::cerr << "\033[1;31m" << message_header() << "Could not start streaming\033[0m" << std::endl;
161 | return initialized_;
162 | }
163 | initialized_ &= getResponse();
164 |
165 | // Parse Calibration from web server
166 | if(initialized_)
167 | getCalibrationData();
168 | }else
169 | initialized_ = false;
170 |
171 | if (!initialized_)
172 | std::cerr << "\033[1;31m" << message_header() << "Error during initialization, FT sensor NOT started\033[0m" << std::endl;
173 |
174 | return initialized_;
175 | }
176 | bool FTSensor::openSockets()
177 | {
178 | try{
179 | // To get the online configuration (need to build rtnet with TCP option)
180 | openSocket(socketHTTPHandle_,getIP(),80,IPPROTO_TCP);
181 | // The data socket
182 | openSocket(socketHandle_,getIP(),getPort(),IPPROTO_UDP);
183 | }
184 | catch (std::exception &ex) {
185 | std::cerr << "\033[1;31m" << message_header() << "openSockets error: " << ex.what() <<"\033[0m" << std::endl;
186 | return false;
187 | }
188 | return true;
189 | }
190 | void FTSensor::openSocket(int& handle,const std::string ip,const uint16_t port,const int option)
191 | {
192 | // create the socket
193 | if (handle != -1)
194 | rt_dev_close(handle);
195 | std::string proto = "";
196 | if(option == IPPROTO_UDP)
197 | {
198 | proto = "UDP";
199 | handle = rt_dev_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
200 | }
201 | else if(option == IPPROTO_TCP)
202 | {
203 | proto = "TCP";
204 | handle = rt_dev_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
205 | }
206 | else
207 | handle = rt_dev_socket(AF_INET, SOCK_DGRAM, 0);
208 |
209 | if (handle < 0) {
210 | std::cerr << "\033[31m" << message_header() << "Could not init sensor socket for proto [" << proto
211 | << "], please make sure your can ping the sensor\033[0m" << std::endl;
212 | throw std::runtime_error("failed to init sensor socket");
213 | }
214 |
215 | // re-use address in case it's still binded
216 | rt_dev_setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, 0, 0);
217 |
218 | // set the socket parameters
219 | struct sockaddr_in addr = {0};
220 | hostent * hePtr = NULL;
221 | hePtr = gethostbyname(ip.c_str());
222 | memcpy(&addr.sin_addr, hePtr->h_addr_list[0], hePtr->h_length);
223 |
224 | //addr_.sin_addr.s_addr = INADDR_ANY;
225 | addr.sin_family = AF_INET;
226 | addr.sin_port = htons(port);
227 |
228 | // connect
229 | if (rt_dev_connect(handle, (struct sockaddr*) &addr, sizeof(addr)) < 0)
230 | {
231 | std::cerr << "\033[31m" << message_header() << "Could not connect to " << ip << "\033[0m" << std::endl ;
232 | throw std::runtime_error("failed to connect to socket" );
233 | }
234 | return;
235 | }
236 | bool FTSensor::closeSockets()
237 | {
238 | return closeSocket(socketHandle_) == 0 && closeSocket(socketHTTPHandle_) == 0;
239 | }
240 | int FTSensor::closeSocket(const int& handle)
241 | {
242 | if(handle < 0)
243 | return 0; // closing a non-open socket is considered successful
244 | return rt_dev_close(handle);
245 | }
246 |
247 | bool FTSensor::getCalibrationData()
248 | {
249 | FTSensor::settings_error_t err = getSettings();
250 | if(err!=SETTINGS_REQUEST_ERROR && err!=CALIB_PARSE_ERROR)
251 | {
252 | std::cout << message_header() << "Sucessfully retrieved counts per force : " << resp_.cpf << std::endl;
253 | std::cout << message_header() << "Sucessfully retrieved counts per torque : " << resp_.cpt << std::endl;
254 | }
255 | else
256 | {
257 | std::cerr << message_header() << "Using default counts per force : " << resp_.cpf << std::endl;
258 | std::cerr << message_header() << "Using default counts per torque : " << resp_.cpt << std::endl;
259 | }
260 | }
261 |
262 | FTSensor::settings_error_t FTSensor::getSettings()
263 | {
264 | std::string index("");
265 | if(calibration_index != ati::current_calibration)
266 | {
267 | std::stringstream ss;
268 | ss << calibration_index;
269 | index = "?index=" + ss.str();
270 | std::cout << message_header() << "Using calibration index "<(xml_s_,"cfgcpf");
301 | const uint32_t cfgcpt_r = getNumberInXml(xml_s_,"cfgcpt");
302 | const int cfgcomrdtrate = getNumberInXml(xml_s_,"comrdtrate");
303 | rdt_rate_ = cfgcomrdtrate;
304 |
305 | // 6 tokens separated by semi-colon
306 | if (!getArrayFromXml(xml_s_,"setbias",';',setbias_, 6))
307 | {
308 | return GAUGE_PARSE_ERROR;
309 | }
310 |
311 | if(cfgcpf_r && cfgcpt_r)
312 | {
313 | resp_.cpf = cfgcpf_r;
314 | resp_.cpt = cfgcpt_r;
315 | return NO_SETTINGS_ERROR;
316 | }
317 | std::cerr << message_header() << "Could not parse file " << filename << std::endl;
318 | return SETTINGS_REQUEST_ERROR;
319 | }
320 |
321 | bool FTSensor::sendTCPrequest(std::string &request_cmd)
322 | {
323 | if (request_cmd.empty() )
324 | {
325 | std::cerr << message_header() << "Empty TCP command, not sending" << std::endl;
326 | return false;
327 | }
328 | else
329 | {
330 | static const uint32_t chunkSize = 4; // Every chunk of data will be of this size
331 | static const uint32_t maxSize = 65536; // The maximum file size to receive
332 | std::string host = getIP();
333 |
334 | std::string request_s = "GET "+request_cmd+" HTTP/1.0\r\nHost: "+host+"\r\n\r\n";
335 |
336 | if (rt_dev_send(socketHTTPHandle_, request_s.c_str(),request_s.length(), 0) < 0)
337 | {
338 | std::cerr << message_header() << "Could not send GET request to " << host
339 | << ":80. Please make sure that RTnet TCP protocol is installed" << std::endl;
340 | return false;
341 | }
342 |
343 | //empty the buffer but we don't care about the result
344 | int recvLength=0;
345 | int posBuff = 0;
346 | while(posBuff < maxSize) // Just a security to avoid infinity loop
347 | {
348 | recvLength = rt_dev_recv(socketHTTPHandle_, &xml_c_[posBuff],chunkSize, 0);
349 | posBuff += recvLength;
350 | if(recvLength <= 0) // The last chunk returns 0
351 | break;
352 | }
353 | if (posBuff > 4)
354 | {
355 | const char *awaited_response = "HTTP/1.0 302 Found";
356 | if (strncmp(xml_c_, awaited_response, 18 )==0)
357 | {
358 | return true;
359 | }
360 | else
361 | {
362 | std::cerr << message_header() << "Bad response from set command. Response is :" << xml_c_ << std::endl;
363 | return false;
364 | }
365 | }
366 | else
367 | {
368 | std::cerr << message_header() << "Bad response from set command. Response is :" << xml_c_ << std::endl;
369 | return false;
370 | }
371 | }
372 | }
373 |
374 |
375 | bool FTSensor::setRDTOutputRate(unsigned int rate)
376 | {
377 | if (rate > 0 && rate <= 7000)
378 | {
379 | std::stringstream cfgcomrdtrate_ss;
380 | cfgcomrdtrate_ss << rate;
381 | std::string cmd = "/comm.cgi?comrdtrate=" + cfgcomrdtrate_ss.str();
382 |
383 | if(sendTCPrequest(cmd))
384 | {
385 | // we consider the rate was set and don't read it back
386 | rdt_rate_ = rate;
387 | return true;
388 | }
389 | else
390 | return false;
391 | }
392 | else
393 | {
394 | std::cerr << message_header() << "RDT rate must be in range [1-7000]" << std::endl;
395 | return false;
396 | }
397 | }
398 |
399 |
400 | bool FTSensor::setGaugeBias(unsigned int gauge_idx, int gauge_bias)
401 | {
402 | std::map map;
403 | map[gauge_idx] = gauge_bias;
404 | return setGaugeBias(map);
405 | }
406 |
407 | std::vector FTSensor::getGaugeBias()
408 | {
409 | FTSensor::settings_error_t err = getSettings();
410 | if(err!=SETTINGS_REQUEST_ERROR && err!=GAUGE_PARSE_ERROR)
411 | {
412 | std::vector bias(setbias_, setbias_ + 6);
413 | return bias;
414 | }
415 | else
416 | {
417 | std::cerr << message_header() << "Could not get gauge bias values" << std::endl;
418 | return std::vector();
419 | }
420 | }
421 |
422 |
423 | bool FTSensor::setGaugeBias(std::vector &gauge_vect)
424 | {
425 | std::map map;
426 | for (size_t i=0; i < gauge_vect.size(); ++i)
427 | {
428 | map[i] = gauge_vect[i];
429 | }
430 | return setGaugeBias(map);
431 | }
432 |
433 | bool FTSensor::setGaugeBias(std::map &gauge_map)
434 | {
435 | std::stringstream setbias_ss;
436 | std::map::iterator it;
437 | bool first_element = true;
438 | //prepare the query
439 | for (it=gauge_map.begin(); it!=gauge_map.end(); ++it)
440 | {
441 | if( it->first < 6)
442 | {
443 | if(first_element)
444 | {
445 | setbias_ss << "?";
446 | first_element = false;
447 | }
448 | else
449 | {
450 | setbias_ss << "&";
451 | }
452 | setbias_ss << "setbias" << it->first << "=" << it->second;
453 | }
454 | else
455 | {
456 | std::cerr << message_header() << "Invalid gauge number "<< it->first << std::endl;
457 | return false;
458 | }
459 | }
460 |
461 | std::string host = getIP();
462 | std::string cmd = "/setting.cgi" + setbias_ss.str();
463 | return sendTCPrequest(cmd);
464 | }
465 |
466 | bool FTSensor::sendCommand()
467 | {
468 | return sendCommand(cmd_.command);
469 | }
470 |
471 | bool FTSensor::sendCommand(uint16_t cmd)
472 | {
473 | *reinterpret_cast(&request_[0]) = htons(command_s::command_header);
474 | *reinterpret_cast(&request_[2]) = htons(cmd);
475 | *reinterpret_cast(&request_[4]) = htonl(cmd_.sample_count);
476 | //return rt_dev_sendto(socketHandle_, (void*) &request_, sizeof(request_), 0, (sockaddr*) &addr_, addr_len_ ) == 8;
477 | return rt_dev_send(socketHandle_, (void*) &request_, sizeof(request_), 0) == sizeof(request_);//, (sockaddr*) &addr_, addr_len_ ) == 8;
478 | }
479 |
480 | bool FTSensor::getResponse()
481 | {
482 |
483 | //response_ret_ = rt_dev_recvfrom(socketHandle_, (void*) &response_, sizeof(response_), 0, (sockaddr*) &addr_, &addr_len_ );
484 | response_ret_ = rt_dev_recv(socketHandle_, (void*) &response_, sizeof(response_), 0);//, (sockaddr*) &addr_, &addr_len_ );
485 | resp_.rdt_sequence = ntohl(*reinterpret_cast(&response_[0]));
486 | resp_.ft_sequence = ntohl(*reinterpret_cast(&response_[4]));
487 | resp_.status = ntohl(*reinterpret_cast(&response_[8]));
488 | resp_.Fx = static_cast(ntohl(*reinterpret_cast(&response_[12 + 0 * 4])));
489 | resp_.Fy = static_cast(ntohl(*reinterpret_cast(&response_[12 + 1 * 4])));
490 | resp_.Fz = static_cast(ntohl(*reinterpret_cast(&response_[12 + 2 * 4])));
491 | resp_.Tx = static_cast(ntohl(*reinterpret_cast(&response_[12 + 3 * 4])));
492 | resp_.Ty = static_cast(ntohl(*reinterpret_cast(&response_[12 + 4 * 4])));
493 | resp_.Tz = static_cast(ntohl(*reinterpret_cast(&response_[12 + 5 * 4])));
494 | if (response_ret_ < 0)
495 | {
496 | std::cerr << "\033[1;31m" << message_header() << "Error while receiving: " << strerror(errno) << "\033[0m" << std::endl;
497 | }
498 | if (response_ret_!=RDT_RECORD_SIZE)
499 | std::cerr << message_header() << "Error of package.xml size " <setSoftwareBias();
519 | }
520 | bool FTSensor::isInitialized()
521 | {
522 | return initialized_;
523 | }
524 |
525 | void FTSensor::setTimeout(float sec)
526 | {
527 | if (sec <= 0) {
528 | std::cerr << message_header() << "Can't set timeout <= 0 sec" << std::endl;
529 | return;
530 | }
531 |
532 | if (isInitialized()) {
533 | std::cerr << message_header() << "Can't set timeout if socket is initialized, call this before init()." << std::endl;
534 | return;
535 | }
536 | timeval_.tv_sec = static_cast(sec);
537 | timeval_.tv_usec = static_cast(sec/1.e6);
538 | }
539 |
540 | bool FTSensor::resetThresholdLatch()
541 | {
542 | if(! sendCommand(command_s::RESET_THRESHOLD_LATCH)){
543 | std::cerr << message_header() << "Could not start reset threshold latch" << std::endl;
544 | return false;
545 | }
546 | return true;
547 | }
548 | bool FTSensor::setSoftwareBias()
549 | {
550 | //if(!stopStreaming())
551 | //std::cerr << "Could not stop streaming" << std::endl;
552 | if(! sendCommand(command_s::SET_SOFWARE_BIAS)){
553 | ;//std::cerr << "Could not set software bias" << std::endl;
554 | return false;
555 | }
556 | //if(!startStreaming())
557 | //std::cerr << "Could not restart streaming" << std::endl;
558 | return true;
559 | }
560 | bool FTSensor::stopStreaming()
561 | {
562 | return sendCommand(command_s::STOP);
563 | }
564 |
565 | bool FTSensor::startBufferedStreaming(uint32_t sample_count)
566 | {
567 | setSampleCount(sample_count);
568 | setCommand(command_s::BUFFERED);
569 | if(! sendCommand()){
570 | std::cerr << message_header() << "Could not start buffered streaming" << std::endl;
571 | return false;
572 | }
573 | return true;
574 | }
575 | bool FTSensor::startMultiUnitStreaming(uint32_t sample_count)
576 | {
577 | setSampleCount(sample_count);
578 | setCommand(command_s::MULTIUNIT);
579 | if(! sendCommand()){
580 | std::cerr << message_header() << "Could not start multi-unit streaming" << std::endl;
581 | return false;
582 | }
583 | return true;
584 | }
585 | bool FTSensor::startRealTimeStreaming(uint32_t sample_count)
586 | {
587 | setSampleCount(sample_count);
588 | setCommand(command_s::REALTIME);
589 | if(! sendCommand()){
590 | std::cerr << message_header() << "Could not start realtime streaming" << std::endl;
591 | return false;
592 | }
593 | std::cout << message_header() << "Start realtime streaming with " << sample_count <<" samples " << std::endl;
594 | return true;
595 | }
596 |
597 | void FTSensor::setCommand(uint16_t cmd)
598 | {
599 | this->cmd_.command = cmd;
600 | }
601 |
602 | void FTSensor::setSampleCount(uint32_t sample_count)
603 | {
604 | this->cmd_.sample_count = sample_count;
605 | }
606 |
607 |
--------------------------------------------------------------------------------
/ati_sensor/src/ft_sensor_node.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include "ft_sensor.h"
13 |
14 | int count = 0;
15 | FILE *f;
16 |
17 |
18 | namespace ftsensor {
19 |
20 | class FTSensorPublisher
21 | {
22 | private:
23 | //! The node handle
24 | ros::NodeHandle nh_;
25 | //! Node handle in the private namespace
26 | ros::NodeHandle priv_nh_;
27 |
28 | //! The sensor
29 | boost::shared_ptr ftsensor_;
30 | std::string ip_;
31 | std::string frame_ft_;
32 |
33 | //! Publisher for sensor readings
34 | ros::Publisher pub_sensor_readings_;
35 |
36 | //! Service for setting the bias
37 | ros::ServiceServer srv_set_bias_;
38 |
39 | public:
40 | //------------------ Callbacks -------------------
41 | // Callback for setting bias
42 | bool setBiasCallback(std_srvs::Empty::Request &request, std_srvs::Empty::Response &response);
43 |
44 | // Publish the measurements
45 | void publishMeasurements();
46 |
47 | //! Subscribes to and advertises topics
48 | FTSensorPublisher(ros::NodeHandle nh) : nh_(nh), priv_nh_("~")
49 | {
50 | priv_nh_.param("frame", frame_ft_, "/ati_ft_link");
51 | priv_nh_.param("ip", ip_, "192.168.1.1");
52 |
53 | ROS_INFO_STREAM("ATISensor IP : "<< ip_);
54 | ROS_INFO_STREAM("ATISensor frame : "<< frame_ft_);
55 |
56 | // Create a new sensor
57 | ftsensor_ = boost::shared_ptr(new ati::FTSensor());
58 |
59 | // Init FT Sensor
60 | if (ftsensor_->init(ip_))
61 | {
62 | // Set bias
63 | ftsensor_->setBias();
64 |
65 | ROS_INFO_STREAM("ATISensor RDT Rate : "<< ftsensor_->getRDTRate());
66 |
67 | // Advertise topic where readings are published
68 | pub_sensor_readings_ = priv_nh_.advertise("data", 10);
69 |
70 | // Advertise service for setting the bias
71 | srv_set_bias_ = priv_nh_.advertiseService("set_bias", &FTSensorPublisher::setBiasCallback, this);
72 | }
73 | else
74 | {
75 | throw std::runtime_error("FT sensor could not initialize");
76 | }
77 | }
78 |
79 | //! Empty stub
80 | ~FTSensorPublisher() {}
81 |
82 | };
83 |
84 | /* 每次启动自动设置bias vetor,用来消除运动时候的偏差 */
85 | bool FTSensorPublisher::setBiasCallback(std_srvs::Empty::Request &request, std_srvs::Empty::Response &response)
86 | {
87 | ftsensor_->setBias();
88 | }
89 |
90 | void FTSensorPublisher::publishMeasurements()
91 | {
92 | // Recall that this has to be transformed using the stewart platform
93 | //tf_broadcaster_.sendTransform(tf::StampedTransform(nano_top_frame_, ros::Time::now(), "/world", "/nano_top_frame"));
94 | geometry_msgs::WrenchStamped ftreadings;
95 | float measurements[6];
96 | ftsensor_->getMeasurements(measurements);
97 |
98 | ftreadings.wrench.force.x = measurements[0];
99 | ftreadings.wrench.force.y = measurements[1];
100 | ftreadings.wrench.force.z = measurements[2];
101 | ftreadings.wrench.torque.x = measurements[3];
102 | ftreadings.wrench.torque.y = measurements[4];
103 | ftreadings.wrench.torque.z = measurements[5];
104 |
105 | ftreadings.header.stamp = ros::Time::now();
106 | ftreadings.header.frame_id = frame_ft_;
107 |
108 | pub_sensor_readings_.publish(ftreadings);
109 |
110 | // ROS_INFO("Measured Force: %f %f %f Measured Torque: %f %f %f", measurements[0], measurements[1], measurements[2], measurements[3], measurements[4], measurements[5]);
111 | }
112 |
113 | } // namespace ftsensor
114 |
115 | int main(int argc, char **argv)
116 | {
117 | ros::init(argc, argv, "ft_sensor");
118 | ros::NodeHandle nh;
119 | ros::Rate loop(100);
120 | try
121 | {
122 | ftsensor::FTSensorPublisher node(nh);
123 | while(ros::ok())
124 | {
125 | node.publishMeasurements();
126 | ros::spinOnce();
127 |
128 | loop.sleep();
129 | }
130 | }
131 | catch (std::exception &ex) {
132 | ROS_FATAL_STREAM("Failed with error : " << ex.what());
133 | return -1;
134 | }
135 | return 0;
136 | }
137 |
--------------------------------------------------------------------------------
/ur5_admittance_control/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(ur5_admittance_control)
3 |
4 | ## Add support for C++11, supported in ROS Kinetic and newer
5 | # add_definitions(-std=c++11)
6 |
7 | ## Find catkin macros and libraries
8 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
9 | ## is used, also find other catkin packages
10 | find_package(catkin REQUIRED COMPONENTS
11 | roscpp
12 | sensor_msgs
13 | tf
14 | tf_conversions
15 | rospy
16 | std_msgs
17 | geometry_msgs
18 | message_generation
19 | )
20 |
21 | set(CMAKE_CXX_FLAGS "-O2 -O3 -std=c++11 -Wall")
22 |
23 | add_message_files(
24 | FILES
25 | PoseTwist.msg
26 | )
27 |
28 | generate_messages(
29 | DEPENDENCIES
30 | geometry_msgs
31 | )
32 |
33 |
34 | catkin_package(
35 | INCLUDE_DIRS include
36 | # LIBRARIES cpr_closed_loop_controller
37 | CATKIN_DEPENDS geometry_msgs message_runtime
38 | # DEPENDS system_lib
39 | )
40 |
41 | ###########
42 | ## Build ##
43 | ###########
44 |
45 | ## Specify additional locations of header files
46 | ## Your package locations should be listed before other locations
47 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include ${catkin_INCLUDE_DIRS})
48 | include_directories(${EIGEN3_INCLUDE_DIR})
49 |
50 | set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
51 | set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
52 |
53 |
54 | add_executable(admittance_controller_node
55 | ${SRC_DIR}/admittance_controller_node.cpp
56 | ${SRC_DIR}/AdmittanceController.cpp
57 | ${INCLUDE_DIR}/AdmittanceController.h)
58 |
59 | ## Add cmake target dependencies of the executable
60 | ## same as for the library above
61 | add_dependencies(admittance_controller_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
62 |
63 | #add_dependencies(cpr_record_demo_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS} ${PROJECT_NAME}_gencfg)
64 | #
65 | #add_dependencies(cpr_ee_state_splitter_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS} ${PROJECT_NAME}_gencfg)
66 |
67 |
68 | ## Specify libraries to link a library or executable target against
69 | target_link_libraries(admittance_controller_node
70 | ${catkin_LIBRARIES}
71 | )
72 |
73 |
--------------------------------------------------------------------------------
/ur5_admittance_control/config/admittance_params.yaml:
--------------------------------------------------------------------------------
1 | # Admittance parameters for two mass damper systems
2 | # (the arm and the platform) with params (mass_arm, damping_arm)
3 | # and (mass_platform, damping_platform) respectively, connected by a
4 | # spring-damper (弹簧减震器)with parameters (damping_coupling耦合阻尼, stiffness_coupling耦合刚度,
5 | # equilibrium_point_spring)
6 | mass_arm: [2,0,0,0,0,0,
7 | 0,2,0,0,0,0,
8 | 0,0,2,0,0,0,
9 | 0,0,0,2,0,0,
10 | 0,0,0,0,2,0,
11 | 0,0,0,0,0,2]
12 | damping_arm: [12,0,0,0,0,0,
13 | 0,12,0,0,0,0,
14 | 0,0,12,0,0,0,
15 | 0,0,0,10,0,0,
16 | 0,0,0,0,10,0,
17 | 0,0,0,0,0,10]
18 | stiffness_arm: [10,0,0,0,0,0,
19 | 0,20,0,0,0,0,
20 | 0,0,10,0,0,0,
21 | 0,0,0,10,0,0,
22 | 0,0,0,0,10,0,
23 | 0,0,0,0,0,10]
24 | # [position (x, y, z) orientation (x, y, z, w)]
25 | # 就是设该点为力平衡点,此时在外界没有作用力的时候机械臂是平衡的,不给自动耷拉下来(耷拉说明平衡点为0)
26 | # 通过指定平衡点应该就可以实现东南的第二个视频
27 | # 因为平衡点的是(0.1,0.4),要平衡力, 所以fake foce 的力肯定是相反方向的,也就是(0.4,-0.1)
28 | # 上条驳回,其实就是(0.1,0.4,0.5),前面是关节rpy转角的问题,见ur5.urdf.xacro
29 | # equilibrium_point_spring: [0.1,0.4,0.5,-0.593599, -0.566706, -0.369419, 0.435908]
30 | equilibrium_point_spring: [-0.341,-0.103,0.657,-0.49, -0.1520, 0.8077, -0.2835]
31 |
32 |
33 | workspace_limits: [-0.50, 0.50, -0.5, 0.5, 0.30, 0.75]
34 |
35 | arm_max_vel: 1.5
36 | arm_max_acc: 1.0
--------------------------------------------------------------------------------
/ur5_admittance_control/include/AdmittanceController.h:
--------------------------------------------------------------------------------
1 | #ifndef ADMITTANCECONTROLLER_H
2 | #define ADMITTANCECONTROLLER_H
3 |
4 | #include "ros/ros.h"
5 | #include "ur5_admittance_control/PoseTwist.h"
6 | #include "geometry_msgs/WrenchStamped.h"
7 | #include "geometry_msgs/TwistStamped.h"
8 | #include
9 | #include
10 | #include
11 |
12 | #include "eigen3/Eigen/Core"
13 | #include "eigen3/Eigen/Geometry"
14 | #include "eigen3/Eigen/Dense"
15 |
16 | #include "std_msgs/Float32.h"
17 |
18 | using namespace Eigen;
19 |
20 | typedef Matrix Vector7d;
21 | typedef Matrix Vector6d;
22 | typedef Matrix Matrix6d;
23 |
24 | class AdmittanceController
25 | {
26 | protected:
27 | ////// ROS VARIABLES:
28 | // A handle to the node in ros
29 | ros::NodeHandle nh_;
30 | // Rate of the run loop
31 | ros::Rate loop_rate_;
32 |
33 |
34 | ///// Subscribers:
35 | // Subscriber for the arm state
36 | ros::Subscriber sub_arm_state_;
37 | // Subscriber for the ft sensor at the endeffector
38 | ros::Subscriber sub_wrench_external_;
39 |
40 | ////// Publishers:
41 | // Publisher for the twist of arm endeffector
42 | ros::Publisher pub_arm_cmd_;
43 |
44 | ////// INPUT SIGNAL
45 | // external wrench (force/torque sensor) in "robotiq_force_torque_frame_id" frame
46 | Vector6d wrench_external_;
47 |
48 |
49 | ////// FORCE/TORQUE-SENSOR FILTER:
50 | // Parameters for the noisy wrench
51 | double wrench_filter_factor_;
52 | double force_dead_zone_thres_;
53 | double torque_dead_zone_thres_;
54 | double admittance_ratio_;
55 |
56 |
57 | /////// ADMITTANCE PARAMETERS:
58 | // M_a_ -> Desired mass of arm
59 | // D_a_ -> Desired damping of arm
60 | // K_ -> Desired Stiffness of the coupling
61 | Matrix6d M_a_, D_a_, K_a_;
62 | // equilibrium position of the coupling spring
63 | Vector3d equilibrium_position_;
64 | // equilibrium orientation of the coupling spring
65 | Quaterniond equilibrium_orientation_;
66 |
67 | // OUTPUT COMMANDS
68 | // final arm desired velocity
69 | Vector6d arm_desired_twist_final_;
70 |
71 | // limiting the workspace of the arm
72 | Vector6d workspace_limits_;
73 | double arm_max_vel_;
74 | double arm_max_acc_;
75 |
76 |
77 | ////// STATE VARIABLES:
78 | // Arm state: position, orientation, and twist (in "ur5_arm_base_link")
79 | Vector3d arm_real_position_;
80 | Quaterniond arm_real_orientation_;
81 | Vector6d arm_real_twist_;
82 |
83 |
84 | // Transform from base_link to world
85 | Matrix6d rotation_base_;
86 |
87 | // TF:
88 | // Listeners
89 | tf::TransformListener listener_ft_;
90 | tf::TransformListener listener_control_;
91 | tf::TransformListener listener_arm_;
92 |
93 | // 判断是否所有坐标系矩阵建立
94 | bool transformation;
95 |
96 | // Initialization
97 | void wait_for_transformations();
98 |
99 | // Control
100 | void compute_admittance();
101 |
102 |
103 |
104 | // Callbacks
105 | void state_arm_callback(const ur5_admittance_control::PoseTwistConstPtr msg);
106 | void wrench_callback(const geometry_msgs::WrenchStampedConstPtr msg);
107 |
108 | // Util
109 | bool get_rotation_matrix(Matrix6d & rotation_matrix,tf::TransformListener & listener,std::string from_frame, std::string to_frame);
110 |
111 | void limit_to_workspace();
112 |
113 | void send_commands_to_robot();
114 |
115 |
116 | public:
117 | AdmittanceController(ros::NodeHandle &n, double frequency,
118 | std::string cmd_topic_arm,
119 | std::string state_topic_arm,
120 | std::string wrench_topic,
121 | std::vector M_a,
122 | std::vector D_a,
123 | std::vector K_a,
124 | std::vector d_e,
125 | std::vector workspace_limits,
126 | double arm_max_vel,
127 | double arm_max_acc,
128 | double wrench_filter_factor,
129 | double force_dead_zone_thres,
130 | double torque_dead_zone_thres);
131 | void run();
132 | };
133 |
134 | #endif // ADMITTANCECONTROLLER_H
135 |
136 |
--------------------------------------------------------------------------------
/ur5_admittance_control/launch/admittance_controller.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/ur5_admittance_control/msg/PoseTwist.msg:
--------------------------------------------------------------------------------
1 | # The pose in this message should be specified in the coordinate frame given by header.frame_id.
2 | # The twist in this message should be specified in the coordinate frame given by the child_frame_id
3 | Header header
4 | string child_frame_id
5 | geometry_msgs/Pose pose
6 | geometry_msgs/Twist twist
7 |
--------------------------------------------------------------------------------
/ur5_admittance_control/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | ur5_admittance_control
4 | 0.0.0
5 | The admittance_control package
6 |
7 |
8 |
9 |
10 | Jose Medina
11 |
12 |
13 |
14 |
15 |
16 | MIT
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | sensor_msgs
31 | tf
32 | cmake_modules
33 | eigen
34 | message_generation
35 | geometry_msgs
36 | message_runtime
37 | geometry_msgs
38 | sensor_msgs
39 | tf
40 | eigen
41 | catkin
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/ur5_admittance_control/src/AdmittanceController.cpp:
--------------------------------------------------------------------------------
1 | #include "AdmittanceController.h"
2 |
3 | AdmittanceController::AdmittanceController(ros::NodeHandle &n,
4 | double frequency,
5 | std::string topic_arm_command,
6 | std::string topic_arm_state,
7 | std::string topic_external_wrench,
8 | std::vector M_a,
9 | std::vector D_a,
10 | std::vector K_a,
11 | std::vector d_e,
12 | std::vector workspace_limits,
13 | double arm_max_vel,
14 | double arm_max_acc,
15 | double wrench_filter_factor,
16 | double force_dead_zone_thres,
17 | double torque_dead_zone_thres) :
18 | nh_(n), loop_rate_(frequency),
19 | wrench_filter_factor_(wrench_filter_factor),
20 | force_dead_zone_thres_(force_dead_zone_thres),
21 | torque_dead_zone_thres_(torque_dead_zone_thres),
22 | M_a_(M_a.data()),D_a_(D_a.data()), K_a_(K_a.data()),
23 | workspace_limits_(workspace_limits.data()),
24 | arm_max_vel_(arm_max_vel),
25 | arm_max_acc_(arm_max_acc)
26 | {
27 | ///// Subscribers
28 | sub_arm_state_ = nh_.subscribe(topic_arm_state, 10,
29 | &AdmittanceController::state_arm_callback, this,
30 | ros::TransportHints().reliable().tcpNoDelay());
31 |
32 | sub_wrench_external_ = nh_.subscribe(topic_external_wrench, 5,
33 | &AdmittanceController::wrench_callback, this,
34 | ros::TransportHints().reliable().tcpNoDelay());
35 |
36 | ////// Publishers
37 | pub_arm_cmd_ = nh_.advertise(topic_arm_command, 5);
38 |
39 | /// initializing the class variables
40 | wrench_external_.setZero();
41 |
42 | // setting the equilibrium position and orientation and Make sure the orientation goal is normalized
43 | Vector7d equilibrium_full(d_e.data());
44 | equilibrium_position_ << equilibrium_full.topRows(3);
45 | equilibrium_orientation_.coeffs() << equilibrium_full.bottomRows(4) /equilibrium_full.bottomRows(4).norm();
46 | // starting from a state that does not create movements on the robot
47 | arm_real_orientation_ = equilibrium_orientation_;
48 | arm_real_position_ = equilibrium_position_ ;
49 |
50 | while (nh_.ok() && !arm_real_position_(0)) {
51 | ROS_WARN_THROTTLE(1, "Waiting for the state of the arm...");
52 | ros::spinOnce();
53 | loop_rate_.sleep();
54 | }
55 |
56 | // Init integrator
57 | arm_desired_twist_final_.setZero();
58 |
59 | transformation = false;
60 |
61 | // between zero and one that modulated the input force as to control the stiffness(刚度)
62 | admittance_ratio_ = 1;
63 |
64 | wait_for_transformations();
65 | }
66 |
67 | ///////////////////////////////////////////////////////////////
68 | ////////////////////////// Callbacks //////////////////////////
69 | ///////////////////////////////////////////////////////////////
70 | void AdmittanceController::state_arm_callback(const ur5_admittance_control::PoseTwistConstPtr msg) {
71 | arm_real_position_ << msg->pose.position.x, msg->pose.position.y,
72 | msg->pose.position.z;
73 |
74 | arm_real_orientation_.coeffs() << msg->pose.orientation.x,
75 | msg->pose.orientation.y,
76 | msg->pose.orientation.z,
77 | msg->pose.orientation.w;
78 |
79 | arm_real_twist_ << msg->twist.linear.x, msg->twist.linear.y,
80 | msg->twist.linear.z, msg->twist.angular.x, msg->twist.angular.y,
81 | msg->twist.angular.z;
82 | }
83 |
84 | void AdmittanceController::wrench_callback(const geometry_msgs::WrenchStampedConstPtr msg) {
85 | Vector6d wrench_ft_frame;
86 | Matrix6d rotation_ft_base;
87 | if (transformation) {
88 |
89 | // Reading the FT-sensor in its own frame (robotiq_force_torque_frame_id)
90 | wrench_ft_frame << msg->wrench.force.x, msg->wrench.force.y,
91 | msg->wrench.force.z, msg->wrench.torque.x,
92 | msg->wrench.torque.y, msg->wrench.torque.z;
93 |
94 | for (int i = 0; i < 3; i++) {
95 | if (abs(wrench_ft_frame(i)) < force_dead_zone_thres_) {
96 | wrench_ft_frame(i) = 0;
97 | }
98 | if (abs(wrench_ft_frame(i + 3)) < torque_dead_zone_thres_) {
99 | wrench_ft_frame(i + 3) = 0;
100 | }
101 | }
102 | // Get transform from arm base link to platform base link
103 | get_rotation_matrix(rotation_ft_base, listener_ft_,
104 | "base_link", "FT_link");
105 |
106 | // Filter and update
107 | wrench_external_ << (1 - wrench_filter_factor_) * wrench_external_ +
108 | wrench_filter_factor_ * rotation_ft_base * wrench_ft_frame;
109 | }
110 | }
111 |
112 | ///////////////////////////////////////////////////////////////
113 | ///////////////////// Control Loop ////////////////////////////
114 | ///////////////////////////////////////////////////////////////
115 | void AdmittanceController::run() {
116 |
117 | ROS_INFO("Running the admittance control loop .................");
118 |
119 | while (nh_.ok()) {
120 | // Admittance Dynamics computation
121 | compute_admittance();
122 |
123 | // sum the vel from admittance to DS in this function
124 | // limit the the movement of the arm to the permitted workspace
125 | limit_to_workspace();
126 |
127 | // Copy commands to messages
128 | send_commands_to_robot();
129 |
130 | // publishing visualization/debugging info
131 | // publish_debuggings_signals();
132 |
133 | ros::spinOnce();
134 | loop_rate_.sleep();
135 | }
136 |
137 |
138 | }
139 |
140 | ///////////////////////////////////////////////////////////////
141 | ///////////////////// Admittance Dynamics /////////////////////
142 | ///////////////////////////////////////////////////////////////
143 | void AdmittanceController::compute_admittance() {
144 |
145 | Vector6d arm_desired_accelaration;
146 |
147 | Vector6d error;
148 | // Orientation error w.r.t. desired equilibriums
149 | if (equilibrium_orientation_.coeffs().dot(arm_real_orientation_.coeffs()) < 0.0) {
150 | arm_real_orientation_.coeffs() << -arm_real_orientation_.coeffs();
151 | }
152 |
153 | Eigen::Quaterniond quat_rot_err(arm_real_orientation_* equilibrium_orientation_.inverse());
154 |
155 | if (quat_rot_err.coeffs().norm() > 1e-3) {
156 | // Normalize error quaternion
157 | quat_rot_err.coeffs() << quat_rot_err.coeffs() / quat_rot_err.coeffs().norm();
158 | }
159 |
160 | Eigen::AngleAxisd err_arm_des_orient(quat_rot_err);
161 | error.bottomRows(3) << err_arm_des_orient.axis() *err_arm_des_orient.angle();
162 | // Translation error w.r.t.(with respect to) desipared equilibrium
163 | error.topRows(3) = arm_real_position_ - equilibrium_position_;
164 |
165 | arm_desired_accelaration = M_a_.inverse() * ( - K_a_ * error - D_a_ * arm_desired_twist_final_ + admittance_ratio_ * wrench_external_);
166 |
167 | // limiting the accelaration for better stability and safety
168 | // x,y,z for the arm
169 | double a_acc_norm = (arm_desired_accelaration.segment(0, 3)).norm();
170 | if (a_acc_norm > arm_max_acc_) {
171 | ROS_WARN_STREAM_THROTTLE(1, "Admittance generates high arm accelaration!"<< " norm: " << a_acc_norm);
172 | arm_desired_accelaration.segment(0, 3) *= (arm_max_acc_ / a_acc_norm);
173 | }
174 |
175 | // Integrate for velocity based interface
176 | ros::Duration duration = loop_rate_.expectedCycleTime();
177 | arm_desired_twist_final_ += arm_desired_accelaration * duration.toSec();
178 | }
179 |
180 | ///////////////////////////////////////////////////////////////
181 | //////////////////// Limit to workspace////////////////////////
182 | ///////////////////////////////////////////////////////////////
183 | void AdmittanceController::limit_to_workspace() {
184 |
185 | if (arm_real_position_(0) < workspace_limits_(0) || arm_real_position_(0) > workspace_limits_(1)) {
186 | ROS_WARN_STREAM_THROTTLE (1, "Out of permitted workspace. x = "
187 | << arm_real_position_(0) << " not in [" << workspace_limits_(0) << " , "
188 | << workspace_limits_(1) << "]");
189 | }
190 |
191 | if (arm_real_position_(1) < workspace_limits_(2) || arm_real_position_(1) > workspace_limits_(3)) {
192 | ROS_WARN_STREAM_THROTTLE (1, "Out of permitted workspace. y = "
193 | << arm_real_position_(1) << " not in [" << workspace_limits_(2) << " , "
194 | << workspace_limits_(3) << "]");
195 | }
196 |
197 | if (arm_real_position_(2) < workspace_limits_(4) || arm_real_position_(2) > workspace_limits_(5)) {
198 | ROS_WARN_STREAM_THROTTLE (1, "Out of permitted workspace. z = "
199 | << arm_real_position_(2) << " not in [" << workspace_limits_(4) << " , "
200 | << workspace_limits_(5) << "]");
201 | }
202 |
203 | if (arm_desired_twist_final_(0) < 0 && arm_real_position_(0) < workspace_limits_(0)) {
204 | arm_desired_twist_final_(0) = 0;
205 | }
206 |
207 | if (arm_desired_twist_final_(0) > 0 && arm_real_position_(0) > workspace_limits_(1)) {
208 | arm_desired_twist_final_(0) = 0;
209 | }
210 |
211 | if (arm_desired_twist_final_(1) < 0 && arm_real_position_(1) < workspace_limits_(2)) {
212 | arm_desired_twist_final_(1) = 0;
213 | }
214 |
215 | if (arm_desired_twist_final_(1) > 0 && arm_real_position_(1) > workspace_limits_(3)) {
216 | arm_desired_twist_final_(1) = 0;
217 | }
218 |
219 | if (arm_desired_twist_final_(2) < 0 && arm_real_position_(2) < workspace_limits_(4)) {
220 | arm_desired_twist_final_(2) = 0;
221 | }
222 |
223 | if (arm_desired_twist_final_(2) > 0 && arm_real_position_(2) > workspace_limits_(5)) {
224 | arm_desired_twist_final_(2) = 0;
225 | }
226 |
227 | // velocity of the arm along x, y, and z axis
228 | double norm_vel_des = (arm_desired_twist_final_.segment(0, 3)).norm();
229 |
230 | if (norm_vel_des > arm_max_vel_) {
231 | ROS_WARN_STREAM_THROTTLE(1, "Admittance generate fast arm movements! velocity norm: " << norm_vel_des);
232 | arm_desired_twist_final_.segment(0, 3) *= (arm_max_vel_ / norm_vel_des);
233 | }
234 |
235 | }
236 |
237 | ///////////////////////////////////////////////////////////////
238 | //////////////////// COMMANDING THE ROBOT /////////////////////
239 | ///////////////////////////////////////////////////////////////
240 | void AdmittanceController::send_commands_to_robot() {
241 | geometry_msgs::Twist arm_twist_cmd;
242 |
243 | arm_twist_cmd.linear.x = arm_desired_twist_final_(0);
244 | arm_twist_cmd.linear.y = arm_desired_twist_final_(1);
245 | arm_twist_cmd.linear.z = arm_desired_twist_final_(2);
246 | arm_twist_cmd.angular.x = arm_desired_twist_final_(3);
247 | arm_twist_cmd.angular.y = arm_desired_twist_final_(4);
248 | arm_twist_cmd.angular.z = arm_desired_twist_final_(5);
249 |
250 | pub_arm_cmd_.publish(arm_twist_cmd);
251 | }
252 |
253 |
254 | //////////////////////
255 | /// INITIALIZATION ///
256 | //////////////////////
257 | void AdmittanceController::wait_for_transformations() {
258 | tf::TransformListener listener;
259 | Matrix6d rot_matrix;
260 | rotation_base_.setZero();
261 |
262 | while (!get_rotation_matrix(rot_matrix, listener, "world", "base_link")) {
263 | sleep(1);
264 | }
265 |
266 | while (!get_rotation_matrix(rotation_base_, listener, "base_link", "base_link")) {
267 | sleep(1);
268 | }
269 |
270 | while (!get_rotation_matrix(rot_matrix, listener, "base_link", "FT_link")) {
271 | sleep(1);
272 | }
273 | transformation = true;
274 |
275 | ROS_INFO("The Force/Torque sensor is ready to use.");
276 | }
277 |
278 | ////////////
279 | /// UTIL ///
280 | ////////////
281 |
282 | bool AdmittanceController::get_rotation_matrix(Matrix6d & rotation_matrix,
283 | tf::TransformListener & listener,
284 | std::string from_frame,
285 | std::string to_frame)
286 | {
287 | tf::StampedTransform transform;
288 | Matrix3d rotation_from_to;
289 | try {
290 | listener.lookupTransform(from_frame, to_frame,
291 | ros::Time(0), transform);
292 | tf::matrixTFToEigen(transform.getBasis(), rotation_from_to);
293 | rotation_matrix.setZero();
294 | // 因为力和力矩是六维的,所以用两个相同的 R
295 | rotation_matrix.topLeftCorner(3, 3) = rotation_from_to;
296 | rotation_matrix.bottomRightCorner(3, 3) = rotation_from_to;
297 | }
298 | catch (tf::TransformException ex) {
299 | rotation_matrix.setZero();
300 | ROS_WARN_STREAM_THROTTLE(1, "Waiting for TF from: " << from_frame << " to: " << to_frame );
301 | return false;
302 | }
303 |
304 | return true;
305 | }
306 |
307 |
308 |
--------------------------------------------------------------------------------
/ur5_admittance_control/src/admittance_controller_node.cpp:
--------------------------------------------------------------------------------
1 | #include "ros/ros.h"
2 | #include "AdmittanceController.h"
3 |
4 | int main(int argc, char **argv)
5 | {
6 | ros::init(argc, argv, "admittance_controller_node");
7 |
8 | ros::NodeHandle nh;
9 | double frequency = 100.0;
10 |
11 | // Parameters
12 | std::string topic_arm_state;
13 | std::string topic_arm_command;
14 | std::string topic_external_wrench;
15 |
16 | std::vector M_a;
17 | std::vector D_a;
18 | std::vector K_a;
19 | std::vector d_e;
20 | std::vector workspace_limits;
21 |
22 | double arm_max_vel;
23 | double arm_max_acc;
24 |
25 | double wrench_filter_factor;
26 | double force_dead_zone_thres;
27 | double torque_dead_zone_thres;
28 |
29 |
30 | /// LOADING PARAMETERS FROM THE ROS SERVER
31 | if (!nh.getParam("topic_arm_state", topic_arm_state)) {
32 | ROS_ERROR("Couldn't retrieve the topic name for the state of the arm.");
33 | return -1;
34 | }
35 | if (!nh.getParam("topic_arm_command", topic_arm_command)) {
36 | ROS_ERROR("Couldn't retrieve the topic name for commanding the arm.");
37 | return -1;
38 | }
39 | if (!nh.getParam("topic_external_wrench", topic_external_wrench)) {
40 | ROS_ERROR("Couldn't retrieve the topic name for the force/torque sensor.");
41 | return -1;
42 | }
43 |
44 | /// ADMITTANCE PARAMETERS
45 | if (!nh.getParam("mass_arm", M_a)) {
46 | ROS_ERROR("Couldn't retrieve the desired mass of the arm.");
47 | return -1;
48 | }
49 | if (!nh.getParam("damping_arm", D_a)) {
50 | ROS_ERROR("Couldn't retrieve the desired damping of the arm.");
51 | return -1;
52 | }
53 | if (!nh.getParam("stiffness_arm", K_a)) {
54 | ROS_ERROR("Couldn't retrieve the desired stiffness of the coupling.");
55 | return -1;
56 | }
57 | if (!nh.getParam("equilibrium_point_spring", d_e)) {
58 | ROS_ERROR("Couldn't retrieve the desired equilibrium of the spring.");
59 | return -1;
60 | }
61 |
62 | /// SAFETY PARAMETERS
63 | if (!nh.getParam("workspace_limits", workspace_limits)) {
64 | ROS_ERROR("Couldn't retrieve the limits of the workspace.");
65 | return -1;
66 | }
67 | if (!nh.getParam("arm_max_vel", arm_max_vel)) {
68 | ROS_ERROR("Couldn't retrieve the max velocity for the arm.");
69 | return -1;
70 | }
71 | if (!nh.getParam("arm_max_acc", arm_max_acc)) {
72 | ROS_ERROR("Couldn't retrieve the max acceleration for the arm.");
73 | return -1;
74 | }
75 |
76 | /// FORCE/TORQUE-SENSOR PARAMETERS
77 | if (!nh.getParam("wrench_filter_factor", wrench_filter_factor)) {
78 | ROS_ERROR("Couldn't retrieve the desired wrench filter factor.");
79 | return -1;
80 | }
81 | if (!nh.getParam("force_dead_zone_thres", force_dead_zone_thres)) {
82 | ROS_ERROR("Couldn't retrieve the desired force_dead_zone threshold.");
83 | return -1;
84 | }
85 | if (!nh.getParam("torque_dead_zone_thres", torque_dead_zone_thres)) {
86 | ROS_ERROR("Couldn't retrieve the desired torque_dead_zone threshold. ");
87 | return -1;
88 | }
89 |
90 | // Constructing the controller
91 | AdmittanceController admittance_controller(
92 | nh,
93 | frequency,
94 | topic_arm_command,
95 | topic_arm_state,
96 | topic_external_wrench,
97 | M_a, D_a, K_a, d_e,
98 | workspace_limits,
99 | arm_max_vel, arm_max_acc,
100 | wrench_filter_factor,
101 | force_dead_zone_thres,
102 | torque_dead_zone_thres);
103 |
104 | // Running the controller
105 | admittance_controller.run();
106 |
107 | return 0;
108 | }
109 |
--------------------------------------------------------------------------------
/ur5_bringup/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(ur5_bringup)
3 |
4 | add_definitions(-std=c++11)
5 |
6 | find_package(catkin REQUIRED COMPONENTS roslaunch)
7 |
8 | catkin_package()
9 |
10 | install(DIRECTORY launch urdf
11 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
12 | )
13 |
14 |
--------------------------------------------------------------------------------
/ur5_bringup/config/initial_pose.yaml:
--------------------------------------------------------------------------------
1 | initial_pose:
2 | joint_names: ["elbow_joint",
3 | "shoulder_lift_joint",
4 | "shoulder_pan_joint",
5 | "wrist_1_joint",
6 | "wrist_2_joint",
7 | "wrist_3_joint"]
8 | joint_values: [2.137181473386596,
9 | -1.4998039803657388,
10 | 1.549433454173772,
11 | -2.0415906290824704,
12 | 1.652389958375986,
13 | 0.0786922321771]
14 |
--------------------------------------------------------------------------------
/ur5_bringup/controllers/joint_state_controller.yaml:
--------------------------------------------------------------------------------
1 | joint_state_controller:
2 | type: joint_state_controller/JointStateController
3 | publish_rate: 150
4 |
--------------------------------------------------------------------------------
/ur5_bringup/controllers/ur5_vel_controller.yaml:
--------------------------------------------------------------------------------
1 | hardware_control_loop:
2 | loop_hz: 125
3 |
4 | # Settings for ros_control hardware interface
5 | hardware_interface:
6 | joints:
7 | - shoulder_pan_joint
8 | - shoulder_lift_joint
9 | - elbow_joint
10 | - wrist_1_joint
11 | - wrist_2_joint
12 | - wrist_3_joint
13 |
14 | ur5_cartesian_velocity_controller:
15 | type: cartesian_controller/CartesianVelocityController
16 | publish_rate: 125
17 | root_name: base_link
18 | tip_name: ee_link
19 |
20 | ur5_cartesian_velocity_controller_sim:
21 | type: cartesian_controller/CartesianVelocityControllerSim
22 | publish_rate: 125
23 | root_name: base_link
24 | tip_name: ee_link
25 |
26 | ur5_cartesian_state_controller:
27 | type: cartesian_controller/CartesianStateController
28 | publish_rate: 125
29 | root_name: base_link
30 | tip_name: ee_link
31 |
32 | #Publish wrench ----------------------------------
33 | force_torque_sensor_controller:
34 | type: force_torque_sensor_controller/ForceTorqueSensorController
35 | publish_rate: 125
36 |
--------------------------------------------------------------------------------
/ur5_bringup/launch/init_pose_start_controllers.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ur5_bringup/launch/robot_bringup.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
40 |
41 |
43 |
44 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
75 |
76 |
77 |
79 |
80 |
81 |
82 |
83 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/ur5_bringup/launch/ur5_bringup.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/ur5_bringup/launch/ur_force_control.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/ur5_bringup/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | ur5_bringup
4 | 0.0.0
5 | The ur5_bringup package
6 |
7 | medina
8 |
9 | TODO
10 |
11 |
12 | catkin
13 | roslaunch
14 |
15 | gazebo_msgs
16 | controller_manager_msgs
17 | robot_state_publisher
18 | urdf
19 | xacro
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/ur5_bringup/rviz/admittance_fake_wrench.rviz:
--------------------------------------------------------------------------------
1 | Panels:
2 | - Class: rviz/Displays
3 | Help Height: 78
4 | Name: Displays
5 | Property Tree Widget:
6 | Expanded:
7 | - /Grid1/Offset1
8 | Splitter Ratio: 0.675000012
9 | Tree Height: 522
10 | - Class: rviz/Selection
11 | Name: Selection
12 | - Class: rviz/Tool Properties
13 | Expanded:
14 | - /2D Pose Estimate1
15 | - /2D Nav Goal1
16 | - /Publish Point1
17 | Name: Tool Properties
18 | Splitter Ratio: 0.588679016
19 | - Class: rviz/Views
20 | Expanded:
21 | - /Current View1
22 | Name: Views
23 | Splitter Ratio: 0.5
24 | - Class: rviz/Time
25 | Experimental: false
26 | Name: Time
27 | SyncMode: 0
28 | SyncSource: ""
29 | - Class: redwall_arm_panel/Teleop
30 | Name: Teleop
31 | Toolbars:
32 | toolButtonStyle: 2
33 | Visualization Manager:
34 | Class: ""
35 | Displays:
36 | - Alpha: 0.899999976
37 | Cell Size: 1
38 | Class: rviz/Grid
39 | Color: 160; 160; 164
40 | Enabled: true
41 | Line Style:
42 | Line Width: 0.0299999993
43 | Value: Lines
44 | Name: Grid
45 | Normal Cell Count: 0
46 | Offset:
47 | X: 0
48 | Y: 0
49 | Z: 0
50 | Plane: XY
51 | Plane Cell Count: 1000
52 | Reference Frame:
53 | Value: true
54 | - Alpha: 1
55 | Class: rviz/RobotModel
56 | Collision Enabled: false
57 | Enabled: true
58 | Links:
59 | All Links Enabled: true
60 | Expand Joint Details: false
61 | Expand Link Details: false
62 | Expand Tree: false
63 | FT_link:
64 | Alpha: 1
65 | Show Axes: false
66 | Show Trail: false
67 | Value: true
68 | Link Tree Style: Links in Alphabetic Order
69 | base_link:
70 | Alpha: 1
71 | Show Axes: false
72 | Show Trail: false
73 | Value: true
74 | ee_link:
75 | Alpha: 1
76 | Show Axes: false
77 | Show Trail: false
78 | Value: true
79 | forearm_link:
80 | Alpha: 1
81 | Show Axes: false
82 | Show Trail: false
83 | Value: true
84 | shoulder_link:
85 | Alpha: 1
86 | Show Axes: false
87 | Show Trail: false
88 | Value: true
89 | upper_arm_link:
90 | Alpha: 1
91 | Show Axes: false
92 | Show Trail: false
93 | Value: true
94 | wrist_1_link:
95 | Alpha: 1
96 | Show Axes: false
97 | Show Trail: false
98 | Value: true
99 | wrist_2_link:
100 | Alpha: 1
101 | Show Axes: false
102 | Show Trail: false
103 | Value: true
104 | wrist_3_link:
105 | Alpha: 1
106 | Show Axes: false
107 | Show Trail: false
108 | Value: true
109 | Name: ur5
110 | Robot Description: robot_description
111 | TF Prefix: ""
112 | Update Interval: 0
113 | Value: true
114 | Visual Enabled: true
115 | - Class: rviz/TF
116 | Enabled: true
117 | Frame Timeout: 15
118 | Frames:
119 | All Enabled: false
120 | FT_link:
121 | Value: true
122 | base_link:
123 | Value: false
124 | ee_link:
125 | Value: true
126 | fake_force_pose:
127 | Value: false
128 | forearm_link:
129 | Value: true
130 | shoulder_link:
131 | Value: true
132 | upper_arm_link:
133 | Value: true
134 | world:
135 | Value: false
136 | wrist_1_link:
137 | Value: true
138 | wrist_2_link:
139 | Value: true
140 | wrist_3_link:
141 | Value: true
142 | Marker Scale: 1
143 | Name: TF
144 | Show Arrows: false
145 | Show Axes: false
146 | Show Names: false
147 | Tree:
148 | world:
149 | base_link:
150 | shoulder_link:
151 | upper_arm_link:
152 | forearm_link:
153 | wrist_1_link:
154 | wrist_2_link:
155 | wrist_3_link:
156 | ee_link:
157 | FT_link:
158 | {}
159 | fake_force_pose:
160 | {}
161 | Update Interval: 0
162 | Value: true
163 | - Class: rviz/InteractiveMarkers
164 | Enable Transparency: false
165 | Enabled: true
166 | Name: foce_torque_marker
167 | Show Axes: false
168 | Show Descriptions: true
169 | Show Visual Aids: false
170 | Update Topic: /fake_force_sensor/update
171 | Value: true
172 | - Alpha: 1
173 | Arrow Width: 0.5
174 | Class: rviz/WrenchStamped
175 | Enabled: true
176 | Force Arrow Scale: 2
177 | Force Color: 204; 51; 51
178 | History Length: 1
179 | Name: External_wrench
180 | Topic: /ft_sensor/data
181 | Torque Arrow Scale: 2
182 | Torque Color: 204; 204; 51
183 | Unreliable: false
184 | Value: true
185 | - Class: rviz/Image
186 | Enabled: true
187 | Image Topic: /camera/color/image_raw
188 | Max Value: 1
189 | Median window: 5
190 | Min Value: 0
191 | Name: Image
192 | Normalize Range: true
193 | Queue Size: 2
194 | Transport Hint: raw
195 | Unreliable: false
196 | Value: true
197 | - Class: octomap_rviz_plugin/OccupancyGrid
198 | Enabled: true
199 | Max. Height Display: 3.40282347e+38
200 | Max. Octree Depth: 16
201 | Min. Height Display: -3.40282347e+38
202 | Name: OccupancyGrid
203 | Octomap Topic: /octomap_full
204 | Queue Size: 5
205 | Value: true
206 | Voxel Alpha: 1
207 | Voxel Coloring: Z-Axis
208 | Voxel Rendering: All Voxels
209 | Enabled: true
210 | Global Options:
211 | Background Color: 48; 48; 48
212 | Default Light: true
213 | Fixed Frame: world
214 | Frame Rate: 30
215 | Name: root
216 | Tools:
217 | - Class: rviz/Interact
218 | Hide Inactive Objects: true
219 | - Class: rviz/MoveCamera
220 | - Class: rviz/Select
221 | - Class: rviz/FocusCamera
222 | - Class: rviz/Measure
223 | - Class: rviz/SetInitialPose
224 | Topic: /initialpose
225 | - Class: rviz/SetGoal
226 | Topic: /move_base_simple/goal
227 | - Class: rviz/PublishPoint
228 | Single click: true
229 | Topic: /clicked_point
230 | Value: true
231 | Views:
232 | Current:
233 | Class: rviz/XYOrbit
234 | Distance: 3.07725
235 | Enable Stereo Rendering:
236 | Stereo Eye Separation: 0.0599999987
237 | Stereo Focal Distance: 1
238 | Swap Stereo Eyes: false
239 | Value: false
240 | Focal Point:
241 | X: 0
242 | Y: 0
243 | Z: 0
244 | Focal Shape Fixed Size: false
245 | Focal Shape Size: 0.0500000007
246 | Invert Z Axis: false
247 | Name: Current View
248 | Near Clip Distance: 0.00999999978
249 | Pitch: 0.0252030715
250 | Target Frame: ur5_arm_base
251 | Value: XYOrbit (rviz)
252 | Yaw: 2.36222696
253 | Saved: ~
254 | Window Geometry:
255 | Displays:
256 | collapsed: false
257 | Height: 1056
258 | Hide Left Dock: false
259 | Hide Right Dock: false
260 | Image:
261 | collapsed: false
262 | QMainWindow State: 000000ff00000000fd00000004000000000000017a00000396fc020000000afb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afc0000002800000299000000d700fffffffa000000010100000002fb0000000c00430061006d0065007200610000000000ffffffff0000000000000000fb000000100044006900730070006c00610079007301000000000000017a0000016a00fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000c00430061006d00650072006100000002520000009c0000000000000000fb0000000a0049006d00610067006501000002c7000000f70000001600ffffff000000010000016200000396fc0200000004fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000c00540065006c0065006f00700100000028000003960000001600fffffffb0000000a0056006900650077007300000000440000037a000000ad00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000007800000003efc0100000002fb0000000800540069006d00650100000000000007800000030000fffffffb0000000800540069006d00650100000000000004500000000000000000000004980000039600000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
263 | Selection:
264 | collapsed: false
265 | Teleop:
266 | collapsed: false
267 | Time:
268 | collapsed: false
269 | Tool Properties:
270 | collapsed: false
271 | Views:
272 | collapsed: false
273 | Width: 1920
274 | X: 0
275 | Y: 24
276 |
--------------------------------------------------------------------------------
/ur5_bringup/src/fake_wrench.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | import rospy
4 | import copy
5 | import tf
6 | import numpy
7 |
8 | from interactive_markers.interactive_marker_server import *
9 | from interactive_markers.menu_handler import *
10 | from visualization_msgs.msg import *
11 | from geometry_msgs.msg import Point
12 | from geometry_msgs.msg import WrenchStamped
13 | from tf.broadcaster import TransformBroadcaster
14 |
15 | marker_pose = geometry_msgs.msg.Transform()
16 | listener = None
17 | wrench_pub = None
18 |
19 | def publisherCallback( msg ):
20 | try:
21 | listener.waitForTransform("/world", "/fake_force_pose", rospy.Time(0), rospy.Duration(10.0))
22 | (trans1,rot1) = listener.lookupTransform("/world", "/fake_force_pose", rospy.Time(0))
23 | (trans2,rot2) = listener.lookupTransform("/world", "/FT_link", rospy.Time(0))
24 | (trans3,rot3) = listener.lookupTransform("/FT_link", "/world",rospy.Time(0))
25 | # Publish the fake force
26 | fake_wrench = geometry_msgs.msg.WrenchStamped()
27 | trans1_mat = tf.transformations.translation_matrix(trans1)
28 | trans2_mat = tf.transformations.translation_matrix(trans2)
29 | rot3_mat = tf.transformations.quaternion_matrix(rot3)
30 | mat1 = numpy.dot(rot3_mat, trans1_mat-trans2_mat)
31 | force_at_ft_link = tf.transformations.translation_from_matrix(mat1)
32 | # print(marker_pose)
33 | fake_wrench.wrench.force.x = force_at_ft_link[0]
34 | fake_wrench.wrench.force.y = force_at_ft_link[1]
35 | fake_wrench.wrench.force.z = force_at_ft_link[2]
36 | rot = (marker_pose.rotation.x, marker_pose.rotation.y, marker_pose.rotation.z, marker_pose.rotation.w)
37 | euler = tf.transformations.euler_from_quaternion(rot)
38 | fake_wrench.wrench.torque.x = euler[0]
39 | fake_wrench.wrench.torque.y = euler[1]
40 | fake_wrench.wrench.torque.z = euler[2]
41 | fake_wrench.header.frame_id = "FT_link"
42 | fake_wrench.header.stamp = rospy.Time.now()
43 | wrench_pub.publish(fake_wrench)
44 | except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
45 | print "Coudn't find transforms!"
46 |
47 | def transformCallback( msg ):
48 | br = TransformBroadcaster()
49 | br.sendTransform((marker_pose.translation.x,
50 | marker_pose.translation.y,
51 | marker_pose.translation.z),
52 | (0,0,0,1),
53 | rospy.Time.now(),
54 | "fake_force_pose",
55 | "world")
56 |
57 | def makeBox( msg ):
58 | marker = Marker()
59 |
60 | marker.type = Marker.SPHERE
61 | marker.scale.x = msg.scale * 0.02
62 | marker.scale.y = msg.scale * 0.02
63 | marker.scale.z = msg.scale * 0.02
64 | marker.color.r = 0.0
65 | marker.color.g = 1.0
66 | marker.color.b = 0.0
67 | marker.color.a = 1.0
68 |
69 | return marker
70 |
71 | def makeBoxControl( msg ):
72 | control = InteractiveMarkerControl()
73 | control.always_visible = True
74 | control.markers.append( makeBox(msg) )
75 | msg.controls.append( control )
76 | return control
77 |
78 | def processFeedback(feedback, br):
79 | s = "Feedback from marker '" + feedback.marker_name
80 | s += "' / control '" + feedback.control_name + "'"
81 |
82 | mp = ""
83 | if feedback.mouse_point_valid:
84 | mp = " at " + str(feedback.mouse_point.x)
85 | mp += ", " + str(feedback.mouse_point.y)
86 | mp += ", " + str(feedback.mouse_point.z)
87 | mp += " in frame " + feedback.header.frame_id
88 |
89 | if feedback.event_type == InteractiveMarkerFeedback.BUTTON_CLICK:
90 | # rospy.loginfo(s + ": button click" + mp + ".")
91 | pass
92 | elif feedback.event_type == InteractiveMarkerFeedback.MENU_SELECT:
93 | # rospy.loginfo(s + ": menu item " + str(feedback.menu_entry_id) + " clicked" + mp + ".")
94 | pass
95 | elif feedback.event_type == InteractiveMarkerFeedback.POSE_UPDATE:
96 | # rospy.loginfo(s + ": pose changed")
97 | marker_pose.translation.x = feedback.pose.position.x
98 | marker_pose.translation.y = feedback.pose.position.y
99 | marker_pose.translation.z = feedback.pose.position.z
100 | marker_pose.rotation.x = feedback.pose.orientation.x
101 | marker_pose.rotation.y = feedback.pose.orientation.y
102 | marker_pose.rotation.z = feedback.pose.orientation.z
103 | marker_pose.rotation.w = feedback.pose.orientation.w
104 | elif feedback.event_type == InteractiveMarkerFeedback.MOUSE_DOWN:
105 | pass
106 | # rospy.loginfo(s + ": mouse down" + mp + ".")
107 | elif feedback.event_type == InteractiveMarkerFeedback.MOUSE_UP:
108 | # rospy.loginfo(s + ": mouse up" + mp + ".")
109 | pass
110 | server.applyChanges()
111 |
112 |
113 | if __name__ == "__main__":
114 | rospy.init_node("fake_force_sensor")
115 | br = TransformBroadcaster()
116 | listener = tf.TransformListener()
117 | wrench_pub = rospy.Publisher('/ft_sensor/data', geometry_msgs.msg.WrenchStamped, queue_size=4)
118 |
119 | # for default trans and rotation same with postion
120 | marker_pose.translation.x = 0.101201
121 | marker_pose.translation.y = 0.40755
122 | marker_pose.translation.z = 0.51814
123 | marker_pose.rotation.x = 0
124 | marker_pose.rotation.y = 0
125 | marker_pose.rotation.z = 0
126 | marker_pose.rotation.w = 1
127 |
128 | # Publisher for the topic
129 | rospy.Timer(rospy.Duration(0.02), publisherCallback)
130 | # Publisher for the TF
131 | rospy.Timer(rospy.Duration(0.02), transformCallback)
132 |
133 | server = InteractiveMarkerServer("fake_force_sensor")
134 | menu_handler = MenuHandler()
135 | pf_wrap = lambda fb: processFeedback(fb, br)
136 |
137 | menu_handler.insert("First Entry", callback=pf_wrap)
138 | menu_handler.insert("Second Entry", callback=pf_wrap)
139 | sub_menu_handle = menu_handler.insert("Submenu")
140 | menu_handler.insert("First Entry", parent=sub_menu_handle, callback=pf_wrap)
141 | menu_handler.insert("Second Entry", parent=sub_menu_handle, callback=pf_wrap)
142 |
143 | # for force and torque
144 | # position = Point(0, 0, 0)
145 | # beacause admittance_control config file
146 | # for force to zero
147 | position = Point(0.101201, 0.40755, 0.51814)
148 | int_marker = InteractiveMarker()
149 | int_marker.header.frame_id = "world"
150 | int_marker.pose.position = position
151 | int_marker.scale = 0.3
152 | int_marker.name = "fake_wrench"
153 | int_marker.description = "Simulation: \n Force = the distance vector from UR5_ee_link to marker \n Torque = the angle vector from initial orientation to marker"
154 | # insert a box
155 | makeBoxControl(int_marker)
156 |
157 |
158 | fixed = False
159 | control = InteractiveMarkerControl()
160 | control.orientation.w = 1
161 | control.orientation.x = 1
162 | control.orientation.y = 0
163 | control.orientation.z = 0
164 | control.name = "rotate_x"
165 | control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS
166 | if fixed:
167 | control.orientation_mode = InteractiveMarkerControl.FIXED
168 | int_marker.controls.append(control)
169 |
170 | control = InteractiveMarkerControl()
171 | control.orientation.w = 1
172 | control.orientation.x = 1
173 | control.orientation.y = 0
174 | control.orientation.z = 0
175 | control.name = "move_x"
176 | control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS
177 | if fixed:
178 | control.orientation_mode = InteractiveMarkerControl.FIXED
179 | int_marker.controls.append(control)
180 |
181 | control = InteractiveMarkerControl()
182 | control.orientation.w = 1
183 | control.orientation.x = 0
184 | control.orientation.y = 1
185 | control.orientation.z = 0
186 | control.name = "rotate_y"
187 | control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS
188 | if fixed:
189 | control.orientation_mode = InteractiveMarkerControl.FIXED
190 | int_marker.controls.append(control)
191 |
192 | control = InteractiveMarkerControl()
193 | control.orientation.w = 1
194 | control.orientation.x = 0
195 | control.orientation.y = 1
196 | control.orientation.z = 0
197 | control.name = "move_y"
198 | control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS
199 | if fixed:
200 | control.orientation_mode = InteractiveMarkerControl.FIXED
201 | int_marker.controls.append(control)
202 |
203 | control = InteractiveMarkerControl()
204 | control.orientation.w = 1
205 | control.orientation.x = 0
206 | control.orientation.y = 0
207 | control.orientation.z = 1
208 | control.name = "rotate_z"
209 | control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS
210 | if fixed:
211 | control.orientation_mode = InteractiveMarkerControl.FIXED
212 | int_marker.controls.append(control)
213 |
214 | control = InteractiveMarkerControl()
215 | control.orientation.w = 1
216 | control.orientation.x = 0
217 | control.orientation.y = 0
218 | control.orientation.z = 1
219 | control.name = "move_z"
220 | control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS
221 | if fixed:
222 | control.orientation_mode = InteractiveMarkerControl.FIXED
223 | int_marker.controls.append(control)
224 |
225 | server.insert(int_marker, pf_wrap)
226 | menu_handler.apply(server, int_marker.name)
227 |
228 | server.applyChanges()
229 |
230 | rospy.spin()
231 |
--------------------------------------------------------------------------------
/ur5_bringup/src/init_pose_start_controllers.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import rospy
4 | import sys
5 | import subprocess
6 |
7 | from gazebo_msgs.srv import SetModelConfiguration, SetModelConfigurationRequest
8 | from controller_manager_msgs.srv import SwitchController, SwitchControllerRequest
9 |
10 | SET_MODEL_CONFIGURATION = "/gazebo/set_model_configuration"
11 | SWITCH_CONTROLLER = "/controller_manager/switch_controller"
12 |
13 | def set_initial_pose_gazebo():
14 | set_model_config_client = rospy.ServiceProxy(SET_MODEL_CONFIGURATION, SetModelConfiguration)
15 | req = SetModelConfigurationRequest()
16 | req.model_name = "ur5"
17 | req.urdf_param_name = "robot_description"
18 | req.joint_names = rospy.get_param("/initial_pose/joint_names")
19 | req.joint_positions = rospy.get_param("/initial_pose/joint_values")
20 | rospy.wait_for_service(SET_MODEL_CONFIGURATION)
21 | res = set_model_config_client(req)
22 |
23 | def pause_gazebo():
24 | subprocess.check_call("rosservice call /gazebo/pause_physics", shell=True)
25 |
26 | def unpause_gazebo():
27 | subprocess.check_call("rosservice call /gazebo/unpause_physics", shell=True)
28 |
29 | def clear_wrenches():
30 | subprocess.check_call("rosservice call /gazebo/clear_body_wrenches \"body_name: 'ur5'\"", shell=True)
31 |
32 | def reset_world():
33 | subprocess.check_call("rosservice call /gazebo/reset_world", shell=True)
34 |
35 |
36 | def start_ros_controllers():
37 | start_controllers_client = rospy.ServiceProxy(SWITCH_CONTROLLER, SwitchController)
38 | req = SwitchControllerRequest()
39 | # this two controller is same as the ur joint trajectory controller
40 | req.start_controllers.append("ur5_cartesian_velocity_controller_sim")
41 | req.start_controllers.append("joint_state_controller")
42 | req.strictness = req.BEST_EFFORT
43 | rospy.wait_for_service(SWITCH_CONTROLLER)
44 | res = start_controllers_client(req)
45 |
46 | if __name__ == "__main__":
47 | pause_gazebo()
48 | set_initial_pose_gazebo()
49 | clear_wrenches()
50 | unpause_gazebo()
51 | start_ros_controllers()
52 |
53 |
--------------------------------------------------------------------------------
/ur5_bringup/src/timed_roslaunch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Script to delay the launch of a roslaunch file
4 | #
5 | # Koen Lekkerkerker
6 | # Thu 24 Apr 2014
7 | #
8 | # Use: ./timed_roslaunch.sh [number of seconds to delay] [rospkg] [roslaunch file]
9 | #
10 |
11 | function showHelp(){
12 | echo
13 | echo "This script can delay the launch of a roslaunch file"
14 | echo "Place it in the 'scripts' folder of your catkin package"
15 | echo "and make sure that the file is executable (chmod +x timed_roslaunch.sh)"
16 | echo
17 | echo "Run it from command line:"
18 | echo
19 | echo "Use: ./timed_roslaunch.sh [number of seconds to delay] [rospkg] [roslaunch file] [arguments (optional)]"
20 | echo "Or: rosrun [yourpackage] time_roslaunch.sh [number of seconds to delay] [rospkg] [roslaunch file] [arguments (optional)]"
21 | echo "Example: ./timed_roslaunch.sh 2 turtlebot_navigation amcl_demo.launch initial_pose_x:=17.0 initial_pose_y:=17.0"
22 | echo
23 | echo "Or run it from another roslaunch file:"
24 | echo
25 | echo ''
26 | echo ' '
27 | echo ' '
30 | echo ' '
31 | echo ' '
32 | }
33 |
34 | if [ "$1" = "-h" ]; then
35 | showHelp
36 | else
37 | echo "start wait for $1 seconds"
38 | sleep $1
39 | echo "end wait for $1 seconds"
40 | shift
41 | echo "now running 'roslaunch $@'"
42 | roslaunch $@
43 | fi
44 |
--------------------------------------------------------------------------------
/ur5_bringup/urdf/ur5.urdf.xacro:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ur5_bringup/urdf/ur5_description.urdf.xacro:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
40 |
41 |
42 |
43 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
358 |
362 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 | true
396 |
397 |
398 | true
399 |
400 |
401 | true
402 |
403 |
404 | true
405 |
406 |
407 | true
408 |
409 |
410 | true
411 |
412 |
413 | true
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 | transmission_interface/SimpleTransmission
422 |
423 | ${hw_interface}
424 |
425 |
426 | 1
427 |
428 |
429 |
430 |
431 | transmission_interface/SimpleTransmission
432 |
433 | ${hw_interface}
434 |
435 |
436 | 1
437 |
438 |
439 |
440 |
441 | transmission_interface/SimpleTransmission
442 |
443 | ${hw_interface}
444 |
445 |
446 | 1
447 |
448 |
449 |
450 |
451 | transmission_interface/SimpleTransmission
452 |
453 | ${hw_interface}
454 |
455 |
456 | 1
457 |
458 |
459 |
460 |
461 | transmission_interface/SimpleTransmission
462 |
463 | ${hw_interface}
464 |
465 |
466 | 1
467 |
468 |
469 |
470 |
471 | transmission_interface/SimpleTransmission
472 |
473 | ${hw_interface}
474 |
475 |
476 | 1
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 | /
485 | true
486 |
487 |
488 |
489 |
--------------------------------------------------------------------------------
/ur5_bringup/worlds/bifurcation.world:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1
5 | 0 0 10 0 -0 0
6 | 0.8 0.8 0.8 1
7 | 0.2 0.2 0.2 1
8 |
9 | 1000
10 | 0.9
11 | 0.01
12 | 0.001
13 |
14 | -0.5 0.1 -0.9
15 |
16 |
17 | 1
18 |
19 |
20 |
21 |
22 | 0 0 1
23 | 100 100
24 |
25 |
26 |
27 |
28 |
29 | 100
30 | 50
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | 10
39 |
40 |
41 | 0
42 |
43 |
44 | 0 0 1
45 | 100 100
46 |
47 |
48 |
49 |
53 |
54 |
55 |
56 | 0
57 | 0
58 |
59 | 0
60 | 0
61 | 1
62 |
63 |
64 |
65 | 0.001
66 | 1
67 | 1000
68 | 0 0 -9.8
69 |
70 |
71 | 0.4 0.4 0.4 1
72 | 0.7 0.7 0.7 1
73 | 1
74 |
75 |
76 | EARTH_WGS84
77 | 0
78 | 0
79 | 0
80 | 0
81 |
82 |
83 | 1
84 |
85 |
86 | 0 0 1 0 -0 0
87 |
88 |
89 | 1.5 0.8 0.03
90 |
91 |
92 |
93 |
94 |
95 | 0.6
96 | 0.6
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | 10
105 |
106 |
107 | 0 0 1 0 -0 0
108 |
109 |
110 | 1.5 0.8 0.03
111 |
112 |
113 |
114 |
118 |
119 |
120 |
121 | 0.68 0.38 0.5 0 -0 0
122 |
123 |
124 | 0.02
125 | 1
126 |
127 |
128 | 10
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | 0.68 0.38 0.5 0 -0 0
141 |
142 |
143 | 0.02
144 | 1
145 |
146 |
147 |
148 |
152 |
153 |
154 |
155 | 0.68 -0.38 0.5 0 -0 0
156 |
157 |
158 | 0.02
159 | 1
160 |
161 |
162 | 10
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 | 0.68 -0.38 0.5 0 -0 0
175 |
176 |
177 | 0.02
178 | 1
179 |
180 |
181 |
182 |
186 |
187 |
188 |
189 | -0.68 -0.38 0.5 0 -0 0
190 |
191 |
192 | 0.02
193 | 1
194 |
195 |
196 | 10
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 | -0.68 -0.38 0.5 0 -0 0
209 |
210 |
211 | 0.02
212 | 1
213 |
214 |
215 |
216 |
220 |
221 |
222 |
223 | -0.68 0.38 0.5 0 -0 0
224 |
225 |
226 | 0.02
227 | 1
228 |
229 |
230 | 10
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 | -0.68 0.38 0.5 0 -0 0
243 |
244 |
245 | 0.02
246 | 1
247 |
248 |
249 |
250 |
254 |
255 |
256 |
257 | 0
258 | 0
259 |
260 | 0
261 | 0
262 | 1
263 |
264 | 0 1.45575 0 0 -0 0
265 |
266 |
267 | true
268 |
269 |
270 | 0 0 1 0 -0 0
271 |
272 |
273 | 1.5 0.8 0.03
274 |
275 |
276 |
277 |
278 |
279 | 0.6
280 | 0.6
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 | 10
289 |
290 |
291 | 0 0 1 0 -0 0
292 |
293 |
294 | 1.5 0.8 0.03
295 |
296 |
297 |
298 |
302 |
303 |
304 |
305 | 0.68 0.38 0.5 0 -0 0
306 |
307 |
308 | 0.02
309 | 1
310 |
311 |
312 | 10
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 | 0.68 0.38 0.5 0 -0 0
325 |
326 |
327 | 0.02
328 | 1
329 |
330 |
331 |
332 |
336 |
337 |
338 |
339 | 0.68 -0.38 0.5 0 -0 0
340 |
341 |
342 | 0.02
343 | 1
344 |
345 |
346 | 10
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 | 0.68 -0.38 0.5 0 -0 0
359 |
360 |
361 | 0.02
362 | 1
363 |
364 |
365 |
366 |
370 |
371 |
372 |
373 | -0.68 -0.38 0.5 0 -0 0
374 |
375 |
376 | 0.02
377 | 1
378 |
379 |
380 | 10
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 | -0.68 -0.38 0.5 0 -0 0
393 |
394 |
395 | 0.02
396 | 1
397 |
398 |
399 |
400 |
404 |
405 |
406 |
407 | -0.68 0.38 0.5 0 -0 0
408 |
409 |
410 | 0.02
411 | 1
412 |
413 |
414 | 10
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 | -0.68 0.38 0.5 0 -0 0
427 |
428 |
429 | 0.02
430 | 1
431 |
432 |
433 |
434 |
438 |
439 |
440 |
441 | 0
442 | 0
443 |
444 | 0
445 | 0
446 | 1
447 |
448 | 6 1.48898 0 0 -0 0
449 |
450 |
451 |
452 |
453 |
454 |
455 | model://stop_sign/meshes/stop_sign.dae
456 |
457 |
458 | 10
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 | model://stop_sign/meshes/stop_sign.dae
473 |
474 |
475 |
476 |
481 |
482 |
483 |
484 | 0
485 | 0
486 |
487 | 0
488 |
489 |
490 | 1
491 | 0
492 | 0
493 | 1
494 | 0
495 | 1
496 |
497 | 1
498 |
499 | 0
500 | 1
501 |
502 | 3 -2 0 0 -0 0
503 | 1
504 |
505 |
506 |
507 | 3 -2 0 1.5e-05 7e-06 0
508 |
509 | 3 -2 0 1.5e-05 7e-06 0
510 | 0 0 0 0 -0 0
511 | -0 0 -0.010602 -0.107938 -0.303544 0
512 | -0 0 -0.010602 0 -0 0
513 |
514 |
515 |
516 | 0 0 0 0 -0 0
517 |
518 | 0 0 0 0 -0 0
519 | 0 0 0 0 -0 0
520 | 0 0 0 0 -0 0
521 | 0 0 0 0 -0 0
522 |
523 |
524 |
525 | 0 1.45575 0 0 -0 0
526 |
527 | 0 1.45575 0 0 -0 0
528 | 0 0 0 0 -0 0
529 | 0 0 0 0 -0 0
530 | 0 0 0 0 -0 0
531 |
532 |
533 |
534 | 6 1.48898 0 0 -0 0
535 |
536 | 6 1.48898 0 0 -0 0
537 | 0 0 0 0 -0 0
538 | 0 0 0 0 -0 0
539 | 0 0 0 0 -0 0
540 |
541 |
542 |
543 |
544 |
545 | 9.83224 -8.50019 7.46455 0 0.589424 2.35245
546 | orbit
547 |
548 |
549 |
550 |
551 |
--------------------------------------------------------------------------------
/ur5_bringup/worlds/empty.world:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | model://sun
7 |
8 |
9 |
10 | model://ground_plane
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ur5_cartesian_velocity_control/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(ur5_cartesian_velocity_control)
3 |
4 | ## Add support for C++11, supported in ROS Kinetic and newer
5 | # add_definitions(-std=c++11)
6 |
7 |
8 | find_package(catkin REQUIRED COMPONENTS
9 | controller_interface
10 | control_msgs
11 | forward_command_controller
12 | control_toolbox
13 | realtime_tools
14 | urdf
15 | roscpp
16 | kdl_parser
17 | kdl_conversions
18 | ur5_admittance_control
19 | )
20 | set(CMAKE_CXX_FLAGS "-O2 -O3 -std=c++11 -mtune=native -fPIC -Wall -Wno-deprecated-declarations")
21 |
22 |
23 | catkin_package(
24 | INCLUDE_DIRS include
25 | LIBRARIES ur5_cartesian_velocity_control
26 | DEPENDS ur5_admittance_control
27 | )
28 |
29 | include_directories(include ${catkin_INCLUDE_DIRS})
30 |
31 |
32 | ## Declare a C++ library
33 | # add_library(${PROJECT_NAME}
34 | # src/${PROJECT_NAME}/ur5_cartesian_velocity_control.cpp
35 | # )
36 | add_library(${PROJECT_NAME}
37 | include/ur5_cartesian_velocity_control/kinematic_chain_controller_base.h
38 | include/ur5_cartesian_velocity_control/cartesian_velocity_controller.h
39 | include/ur5_cartesian_velocity_control/cartesian_state_controller.h
40 | src/cartesian_velocity_controller.cpp
41 | src/cartesian_state_controller.cpp
42 | )
43 |
44 | add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
45 |
46 | ## Specify libraries to link a library or executable target against
47 | # target_link_libraries(${PROJECT_NAME}_node
48 | # ${catkin_LIBRARIES}
49 | # )
50 | target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES})
51 |
--------------------------------------------------------------------------------
/ur5_cartesian_velocity_control/config/controllers.yaml:
--------------------------------------------------------------------------------
1 | ur5:
2 | # Controller for the real hardware (velocity interface)
3 | cartesian_velocity_controller:
4 | type: cartesian_controller/CartesianVelocityController
5 | publish_rate: 125
6 | root_name: base_link
7 | tip_name: ee_link
8 |
9 | # Controller for gazebo (velocity interface on top of a position interface)
10 | cartesian_velocity_controller_sim:
11 | type: cartesian_controller/CartesianVelocityControllerSim
12 | publish_rate: 125
13 | root_name: base_link
14 | tip_name: ee_link
15 |
16 | # Cartesian state publisher
17 | cartesian_state_controller:
18 | type: cartesian_controller/CartesianStateController
19 | publish_rate: 125
20 | root_name: base_link
21 | tip_name: ee_link
22 |
--------------------------------------------------------------------------------
/ur5_cartesian_velocity_control/include/ur5_cartesian_velocity_control/cartesian_state_controller.h:
--------------------------------------------------------------------------------
1 | #ifndef CARTESIAN_STATE_CONTROLLER_H
2 | #define CARTESIAN_STATE_CONTROLLER_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "ur5_cartesian_velocity_control/kinematic_chain_controller_base.h"
11 | #include
12 |
13 | namespace controller_interface
14 | {
15 |
16 | /** \brief This class implements a cartesian state publisher
17 | * for ROS control.
18 | */
19 |
20 | class CartesianStateController:
21 | public KinematicChainControllerBase<
22 | hardware_interface::JointStateInterface>
23 | {
24 | public:
25 | CartesianStateController() {}
26 | ~CartesianStateController() {}
27 |
28 | /** \brief The init function is called to initialize the controller from a
29 | * non-realtime thread with a pointer to the hardware interface, itself,
30 | * instead of a pointer to a RobotHW.
31 | *s
32 | * \param robot The specific hardware interface used by this controller.
33 | *
34 | * \param n A NodeHandle in the namespace from which the controller
35 | * should read its configuration, and where it should set up its ROS
36 | * interface.
37 | *
38 | * \returns True if initialization was successful and the controller
39 | * is ready to be started.
40 | */
41 | bool init(hardware_interface::JointStateInterface *robot, ros::NodeHandle &n);
42 |
43 | /** \brief This is called from within the realtime thread just before the
44 | * first call to \ref update
45 | *
46 | * \param time The current time
47 | */
48 | void starting(const ros::Time& time);
49 |
50 | /*!
51 | * \brief Issues commands to the joint. Called at regular intervals
52 | */
53 | void update(const ros::Time& time, const ros::Duration& period);
54 |
55 | protected:
56 | ros::Publisher pub_state_;
57 |
58 | KDL::FrameVel x_dot_;
59 | KDL::Frame x_;
60 |
61 | boost::shared_ptr fk_vel_solver_;
62 | boost::shared_ptr fk_pos_solver_;
63 |
64 | boost::shared_ptr > realtime_pub_;
66 |
67 | ros::Time last_publish_time_;
68 | double publish_rate_;
69 | };
70 |
71 | } // namespace controller_interface
72 |
73 |
74 | #endif
75 |
--------------------------------------------------------------------------------
/ur5_cartesian_velocity_control/include/ur5_cartesian_velocity_control/cartesian_velocity_controller.h:
--------------------------------------------------------------------------------
1 | #ifndef CARTESIAN_VELOCITY_CONTROLLER_H
2 | #define CARTESIAN_VELOCITY_CONTROLLER_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include "ur5_cartesian_velocity_control/kinematic_chain_controller_base.h"
15 | #include
16 |
17 | namespace controller_interface
18 | {
19 |
20 | /** \brief This class implements a ROS control cartesian velocity
21 | * controller. Its base class implements the core
22 | * of the controller.
23 | */
24 |
25 | template
26 | class CartesianVelocityControllerBase:
27 | public KinematicChainControllerBase
28 | {
29 | public:
30 | CartesianVelocityControllerBase() {}
31 | ~CartesianVelocityControllerBase() {}
32 |
33 | /** \brief The init function is called to initialize the controller from a
34 | * non-realtime thread with a pointer to the hardware interface, itself,
35 | * instead of a pointer to a RobotHW.
36 | *s
37 | * \param robot The specific hardware interface used by this controller.
38 | *
39 | * \param n A NodeHandle in the namespace from which the controller
40 | * should read its configuration, and where it should set up its ROS
41 | * interface.
42 | *
43 | * \returns True if initialization was successful and the controller
44 | * is ready to be started.
45 | */
46 | bool init(T *robot, ros::NodeHandle &n);
47 |
48 | /** \brief This is called from within the realtime thread just before the
49 | * first call to \ref update
50 | *
51 | * \param time The current time
52 | */
53 | void starting(const ros::Time& time);
54 |
55 | /*!
56 | * \brief Issues commands to the joint. Called at regular intervals
57 | */
58 | void update(const ros::Time& time, const ros::Duration& period);
59 |
60 | /*!
61 | * \brief Subscriber's callback function
62 | */
63 | void command_cart_vel(const geometry_msgs::TwistConstPtr &msg);
64 |
65 | /** \brief Write current commands to the hardware interface
66 | */
67 | virtual void writeVelocityCommands(const ros::Duration& period) = 0;
68 |
69 | protected:
70 | ros::Subscriber sub_command_; // Interface to external commands
71 |
72 | KDL::Twist x_dt_des_; // Desired end-effector velocity
73 | KDL::JntArray q_dt_cmd_; // Desired joint velocity
74 |
75 | boost::shared_ptr ik_vel_solver_;
76 |
77 | boost::shared_ptr > realtime_pub_;
79 |
80 | ros::Time last_publish_time_;
81 | double publish_rate_;
82 |
83 | KDL::FrameVel x_dot_;
84 | KDL::Frame x_;
85 | ur5_admittance_control::PoseTwist msg_state_;
86 |
87 | boost::shared_ptr fk_vel_solver_;
88 | boost::shared_ptr fk_pos_solver_;
89 | };
90 |
91 | /** \brief Two different instantiations of the CartesianVelocityControllerBase
92 | * are provided here:
93 | * - CartesianVelocityController: with a VelocityJointInterface
94 | * - CartesianVelocityControllerSim: with a PositionJointInterface
95 | * (for gazebo)
96 | */
97 |
98 | /** The controller instance for the real hardware
99 | * */
100 | class CartesianVelocityController :
101 | public CartesianVelocityControllerBase<
102 | hardware_interface::VelocityJointInterface> {
103 | /**
104 | * Write velocity commands through a velocity interface
105 | */
106 | void writeVelocityCommands(const ros::Duration& period);
107 | };
108 |
109 | /**
110 | * The controller instance for simulationd in gazebo. As of now
111 | * gazebo does not provide a VelocityJointInterface and therefore we simulate
112 | * it here through a PositionJointInterface.
113 | */
114 | class CartesianVelocityControllerSim :
115 | public CartesianVelocityControllerBase<
116 | hardware_interface::PositionJointInterface> {
117 |
118 | /**
119 | * Write velocity commands through a position interface
120 | */
121 | void writeVelocityCommands(const ros::Duration& period);
122 | };
123 |
124 | } // namespace controller_interface
125 |
126 |
127 | #endif
128 |
--------------------------------------------------------------------------------
/ur5_cartesian_velocity_control/include/ur5_cartesian_velocity_control/kinematic_chain_controller_base.h:
--------------------------------------------------------------------------------
1 | #ifndef KINEMATIC_CHAIN_CONTROLLER_BASE_H
2 | #define KINEMATIC_CHAIN_CONTROLLER_BASE_H
3 |
4 | #include
5 | #include
6 |
7 | #include
8 | #include
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include //this to compute the gravity vector
16 | #include
17 | #include
18 | #include
19 |
20 | #include
21 |
22 | namespace controller_interface
23 | {
24 | template
25 | class KinematicChainControllerBase: public Controller
26 | {
27 | public:
28 | KinematicChainControllerBase() {}
29 | ~KinematicChainControllerBase() {}
30 |
31 | bool init(JI *robot, ros::NodeHandle &n);
32 |
33 | protected:
34 | ros::NodeHandle nh_;
35 | KDL::Chain kdl_chain_;
36 | KDL::JntArrayVel joint_msr_;
37 |
38 | struct limits_
39 | {
40 | KDL::JntArray min;
41 | KDL::JntArray max;
42 | KDL::JntArray center;
43 | } joint_limits_;
44 |
45 | std::vector joint_handles_;
46 | };
47 |
48 | template
49 | bool KinematicChainControllerBase::init(JI *robot, ros::NodeHandle &n)
50 | {
51 | nh_ = n;
52 |
53 | // get URDF and name of root and tip from the parameter server
54 | std::string robot_description, root_name, tip_name;
55 |
56 | std::string name_space = nh_.getNamespace();
57 | std::cout<< "--------------------> name_space: " << name_space << std::endl;
58 |
59 | if (!ros::param::search(name_space,"robot_description", robot_description))
60 | {
61 | ROS_ERROR_STREAM("KinematicChainControllerBase: No robot description (URDF)"
62 | "found on parameter server (" << n.getNamespace() <<
63 | "/robot_description)");
64 | return false;
65 | }
66 |
67 | if (!nh_.getParam( name_space + "/root_name", root_name))
68 | {
69 | ROS_ERROR_STREAM("KinematicChainControllerBase: No root name found on "
70 | "parameter server ("< "< link_ = model.getLink(tip_name);
151 | boost::shared_ptr joint_;
152 | joint_limits_.min.resize(kdl_chain_.getNrOfJoints());
153 | joint_limits_.max.resize(kdl_chain_.getNrOfJoints());
154 | joint_limits_.center.resize(kdl_chain_.getNrOfJoints());
155 | int index;
156 |
157 | for (std::size_t i = 0; i < kdl_chain_.getNrOfJoints() && link_; i++)
158 | {
159 | joint_ = model.getJoint(link_->parent_joint->name);
160 | ROS_INFO("Getting limits for joint: %s", joint_->name.c_str());
161 | index = kdl_chain_.getNrOfJoints() - i - 1;
162 |
163 | if(joint_->limits){
164 | joint_limits_.min(index) = joint_->limits->lower;
165 | joint_limits_.max(index) = joint_->limits->upper;
166 | joint_limits_.center(index) = (joint_limits_.min(index) +
167 | joint_limits_.max(index))/2;
168 | }else{
169 | joint_limits_.min(index) = 0;
170 | joint_limits_.max(index) = 0;
171 | joint_limits_.center(index) = 0;
172 | ROS_INFO("joint_->limits is NULL %s",joint_->name.c_str());
173 | }
174 |
175 | link_ = model.getLink(link_->getParent()->name);
176 | }
177 |
178 | ROS_INFO("Getting joint handles");
179 | // Get joint handles for all of the joints in the chain
180 | int count=0;
181 | for(std::vector::const_iterator it =
182 | kdl_chain_.segments.begin(); it != kdl_chain_.segments.end(); ++it)
183 | {
184 |
185 | ROS_INFO("%s type: %s", it->getJoint().getName().c_str(),
186 | it->getJoint().getTypeName().c_str() );
187 | if(it->getJoint().getTypeName() != "None" && count < 7) {
188 | joint_handles_.push_back(robot->getHandle(it->getJoint().getName()));
189 | }
190 | count++;
191 | }
192 |
193 | ROS_INFO("Number of joints in handle = %lu", joint_handles_.size() );
194 | ROS_INFO_STREAM("kdl_chain.getNrOfJoints: " << kdl_chain_.getNrOfJoints());
195 |
196 | ROS_INFO("Finished Kinematic Base init");
197 |
198 | return true;
199 | }
200 |
201 | }
202 |
203 | #endif
204 |
--------------------------------------------------------------------------------
/ur5_cartesian_velocity_control/launch/load_controller.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ur5_cartesian_velocity_control/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | ur5_cartesian_velocity_control
4 | 0.0.1
5 | The ur5_cartesian_velocity_control package
6 |
7 |
8 |
9 |
10 | Jose Medina
11 |
12 |
13 |
14 |
15 |
16 | MIT
17 |
18 | catkin
19 | controller_interface
20 | control_msgs
21 | control_toolbox
22 | realtime_tools
23 | urdf
24 | forward_command_controller
25 | kdl_parser
26 | kdl_conversions
27 | cmake_modules
28 | eigen
29 | ur5_admittance_control
30 |
31 | controller_interface
32 | control_msgs
33 | control_toolbox
34 | realtime_tools
35 | urdf
36 | forward_command_controller
37 | kdl_parser
38 | kdl_conversions
39 | eigen
40 | ur5_admittance_control
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/ur5_cartesian_velocity_control/src/cartesian_state_controller.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "ur5_cartesian_velocity_control/kinematic_chain_controller_base.h"
3 | #include "ur5_cartesian_velocity_control/cartesian_state_controller.h"
4 | #include "kdl_conversions/kdl_msg.h"
5 |
6 |
7 | namespace controller_interface
8 | {
9 | /** \brief Initialize the kinematic chain for kinematics-based computation.
10 | *
11 | */
12 |
13 | bool CartesianStateController::init(
14 | hardware_interface::JointStateInterface *robot, ros::NodeHandle &n) {
15 |
16 | KinematicChainControllerBase::
17 | init(robot, n);
18 |
19 | fk_vel_solver_.reset(new KDL::ChainFkSolverVel_recursive(kdl_chain_));
20 | fk_pos_solver_.reset(new KDL::ChainFkSolverPos_recursive(kdl_chain_));
21 |
22 | // get publishing period
23 | if (!n.getParam("publish_rate", publish_rate_)){
24 | ROS_ERROR("Parameter 'publish_rate' not set");
25 | return false;
26 | }
27 | realtime_pub_.reset(new realtime_tools::RealtimePublisher
28 | (n, "ee_state", 4));
29 |
30 | x_.p.Zero();
31 | x_.M.Identity();
32 | x_dot_.p.Zero();
33 | x_dot_.M.Identity();
34 |
35 | return true;
36 | }
37 |
38 | /** \brief This is called from within the realtime thread just before the
39 | * first call to \ref update
40 | *
41 | * \param time The current time
42 | */
43 | void CartesianStateController::starting(const ros::Time& time) {
44 | last_publish_time_ = time;
45 | }
46 |
47 | /*!
48 | * \brief Issues commands to the joint. Should be called at regular intervals
49 | */
50 | void CartesianStateController::update(const ros::Time& time,
51 | const ros::Duration& period) {
52 |
53 | // Get joint positions
54 | for(std::size_t i=0; i < joint_handles_.size(); i++)
55 | {
56 | joint_msr_.q(i) = joint_handles_[i].getPosition();
57 | joint_msr_.qdot(i) = joint_handles_[i].getVelocity();
58 | }
59 |
60 | // Compute forward kinematics
61 | fk_vel_solver_->JntToCart(joint_msr_, x_dot_);
62 | fk_pos_solver_->JntToCart(joint_msr_.q, x_);
63 |
64 | // Limit rate of publishing
65 | if (publish_rate_ > 0.0 && last_publish_time_
66 | + ros::Duration(1.0/publish_rate_) < time) {
67 |
68 | // try to publish
69 | if (realtime_pub_->trylock()) {
70 | // we're actually publishing, so increment time
71 | last_publish_time_ = last_publish_time_
72 | + ros::Duration(1.0/publish_rate_);
73 |
74 | // populate message
75 | realtime_pub_->msg_.header.stamp = time;
76 | tf::poseKDLToMsg(x_, realtime_pub_->msg_.pose);
77 | tf::twistKDLToMsg(x_dot_.GetTwist(), realtime_pub_->msg_.twist);
78 |
79 | realtime_pub_->unlockAndPublish();
80 | }
81 | }
82 |
83 | }
84 |
85 | } // controller_interface
86 |
87 | // Register controllers with the PLUGINLIB_EXPORT_CLASS macro to enable dynamic
88 | // loading with the controller manager
89 | PLUGINLIB_EXPORT_CLASS(controller_interface::CartesianStateController, controller_interface::ControllerBase)
90 |
--------------------------------------------------------------------------------
/ur5_cartesian_velocity_control/src/cartesian_velocity_controller.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "ur5_cartesian_velocity_control/kinematic_chain_controller_base.h"
3 | #include "ur5_cartesian_velocity_control/cartesian_velocity_controller.h"
4 | #include "kdl_conversions/kdl_msg.h"
5 |
6 | namespace controller_interface
7 | {
8 | /** \brief Initialize the kinematic chain for kinematics-based computation.
9 | *
10 | */
11 | template
12 | bool CartesianVelocityControllerBase::init(
13 | T *robot, ros::NodeHandle &n) {
14 |
15 | // KDL
16 | KinematicChainControllerBase::init(robot, n);
17 | ik_vel_solver_.reset(new KDL::ChainIkSolverVel_pinv_givens(this->kdl_chain_));
18 | fk_vel_solver_.reset(new KDL::ChainFkSolverVel_recursive(this->kdl_chain_));
19 | fk_pos_solver_.reset(new KDL::ChainFkSolverPos_recursive(this->kdl_chain_));
20 |
21 | // get publishing period
22 | if (!n.getParam("publish_rate", publish_rate_)){
23 | ROS_ERROR("Parameter 'publish_rate' not set");
24 | return false;
25 | }
26 | realtime_pub_.reset(new realtime_tools::RealtimePublisher
27 | (n, "ee_state", 4));
28 |
29 |
30 | // Topics
31 | sub_command_ = n.subscribe("command_cart_vel", 5,
32 | &CartesianVelocityControllerBase::command_cart_vel,
33 | this,ros::TransportHints().reliable().tcpNoDelay());
34 |
35 | // Variable init
36 | this->joint_msr_.resize(this->kdl_chain_.getNrOfJoints());
37 | q_dt_cmd_.resize(this->kdl_chain_.getNrOfJoints());
38 | x_dt_des_ = KDL::Twist::Zero();
39 | x_.p.Zero();
40 | x_.M.Identity();
41 | x_dot_.p.Zero();
42 | x_dot_.M.Identity();
43 |
44 | return true;
45 | }
46 |
47 | /** \brief This is called from within the realtime thread just before the
48 | * first call to \ref update
49 | *
50 | * \param time The current time
51 | */
52 | template
53 | void CartesianVelocityControllerBase::starting(const ros::Time& time){
54 | for(std::size_t i=0; i < this->joint_handles_.size(); i++) {
55 | q_dt_cmd_(i) = 0.0;
56 | }
57 | x_dt_des_ = KDL::Twist::Zero();
58 | last_publish_time_ = time;
59 | }
60 |
61 | /*!
62 | * \brief Issues commands to the joint. Should be called at regular intervals
63 | */
64 | template
65 | void CartesianVelocityControllerBase::update(const ros::Time& time,
66 | const ros::Duration& period) {
67 |
68 | // Get joint positions
69 | for(std::size_t i=0; i < this->joint_handles_.size(); i++)
70 | {
71 | this->joint_msr_.q(i) = this->joint_handles_[i].getPosition();
72 | this->joint_msr_.qdot(i) = this->joint_handles_[i].getVelocity();
73 | }
74 |
75 | // Compute inverse kinematics velocity solver
76 | ik_vel_solver_->CartToJnt(this->joint_msr_.q, x_dt_des_, q_dt_cmd_);
77 | writeVelocityCommands(period);
78 |
79 | // Forward kinematics
80 | fk_vel_solver_->JntToCart(this->joint_msr_, x_dot_);
81 | fk_pos_solver_->JntToCart(this->joint_msr_.q, x_);
82 |
83 | // Limit rate of publishing
84 | if (publish_rate_ > 0.0 && last_publish_time_
85 | + ros::Duration(1.0/publish_rate_) < time) {
86 |
87 | // try to publish
88 | if (realtime_pub_->trylock()) {
89 | // we're actually publishing, so increment time
90 | last_publish_time_ = last_publish_time_
91 | + ros::Duration(1.0/publish_rate_);
92 |
93 | // populate message
94 | realtime_pub_->msg_.header.stamp = time;
95 | tf::poseKDLToMsg(x_, realtime_pub_->msg_.pose);
96 | tf::twistKDLToMsg(x_dot_.GetTwist(), realtime_pub_->msg_.twist);
97 |
98 | realtime_pub_->unlockAndPublish();
99 | }
100 | }
101 | }
102 |
103 | /*!
104 | * \brief Subscriber's callback: copies twist commands
105 | */
106 | template
107 | void CartesianVelocityControllerBase::command_cart_vel(
108 | const geometry_msgs::TwistConstPtr &msg) {
109 | x_dt_des_.vel(0) = msg->linear.x;
110 | x_dt_des_.vel(1) = msg->linear.y;
111 | x_dt_des_.vel(2) = msg->linear.z;
112 | x_dt_des_.rot(0) = msg->angular.x;
113 | x_dt_des_.rot(1) = msg->angular.y;
114 | x_dt_des_.rot(2) = msg->angular.z;
115 | }
116 |
117 |
118 | /********************************************/
119 | /**FUNCTIONS OF INSTANCES OF THE BASE CLASS**/
120 | /********************************************/
121 |
122 | /** \brief write the desired velocity command in the hardware interface input
123 | * for a VelocityJointInterface
124 | * \param period The duration of an update cycle
125 | */
126 | void CartesianVelocityController::writeVelocityCommands(
127 | const ros::Duration& period) {
128 | for(std::size_t i=0; i < this->joint_handles_.size(); i++) {
129 | this->joint_handles_[i].setCommand(q_dt_cmd_(i));
130 | }
131 | }
132 |
133 | /** \brief write the desired velocity command in the hardware interface input
134 | * for a PosititionJointInterface
135 | * \param period The duration of an update cycle
136 | */
137 | void CartesianVelocityControllerSim::writeVelocityCommands(
138 | const ros::Duration& period) {
139 | for(std::size_t i=0; i < this->joint_handles_.size(); i++) {
140 | this->joint_handles_[i].setCommand(this->joint_msr_.q(i)
141 | + q_dt_cmd_(i)*period.toSec());
142 | }
143 | }
144 |
145 | } // controller_interface namespace
146 |
147 | // Register controllers with the PLUGINLIB_EXPORT_CLASS macro to enable dynamic
148 | // loading with the controller manager
149 | PLUGINLIB_EXPORT_CLASS(controller_interface::CartesianVelocityController,
150 | controller_interface::ControllerBase)
151 | PLUGINLIB_EXPORT_CLASS(controller_interface::CartesianVelocityControllerSim,
152 | controller_interface::ControllerBase)
153 |
--------------------------------------------------------------------------------
/ur5_cartesian_velocity_control/ur5_cartesian_velocity_control_plugin.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Cartesian velocity control
5 |
6 |
7 |
8 |
9 |
10 | Cartesian state observer
11 |
12 |
13 |
14 |
15 |
16 | Cartesian velocity control using a position interface. This is used in conjunction with Gazebo which, at the moment of writing this code, does not fully support a joint velocity interface.
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------