sdhx_node.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #################################################################
00003 ##\file
00004 #
00005 # \note
00006 # Copyright (c) 2014 \n
00007 # Fraunhofer Institute for Manufacturing Engineering
00008 # and Automation (IPA) \n\n
00009 #
00010 #################################################################
00011 #
00012 # \note
00013 # Project name: schunk_modular_robotics
00014 # \note
00015 # ROS stack name: schunk_sdhx
00016 # \note
00017 # ROS package name: schunk_sdhx
00018 #
00019 # \author
00020 # Thiago de Freitas, email:tdf@ipa.fhg.de
00021 #
00022 # \date Date of creation: November 2014
00023 #
00024 # \brief
00025 # Simple driver for the Schunk SDHx
00026 #
00027 #################################################################
00028 #
00029 # Redistribution and use in source and binary forms, with or without
00030 # modification, are permitted provided that the following conditions are met:
00031 #
00032 # - Redistributions of source code must retain the above copyright
00033 # notice, this list of conditions and the following disclaimer. \n
00034 # - Redistributions in binary form must reproduce the above copyright
00035 # notice, this list of conditions and the following disclaimer in the
00036 # documentation and/or other materials provided with the distribution. \n
00037 # - Neither the name of the Fraunhofer Institute for Manufacturing
00038 # Engineering and Automation (IPA) nor the names of its
00039 # contributors may be used to endorse or promote products derived from
00040 # this software without specific prior written permission. \n
00041 #
00042 # This program is free software: you can redistribute it and/or modify
00043 # it under the terms of the GNU Lesser General Public License LGPL as
00044 # published by the Free Software Foundation, either version 3 of the
00045 # License, or (at your option) any later version.
00046 #
00047 # This program is distributed in the hope that it will be useful,
00048 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00049 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00050 # GNU Lesser General Public License LGPL for more details.
00051 #
00052 # You should have received a copy of the GNU Lesser General Public
00053 # License LGPL along with this program.
00054 # If not, see <http://www.gnu.org/licenses/>.
00055 #
00056 #################################################################
00057 
00058 import serial
00059 import time
00060 import math
00061 import threading
00062 import os
00063 
00064 import rospy
00065 import actionlib
00066 from control_msgs.msg import *
00067 from sensor_msgs.msg import *
00068 
00069 FJT_ACTION_NAME = "joint_trajectory_controller/follow_joint_trajectory"
00070 
00071 Terminator="\r\n"
00072 commands = {"position": "p", "stop": "s", "move": "m", "set_pwm":"set", "get_pwm":"get"}
00073 
00074 class Sdhx():
00075 
00076   def __init__(self):
00077 
00078     if(rospy.has_param("~devicestring")):
00079       rospy.loginfo("Setting port to:")
00080       self.port = rospy.get_param("~devicestring")
00081       rospy.loginfo(self.port)
00082     self.min_pwm0 = rospy.get_param("~min_pwm0")
00083     self.min_pwm1 = rospy.get_param("~min_pwm1")
00084     self.max_pwm0 = rospy.get_param("~max_pwm0")
00085     self.max_pwm1 = rospy.get_param("~max_pwm1")
00086 
00087     rospy.loginfo("starting node")
00088     self._ser = None
00089     self.setup()
00090     self.move_lock = False
00091 
00092     self._as = actionlib.SimpleActionServer(FJT_ACTION_NAME, FollowJointTrajectoryAction, self.execute_cb, False)
00093     self._as.start()
00094     self._pub_joint_states = rospy.Publisher('joint_states', JointState,queue_size=1)
00095     self._pub_controller_state = rospy.Publisher('joint_trajectory_controller/state', JointTrajectoryControllerState,queue_size=1)
00096     # joint state
00097     self._joint_states = JointState()
00098     self._joint_states.name = rospy.get_param("~joint_names")
00099     self._joint_states.velocity = [0.0,0.0]
00100     self._joint_states.position = [0.0,0.0]
00101     self._joint_states.effort = [0.0,0.0]
00102     self._oldpos = [0.0, 0.0]
00103     # controller state
00104     self._controller_state = JointTrajectoryControllerState()
00105 
00106     self.pos = [0,0]
00107     self.command_pos = [0,0]
00108 
00109     rospy.Timer(rospy.Duration(0.1), self.publish_joint_states)
00110     rospy.Timer(rospy.Duration(10), self.intern_move)
00111     self.lock = False
00112 
00113   def setup(self):
00114     self.close_port()
00115     try:
00116       self._ser = serial.Serial(self.port, timeout=0.5)
00117       rospy.loginfo("Port is alive")
00118       self.set_pwm("min_pwm0")
00119       self.set_pwm("min_pwm1")
00120       self.set_pwm("max_pwm0")
00121       self.set_pwm("max_pwm1")
00122     except serial.serialutil.SerialException:
00123       self._ser = None
00124 
00125 
00126   def set_pwm(self, pwm_to_set):
00127     complement = " "+(str)(pwm_to_set)+" "+(str)(eval("self."+pwm_to_set))+Terminator
00128 
00129     self.execute_command("set_pwm", complement)
00130 
00131     status, reply = self.get_pwm(pwm_to_set)
00132 
00133     if(status and (int)(reply) ==(eval("self."+pwm_to_set))):
00134       status = True
00135     else:
00136       status = False
00137 
00138     return status, reply
00139 
00140   def get_pwm(self, pwm_to_get):
00141     complement = " "+(str)(pwm_to_get)+Terminator
00142 
00143     status, reply = self.execute_command("get_pwm", complement)
00144 
00145     while(status and reply and pwm_to_get not in reply):
00146       status, reply = self.execute_command("get_pwm", complement)
00147 
00148     if reply:
00149       reply = reply[reply.find(pwm_to_get)+len(pwm_to_get)+3:-1]
00150 
00151     return status, reply
00152 
00153   def get_pos(self):
00154     status,pos = self.execute_command("position")
00155 
00156     if(not pos==None):
00157       self.pos = pos
00158     return status, self.pos
00159 
00160   def stop(self):
00161     complement = " "+Terminator
00162     status,reply = self.execute_command("stop", complement)
00163 
00164     return status, reply
00165 
00166   def move(self,pos_0, pos_1):
00167     status = None
00168     reply = None
00169 
00170     if(not self.move_lock):
00171       self.move_lock = True
00172       complement = " "+(str)(pos_0)+","+(str)(pos_1)+Terminator
00173       #self.setup()
00174       status, reply = self.execute_command("move", complement)
00175       if status == False:
00176         rospy.logwarn("Trying to reconnect - calling setup()")
00177         self.setup()
00178       self.move_lock = False
00179       self._joint_states.position = [pos_0/100.0/180.0*math.pi, pos_1/100.0/180.0*math.pi]
00180     return status, reply
00181 
00182   def close_port(self):
00183     if self._ser:
00184       self._ser.close()
00185     self._ser = None
00186 
00187   def intern_move(self, event):
00188     self.move(self.command_pos[0], self.command_pos[1])
00189 
00190   def execute_cb(self, goal):
00191 
00192     position_proximal = goal.trajectory.points[-1].positions[0]
00193     position_distal = goal.trajectory.points[-1].positions[1]
00194 
00195     position_proximal = math.degrees(position_proximal)*100 # from radians to centidegrees
00196     position_distal = math.degrees(position_distal)*100
00197     self.command_pos = [position_proximal, position_distal]
00198     status, reply = self.move(position_proximal, position_distal)
00199 
00200     print "status", status
00201 
00202     if(status==True):
00203       self._as.set_succeeded()
00204     else:
00205       self._as.set_aborted()
00206 
00207   def publish_joint_states(self, event):
00208 
00209     self._joint_states.header.stamp = rospy.Time.now()
00210     self._pub_joint_states.publish(self._joint_states)
00211     self.publish_controller_state()
00212 
00213 
00214   def update_joint_states(self):
00215     return
00216     if(not self.lock):
00217       self.lock = True
00218       status, pos = self.get_pos()
00219 
00220       if status == True and (not pos==None):
00221         try:
00222           actual_pos_proximal = math.radians((float)(pos[0])/100)
00223           actual_pos_distal = math.radians((float)(pos[1])/100)
00224           self._joint_states.position = [actual_pos_proximal, actual_pos_distal]
00225         except ValueError:
00226           pass
00227 
00228       self.lock = False
00229 
00230 
00231   def publish_controller_state(self):
00232     self._controller_state.header.stamp = rospy.Time.now()
00233     self._controller_state.joint_names = self._joint_states.name
00234     self._controller_state.actual.positions = self._joint_states.position
00235     self._controller_state.actual.velocities = self._joint_states.velocity
00236     self._pub_controller_state.publish(self._controller_state)
00237 
00238   def execute_command(self, command, complement=Terminator, timeout=1.2):
00239 
00240     if not self._ser:
00241       rospy.logerr("Port is not ready")
00242       return (False,None)
00243 
00244     t_out = time.time() + timeout
00245 
00246     status,result = False,None
00247     try:
00248       self._ser.write(commands[command]+complement)
00249       line_to_parse = self._ser.readline()
00250 
00251       if(command == "position"):
00252 
00253         while True:
00254           if (time.time() > t_out):
00255             break
00256           elif("P=" not in line_to_parse[0:2]):
00257             self._ser.write(commands[command]+complement)
00258             line_to_parse = self._ser.readline()
00259           else:
00260             break
00261           rospy.sleep(0.01)
00262 
00263         line_to_parse = line_to_parse.replace('P=','')
00264         line_to_parse = line_to_parse.strip()
00265         line_to_parse = line_to_parse.split(',')
00266         result = line_to_parse
00267 
00268         if(len(result) !=2):
00269           status = False
00270         else:
00271           status=True
00272 
00273       elif(command=="stop"):
00274         rospy.loginfo("Stopping the movement")
00275         while True:
00276           if (time.time() > t_out):
00277             break
00278           elif("@Sto" not in line_to_parse):
00279             self._ser.write(commands[command]+complement)
00280             line_to_parse = self._ser.readline()
00281           else:
00282             rospy.loginfo("Movement stopped")
00283             result = True
00284             break
00285           rospy.sleep(0.01)
00286 
00287       elif(command=="set_pwm"):
00288         rospy.loginfo("Setting the PWM: "+complement)
00289 
00290       elif(command=="get_pwm"):
00291         result = line_to_parse
00292 
00293 
00294       elif(command == "move"):
00295 
00296         while True:
00297           if (time.time() > t_out):
00298             return False,None
00299           elif("@Mov" not in line_to_parse):
00300             self._ser.write(commands[command]+complement)
00301             line_to_parse = self._ser.readline()
00302           else:
00303             break
00304           rospy.sleep(0.01)
00305 
00306         result = line_to_parse
00307 
00308         status = True
00309 
00310       self._ser.flush()
00311     #except serial.serialutil.SerialException:
00312     #  pass
00313     #except OSError:
00314     #  pass
00315     #except TypeError:
00316     #  pass
00317     except Exception as e:
00318       rospy.logerr("Caught: " + str(e))
00319       status = False
00320       result = None
00321     return status, result
00322 
00323 
00324 if __name__ == '__main__':
00325   try:
00326     rospy.init_node('schunk_sdhx')
00327     sdhx = Sdhx()
00328     r = rospy.Rate(10)
00329     while not rospy.is_shutdown():
00330       sdhx.update_joint_states()
00331       r.sleep()
00332     sdhx.close_port()
00333   except serial.serialutil.SerialException:
00334     pass
00335   except OSError:
00336     pass
00337   except TypeError:
00338     pass
00339 


schunk_sdhx
Author(s): Thiago de Freitas
autogenerated on Wed Dec 14 2016 03:50:46