node.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 import pdb
4 import rospy
5 import math
6 from sensor_msgs.msg import *
7 from std_msgs.msg import String
8 from std_msgs.msg import Float64
9 from std_msgs.msg import Empty
10 from geometry_msgs.msg import *
11 from geometry_msgs.msg import Twist
12 import numpy as np
13 from numpy.linalg import inv
14 import lp_filter as lp
15 import med_filter as mdf
16 import pdb
17 #TODO:
18 #- some basic commands like reset position and so on
19 # test if control works
20 # add arm position calibration in this script for J1 and J2. see embedded code for manual setting via ros message.
21 
22 
24 
25  def __init__(self, isleft = True):
26  self.sync_time = 1.0/10.0
27  self.Hz = 50.0
28  self.rate = rospy.Rate(self.Hz)
29  self.isleft = isleft
30  self.G_RATIO1 = 12.18
31  self.G_RATIO2 = 12.18
32  self.joint2_limit = 1.25
33  self.speed_limit_J1 = 0.5
34  self.speed_limit_J2 = 0.5
35  self.last_sync = rospy.get_time()
36 
37  self.st = 'left'
38 
39  if self.isleft:
40  self.st = 'left'
41  else:
42  self.st = 'right'
43 
44  #Publisher
45  self.pubMcmd_Arm = rospy.Publisher('/quori/arm_' + self.st + '/cmd_pos_dir', Vector3, queue_size=1)
46  # x: Motor position command in radians. This command is meant for the outer motor in the port nearest to the USB.
47  # y: Motor position command in radians. This command is meant for the inner motor in the port away from the USB.
48  # z: varible that can be used for timeing. Sending -1 leads to a coast command
49  self.pubJointState = rospy.Publisher('/quori/arm_' + self.st + '/shoulder_pos', Vector3, queue_size=1)
50  # x: Joint position in radians. This is meant to represent the circumduction motion and is refered to as J1. The sensor should be pluged into the port furtherest from the USB port on the microcontroller.
51  # y: Joint position in radians. This is meant to represent the addduction and abduction motion and is refered to as J2. The sensor should be pluged into the port nearest to the USB port on the microcontroller.
52  # z: unused
53  self.pubJointSpeed = rospy.Publisher('/quori/arm_' + self.st + '/shoulder_speed', Vector3, queue_size=1)
54 
55 
56 
57  #state
58  self.mode = 0 # mode of operation. 0: coast, 1: allow motion
59 
60  self.J1nWraps = 0
61 
62  self.arm_callibration_offset1 = 0.0 #TODO: create a way to set this via the parameter server
63  self.arm_callibration_offset2 = -0.0 #TODO: create a way to set this via the parameter server
64 
65 
66 
67  self.motor_cmd = Vector3() #motor commands loaded to this
68  self.ArmMsg = Vector3() #arm goal positions loaded to this
69  self.pubJointState_msg = Vector3() #arm updated position considering wrapping
78 
79  self.motorDriftSync.x = 0.0
80  self.motorDriftSync.y = 0.0
81  self.armJointPos_sync.x = 0.0
82  self.armJointPos_sync.y = 0.0
83 
84 
85  self.armJointPosRawmeas.x = 0.0
86  self.armJointPosRawmeas.y = 0.0
87  self.armJointPosRawmeasPrev.x = 0.0
88  self.armJointPosmeas.x = 0.0
89  self.armJointPosmeas.y = 0.0
90  self.last_pubJointState_msg.x = 0.0
91  self.last_pubJointState_msg.y = 0.0
92 
93  self.lp_filterx = lp.lp_filter()
94  self.lp_filterx.set_const(0.175) # between 0.25 and 0.1
95  self.lp_filtery = lp.lp_filter()
96  self.lp_filtery.set_const(0.175)
97  self.med_filtery = mdf.med_filter(3)
99  self.arm_sensor_inited = False
100  self.arm_motor_inited = False
101  self.arm_motor_updated = [False, False]
102  self.arm_joint_updated = [False, False]
103  self.rollOverUB = 3.0
104  self.rollOverLB = -3.0
105  self.joint2_LB = 0.7
106 
107  # Value greater than which sensor reading is considered garbage and is rejected
108  self.y_joint_unreasnable_lim = 1.6 #1.4 or 1.5 are also not feasible with panels on
109 
110 
111  def subscribe2topics(self):
112  #Subscriber
113  rospy.Subscriber('/quori/arm_' + self.st + '/pos_status',Vector3,self.armJ_callback)
114  # x: Raw Joint position in radians. This is meant to represent the circumduction motion and is refered to as J1. The sensor should be pluged into the port furtherest from the USB port on the microcontroller.
115  # y: Raw Joint position in radians. This is meant to represent the addduction and abduction motion and is refered to as J2. The sensor should be pluged into the port nearest to the USB port on the microcontroller.
116  # z: unused.
117  rospy.Subscriber('/quori/arm_' + self.st + '/motor_status',Vector3,self.armM_callback)
118  # x: Motor position in radians. This is read from the microcontroller and is meant to describe the outer motor and is refered to as M1. The outer motor is the one plugged into the port near tothe USB.
119  # y: Motor position in radians. This is read from the microcontroller and is meant to describe the inner motorand is refered to as M2. The inner motor is the one plugged into the port away from the USB.
120  # z: unused
121  rospy.Subscriber('/quori/arm_' + self.st + '/joint_goal',Vector3,self.goal_callback) #TODO create a script that publishes this information
122 
123 
124  def goal_callback(self,data):
125 
126  if data.z <0.0:
127  self.mode = 0
128  self.coast_msg()
129  else:
130  self.ArmMsg.x = data.x
131  self.ArmMsg.y = data.y
132  self.ArmMsg.z = data.z
133  self.limit_check() #adjust input if nessesary
134  self.mode = 1
135 
136  #rospy.loginfo('goal received')
137 
138 
139 
140  def armJ_callback(self,msg):
141  #shift by a potential offset due to hardware chage. This can also be done in the embedded code.
142  self.armJointPosRawmeas.x = msg.x
143  self.armJointPosRawmeas.y = msg.y
144 
145  # Filter impossible readings in y sensor of left arm
146  previous_value = self.armJointPosmeas.y
147  error_speed = abs(self.armJointPosRawmeas.y-previous_value)
148  if abs(self.armJointPosRawmeas.y) > self.y_joint_unreasnable_lim:
149  self.armJointPosmeas.y = self.armJointPosmeas.y
150  rospy.logwarn('error-reasonable value received for y:'+self.st)
151  elif error_speed>self.position_error_limit:
152  if self.arm_sensor_inited:
153  self.armJointPosmeas.y = self.armJointPosmeas.y
154  rospy.logwarn('error-reasonable speed sensed for y:'+self.st)
155  else: #assume the arm just turned on and the data is useful
156  self.armJointPosmeas.y = self.armJointPosRawmeas.y
157  else: #probably good data
158  if not self.med_filtery.inited:
159  self.med_filtery.init_filter(self.armJointPosRawmeas.y)
160  self.armJointPosmeas.y = self.med_filtery.ComputeFrmNew(self.armJointPosRawmeas.y)
161 
162  self.handle_J1_wrap()
163 
164  self.pubJointState_msg.x = self.armJointPosmeas.x
165  self.pubJointState_msg.y = self.armJointPosmeas.y
166 
167  self.pubJointSpeed_msg.x = (self.last_pubJointState_msg.x - self.armJointPosmeas.x)*self.Hz
168  self.pubJointSpeed_msg.y = (self.last_pubJointState_msg.y - self.armJointPosmeas.y)*self.Hz
171  if not self.arm_sensor_inited:
172  self.arm_sensor_inited = True
173  self.sync_pos()
174  rospy.loginfo('arm sensor read. init arm J')
175 
176 
177  def armM_callback(self,msg):
178  if msg.z == 3.0:
179  self.armMotorPosmeas.x = msg.x
180  self.arm_motor_updated[0] = True
181  self.armMotorPosmeas.y = msg.y
182  self.arm_motor_updated[1] = True
183  elif msg.z == 2.0:
184  self.armMotorPosmeas.y = msg.y
185  self.arm_motor_updated[0] = False
186  self.arm_motor_updated[1] = True
187  elif msg.z == 1.0:
188  self.armMotorPosmeas.x = msg.x
189  self.arm_motor_updated[0] = True
190  self.arm_motor_updated[1] = False
191  else:
192  self.arm_motor_updated[0] = False
193  self.arm_motor_updated[1] = False
194 
195  if not self.arm_motor_inited and msg.z == 3.0:
196  self.arm_motor_inited = True
197  self.sync_pos()
198  rospy.loginfo('motors sensed on.')
199  if not self.lp_filterx.inited and not self.lp_filtery.inited:
200  self.lp_filterx.init_filter(msg.x)
201  self.lp_filtery.init_filter(msg.y)
202  rospy.loginfo("inited arm motor pos filter")
203  rospy.loginfo(self.st + ":"+ str(self.lp_filterx.old))
204  rospy.loginfo(self.st + ":" + str(self.lp_filterx.new))
205 
206  def coast_msg(self):
207  self.motor_cmd.x = self.motor_cmd.x #just give it the last recieved command to preserve it.
208  self.motor_cmd.y = self.motor_cmd.y
209  self.motor_cmd.z = -1.0
210 
211  def limit_check(self):
212  #protect the arms from moving too fast
213  #change so the vector direction is preserved but scaled by the fastest desired speed
214  # speed modification is desabled in this version of the code.
215 
216  if abs(self.armJointPosmeas.x-self.ArmMsg.x)>self.speed_limit_J1:
217  #self.ArmMsg.x = self.armJointPosmeas.x+self.speed_limit_J1*math.copysign(1, (self.ArmMsg.x-self.armJointPosmeas.x))
218  rospy.logwarn('Joint speed limit x for ' +self.st + ' reached')
219  else:
220  self.ArmMsg.x = self.ArmMsg.x
221  if abs(self.armJointPosmeas.y-self.ArmMsg.y)>self.speed_limit_J2:
222  #self.ArmMsg.y = self.armJointPosmeas.y+self.speed_limit_J2*math.copysign(1, (self.ArmMsg.y-self.armJointPosmeas.y))
223  rospy.logwarn('Joint speed limit y for ' + self.st + ' reached')
224  else:
225  self.ArmMsg.y = self.ArmMsg.y
226 
227 
228  #TODO: protect the motors from moving too fast
229 
230 
231  #protect joint 2
232  if not self.isleft and (self.ArmMsg.y > self.joint2_limit):
233  self.ArmMsg.y = self.joint2_limit
234  #rospy.logwarn('Joint limit for ' + self.st + ' reached')
235  elif self.isleft and (self.ArmMsg.y < -self.joint2_limit):
236  self.ArmMsg.y = -self.joint2_limit
237  #rospy.logwarn('Joint limit for ' + self.st + ' reached'
238 
240  if self.arm_sensor_inited and self.arm_motor_inited:
241  diff_x = self.ArmMsg.x-self.armJointPos_sync.x
242  diff_y = self.ArmMsg.y-self.armJointPos_sync.y
243  self.motor_cmd.z = 1.0/self.Hz
244  self.motor_cmd.x = self.G_RATIO1 * (diff_x + diff_y)+self.motorDriftSync.x
245  #print 'pre: '
246  #print self.motor_cmd.x
247  #pdb.set_trace()
248  #rospy.logwarn("arm warn test")
249  self.motor_cmd.y = self.G_RATIO2 * (diff_x - diff_y)+self.motorDriftSync.y
250  if self.lp_filterx.inited and self.lp_filtery.inited:
251  #rospy.logwarn("filtering")
252  # print "filtering"
253  self.lp_filterx.set_new(self.motor_cmd.x)
254  self.lp_filtery.set_new(self.motor_cmd.y)
255  self.motor_cmd.x = self.lp_filterx.FilterCompute()
256  self.motor_cmd.y = self.lp_filtery.FilterCompute()
257  else:
258  self.mode = 0 #send coast until we get all the data we need
259  self.motor_cmd.z = -1 #send coast until we get all the data we need
260  #print 'waiting to get data'
261  #rospy.logwarn("arm not init_ Sending coast")
262 
263 
264 
265  def sync_pos(self):
266  self.motorDriftSync.x = self.armMotorPosmeas.x
267  self.motorDriftSync.y = self.armMotorPosmeas.y
268 
269  self.armJointPos_sync.x = self.armJointPosmeas.x
270  self.armJointPos_sync.y = self.armJointPosmeas.y
271 
272 
273  def handle_J1_wrap(self):
274  #if wrap detected increment number of wraps then add measurement to it. if
275  diff = self.armJointPosRawmeas.x-self.armJointPosRawmeasPrev.x
276  if abs(diff)> math.pi:
277  if diff < 0:
278  self.J1nWraps = self.J1nWraps + 1
279  elif diff >= 0:
280  self.J1nWraps = self.J1nWraps - 1
281  #add wraps if needed
282  if self.J1nWraps ==1:
283  self.armJointPosmeas.x = math.pi+(math.pi+self.armJointPosRawmeas.x)
284  elif self.J1nWraps ==-1:
285  self.armJointPosmeas.x = -math.pi-(math.pi-self.armJointPosRawmeas.x)
286  elif self.J1nWraps >1:
287  self.armJointPosmeas.x = math.pi+(self.J1nWraps-1)*math.pi*2.0+(math.pi+self.armJointPosRawmeas.x)
288  elif self.J1nWraps <-1:
289  self.armJointPosmeas.x = -math.pi+(self.J1nWraps+1)*math.pi*2.0-(math.pi-self.armJointPosRawmeas.x)
290  elif self.J1nWraps == 0:
291  self.armJointPosmeas.x = self.armJointPosRawmeas.x
293 
294 
295 if __name__ == '__main__':
296  rospy.init_node('Arm_Controller_node')
297  rospy.loginfo('Arm Controller node started')
298  controller_right = arm_controller(0)# change to 0 later
299  controller_left = arm_controller(1)
300  controller_right.subscribe2topics()
301  controller_left.subscribe2topics()
302  #Sync before testing
303  #controller.sync_pos()
304 
305  while not rospy.is_shutdown():
306  #Right Arm
307  if controller_right.mode == 1:
308  controller_right.setMotorGoalFromArm()
309  elif controller_right.mode == 0:
310  #coast
311  controller_right.coast_msg()
312  # Left Arm
313  if controller_left.mode == 1:
314  controller_left.setMotorGoalFromArm()
315  elif controller_left.mode == 0:
316  #coast
317  controller_left.coast_msg()
318  #publish commands
319 
320  controller_left.pubMcmd_Arm.publish(controller_left.motor_cmd)
321  controller_left.pubJointState.publish(controller_left.pubJointState_msg)#TODO. change to ROS joint state message
322  controller_left.pubJointSpeed.publish(controller_left.pubJointSpeed_msg)
323 
324  #publish commands
325  controller_right.pubMcmd_Arm.publish(controller_right.motor_cmd)
326  controller_right.pubJointState.publish(controller_right.pubJointState_msg)#TODO. change to ROS joint state message
327  controller_right.pubJointSpeed.publish(controller_right.pubJointSpeed_msg)
328 
329  if (rospy.get_time()-controller_right.last_sync)>controller_right.sync_time and 1:
330  controller_right.sync_pos()
331  controller_left.sync_pos()
332  controller_right.last_sync = rospy.get_time()
333  controller_right.rate.sleep()
node.arm_controller.goal_callback
def goal_callback(self, data)
Definition: node.py:124
node.arm_controller.lp_filterx
lp_filterx
Definition: node.py:93
node.arm_controller.sync_pos
def sync_pos(self)
Definition: node.py:265
node.arm_controller.G_RATIO1
G_RATIO1
Definition: node.py:30
node.arm_controller.motor_cmd
motor_cmd
Definition: node.py:67
node.arm_controller.J1nWraps
J1nWraps
Definition: node.py:60
node.arm_controller.med_filtery
med_filtery
Definition: node.py:97
node.arm_controller.lp_filtery
lp_filtery
Definition: node.py:95
node.arm_controller.isleft
isleft
Definition: node.py:29
node.arm_controller.position_error_limit
position_error_limit
Definition: node.py:98
msg
node.arm_controller.rollOverLB
rollOverLB
Definition: node.py:104
node.arm_controller.y_joint_unreasnable_lim
y_joint_unreasnable_lim
Definition: node.py:108
node.arm_controller.pubMcmd_Arm
pubMcmd_Arm
Definition: node.py:45
node.arm_controller.pubJointState_msg
pubJointState_msg
Definition: node.py:69
node.arm_controller.armM_callback
def armM_callback(self, msg)
Definition: node.py:177
node.arm_controller.G_RATIO2
G_RATIO2
Definition: node.py:31
node.arm_controller.motorDriftSync
motorDriftSync
Definition: node.py:77
node.arm_controller.last_pubJointState_msg
last_pubJointState_msg
Definition: node.py:76
node.arm_controller.joint2_limit
joint2_limit
Definition: node.py:32
node.arm_controller.last_sync
last_sync
Definition: node.py:35
node.arm_controller.speed_limit_J2
speed_limit_J2
Definition: node.py:34
node.arm_controller
Definition: node.py:23
node.arm_controller.joint2_LB
joint2_LB
Definition: node.py:105
node.arm_controller.arm_joint_updated
arm_joint_updated
Definition: node.py:102
node.arm_controller.__init__
def __init__(self, isleft=True)
Definition: node.py:25
node.arm_controller.arm_callibration_offset1
arm_callibration_offset1
Definition: node.py:62
node.arm_controller.armJointPosmeas
armJointPosmeas
Definition: node.py:72
node.arm_controller.ArmMsg
ArmMsg
Definition: node.py:68
node.arm_controller.armMotorPosmeas
armMotorPosmeas
Definition: node.py:71
node.arm_controller.pubJointState
pubJointState
Definition: node.py:49
node.arm_controller.armJointPos_sync
armJointPos_sync
Definition: node.py:74
node.arm_controller.rollOverUB
rollOverUB
Definition: node.py:103
node.arm_controller.mode
mode
Definition: node.py:58
node.arm_controller.Hz
Hz
Definition: node.py:27
node.arm_controller.arm_motor_inited
arm_motor_inited
Definition: node.py:100
node.arm_controller.subscribe2topics
def subscribe2topics(self)
Definition: node.py:111
node.arm_controller.pubJointSpeed_msg
pubJointSpeed_msg
Definition: node.py:70
node.arm_controller.sync_time
sync_time
Definition: node.py:26
node.arm_controller.armJointPosRawmeasPrev
armJointPosRawmeasPrev
Definition: node.py:75
node.arm_controller.pubJointSpeed
pubJointSpeed
Definition: node.py:53
node.arm_controller.arm_sensor_inited
arm_sensor_inited
Definition: node.py:99
node.arm_controller.handle_J1_wrap
def handle_J1_wrap(self)
Definition: node.py:273
node.arm_controller.armJointPosRawmeas
armJointPosRawmeas
Definition: node.py:73
node.arm_controller.coast_msg
def coast_msg(self)
Definition: node.py:206
node.arm_controller.arm_callibration_offset2
arm_callibration_offset2
Definition: node.py:63
node.arm_controller.rate
rate
Definition: node.py:28
node.arm_controller.speed_limit_J1
speed_limit_J1
Definition: node.py:33
node.arm_controller.armJ_callback
def armJ_callback(self, msg)
Definition: node.py:140
node.arm_controller.limit_check
def limit_check(self)
Definition: node.py:211
node.arm_controller.st
st
Definition: node.py:37
node.arm_controller.Vector3
Vector3
Definition: node.py:49
node.arm_controller.setMotorGoalFromArm
def setMotorGoalFromArm(self)
Definition: node.py:239
msg
node.arm_controller.arm_motor_updated
arm_motor_updated
Definition: node.py:101


quori_arm_controller
Author(s):
autogenerated on Wed Mar 2 2022 00:53:14