pressure_observer.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2008, Willow Garage, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the Willow Garage nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * \author Joe Romano
36  *********************************************************************/
37 //@author Joe Romano
38 //@email joeromano@gmail.com
39 //@brief pressure_observer.cpp
40 
42 
43 // method to be called each 1ms timestep in realtime to ensure data collection and manipulation happens properly
45 {
46  // update the sensor readings and perform actions if new data was aquired.
47  // this inner loop shuld run (become true) at the update rate of the pressure sensors (24.9 Hz)
49  {
50  // update our time values
53 
54  zero(); // zero out our data
55  bias_estimator(); // calculate filtered (bp,hp) force values
56  updateTotalLoading(); // update our total loading estimates
58  updateBrokenSensorStatus(); // update our flag to indicate a broken sensor
59 
61  }
62 
63 }
64 
65 
67 {
68  if(getPadForce(pressure_now.pressure_left) == 0 || getPadForce(pressure_now.pressure_left) == 0)
69  broken_sensor = true;
70  else
71  broken_sensor = false;
72 
73 }
74 
75 
76 // NOTE: remove bias and do for all? remove completely? try remove completely first.
77 // remove the mean for near-zero data at low frequencies
79 {
80  // position high-pass filter cutoff frequency
81  double poshp_fc = 5.0; // Hz
82  double poshp_lambda = 2*3.14159265*poshp_fc;
83  double dt = .041;
84 
85  // for all cells (only if we are not currently zeroing things out)
86  for( int i = 0; (i < 22); i ++)
87  {
88  pressure_prev_bias.pressure_left[i] = pressure_cur_bias.pressure_left[i];
89  pressure_prev_bias.pressure_right[i] = pressure_cur_bias.pressure_right[i];
90 
91  pressure_cur_bias.pressure_left[i] = ((1/(1+dt*poshp_lambda))*pressure_prev_bias.pressure_left[i]) + ((1/(1+dt*poshp_lambda))*(pressure_current_zerod.pressure_left[i]-pressure_prev_zerod.pressure_left[i]));
92  pressure_cur_bias.pressure_right[i] = ((1/(1+dt*poshp_lambda))*pressure_prev_bias.pressure_right[i]) + ((1/(1+dt*poshp_lambda))*(pressure_current_zerod.pressure_right[i]-pressure_prev_zerod.pressure_right[i]));
93 
94  // calculate our band-passed data
95  pressure_bp.pressure_left[i] = pressureLFFilt_left[i]->getNextFilteredValue(pressure_current_zerod.pressure_left[i]);
96  pressure_bp.pressure_right[i] = pressureLFFilt_right[i]->getNextFilteredValue(pressure_current_zerod.pressure_right[i]);
97 
99  }
100 }
101 
102 
104 {
105  if( checkSlip(dF,0.2) || placeContact )
106  placeContact = true;
107  else
108  placeContact = false;
109  return placeContact;
110 }
111 
112 
114 {
115  for(int i = 0; i < 7; i++)
116  {
117  // should really be 600 and 400 depending on sensor. heh.
118  if( (pressure_cur_bias.pressure_left[i]/500.0) > dF )
119  return i+1;
120  if( (pressure_cur_bias.pressure_right[i]/500.0) > dF )
121  return i+10;
122  }
123  return -1;
124 }
125 
126 
127 // method to watch pressure sensor transience during grasp and return true
128 // when both fingers saw a significant force transience
129 bool pressureObserver::graspContact(int contactsDesired)
130 {
131 
132  // if we are looking for both fingers to contact
133  if( contactsDesired == 0 && left_contact && right_contact)
134  return true;
135  // if looking for a single finger contact
136  else if( (contactsDesired == 1 && left_contact) || (contactsDesired == 2 && right_contact))
137  return true;
138  // if we are looking for any contact
139  else if( (contactsDesired ==3) && (left_contact || right_contact) )
140  return true;
141 
142  return false;
143 }
144 
145 
146 // method to update contact state of fingerpads
148 {
149  //float totalLoading_contactThresh = 3000.0/UNITS_PER_N; // was 3000 before unit change to N. Probably should be on param server
150 
152  left_contact = true;
153  else
154  left_contact = false;
155 
157  right_contact = true;
158  else
159  right_contact = false;
160 }
161 
162 
163 // method to update the toal loading of each finger PAD totalLoad_left _right
165 {
166  // store our previous forces on the fingerpads
169 
170  // get our new fingerpad forces
177 
178  // take the discrete derivative and absolute value to get the new total loading
183 
184  lfForce_left = getPadForce(pressure_bp.pressure_left);
185  lfForce_right = getPadForce(pressure_bp.pressure_right);
186 }
187 
188 
189 // method to take in a fingertip pressure vector and return the cumultive sum on the fingerpad (just the pad)
190 double pressureObserver::getPadForce(boost::array<double,22> pressureArray)
191 {
192  double tempLoading = 0.0;
193 
194  // sum the fingerpads to get the new total loading
195  for( int i = 7; i < 22; i ++)
196  {
197  tempLoading += pressureArray[i];
198  }
199 
200  return tempLoading/UNITS_PER_N;
201 
202 }
203 
204 
205 // method to update our zero value for each cell based on a low-pass filtered version of the no-load pressure signal
207 {
208  double
209  zero_weight = 0.6;
210  for( int i = 0; i < 22; i ++)
211  {
212  zero_offset.pressure_left[i] = ( ((1.0-zero_weight)*zero_offset.pressure_left[i]) + (zero_weight*pressure_current.pressure_left[i]) );
213  zero_offset.pressure_right[i] = ( ((1.0-zero_weight)*zero_offset.pressure_right[i]) + (zero_weight*pressure_current.pressure_right[i]) );
214  }
215 }
216 
217 
218 // method to zero out our data by modifying pressureState_current
220 {
221  // update our zero vector
222  for( int i = 0; i < 22; i ++)
223  {
224  pressure_prev_zerod.pressure_left[i] = pressure_current_zerod.pressure_left[i];
225  pressure_prev_zerod.pressure_right[i] = pressure_current_zerod.pressure_right[i];
226 
227  pressure_current_zerod.pressure_left[i] = pressure_current.pressure_left[i] - zero_offset.pressure_left[i];
228  pressure_current_zerod.pressure_right[i] = pressure_current.pressure_right[i] - zero_offset.pressure_right[i];
229  }
230 }
231 
232 
233 // method to acquire new data from both fingers and apply appropriate subsampling
234 // @return true if the data was updated (we took a subsample), false if no data update occured (repetitive data)
236 {
237 
238  bool newData = false;
239  bool updated = false;
240 
241  // grab new data from the left and right sensors
242  std::vector< uint16_t > pressureVector_left = left_finger->state_.data_;
243  std::vector< uint16_t > pressureVector_right = right_finger->state_.data_;
244  for( int i = 0; i < 22; i ++)
245  {
246  pressure_now.pressure_left[i] = (double)pressureVector_left[i];
247  pressure_now.pressure_right[i] = (double)pressureVector_right[i];
248 
249  // check if any values have changed, and if so set a flag
250  if(pressure_now.pressure_left[i] != pressure_current.pressure_left[i] || pressure_now.pressure_right[i] != pressure_current.pressure_right[i])
251  {
252  newData = true;
253  }
254  }
255 
256  // if we went over our 41st sample (the rate at which samples are updated) then update our stored values
257  // subSample_cnt >= 41 if too many samples happened
258  if( newData || subSample_cnt >= subSample_steps)
259  {
260 
261  for( int i = 0; i < 22; i ++)
262  {
263  // store the current value as previous
264  pressure_prev.pressure_left[i] = pressure_current.pressure_left[i];
265  pressure_prev.pressure_right[i] = pressure_current.pressure_right[i];
266 
267  // store the new value as current
268  pressure_current.pressure_left[i] = pressure_now.pressure_left[i];
269  pressure_current.pressure_right[i] = pressure_now.pressure_right[i];
270  }
271  // reset our sample counter to zero
272  subSample_cnt = 0;
273 
274  updated = true;
275  }
276 
277  // increment the subsample counter
278  subSample_cnt++;
279 
280  return updated;
281 }
282 
283 
284 void pressureObserver::getPadCentroid(boost::array<double,22> pressureArray, double *x, double *y)
285 {
286  // weights to multiply our cells on the fingerpad by to determine the x-y centroid
287  double y_weights[15] = {-1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1};
288  double x_weights[15] = {-1, -1, -1, -0.5, -0.5, -0.5, 0, 0, 0, 0.5, 0.5, 0.5, 1, 1, 1};
289 
290  *y = 0;
291  *x = 0;
292 
293  for(int i = 7; i < 22; i++)
294  {
295  *y += pressureArray[i]*y_weights[i-7];
296  *x += pressureArray[i]*x_weights[i-7];
297  }
298 
299  // divide the x and y by the sum of the pad
300  double pressureSum = getPadForce(pressureArray);
301  *y = *y/pressureSum;
302  *x = *x/pressureSum;
303 }
304 
306 {
307  double x_centroid_left, y_centroid_left, x_centroid_right, y_centroid_right;
308  getPadCentroid(pressure_current_zerod.pressure_left,&x_centroid_left,&y_centroid_left);
309  getPadCentroid(pressure_current_zerod.pressure_right,&x_centroid_right,&y_centroid_right);
310 
311 }
312 
313 
314 bool pressureObserver::checkSlip(double slip_motion_limit, double slip_force_limit)
315 {
316  double disturbance_left = std::min(std::max(slip_motion_limit*fabs(padForce_left_cur_nonbiased), .048),0.2);
317  double disturbance_right = std::min(std::max(slip_motion_limit*fabs(padForce_right_cur_nonbiased), .048),0.2);
318 
319  if( ( fabs(padForce_left_cur) > disturbance_left) && (fabs(lfForce_left) < slip_force_limit))
320  return true;
321  else if( ( fabs(padForce_right_cur) > disturbance_right) && (fabs(lfForce_right) < slip_force_limit))
322  return true;
323  else
324  return false;
325 }
326 
327 
328 // constructor
330 {
331  // store our pressure sensor state handles
332  left_finger = left;
333  right_finger = right;
334 
335  // initialize our subsample counter to 1
336  subSample_cnt = 1;
337 
338  // set our subsampling up to pick every 41st sample (since we sample at 1ms but the pressure array updates every 41ms)
339  subSample_steps = 41;
340 
341  // initialize our loading values to zero
342  padForce_left_cur = 0.0;
343  padForce_right_cur = 0.0;
344  padForce_left_prev = 0.0;
345  padForce_right_prev = 0.0;
346 
347  // initialize our time values
350  dt = 0.041;
351 
352  // intialize the right/left contact states
353  left_contact = false;
354  right_contact = false;
355 
356  // initialize our placement contact state
357  placeContact = false;
358 
359  // get some fresh data from the sensors
361 
362  // set all our zero_offset pressures to the first seen value
363  for( int i = 0; i < 22; i ++)
364  {
365  zero_offset.pressure_left[i] = pressure_now.pressure_left[i];
366  zero_offset.pressure_right[i] = pressure_now.pressure_right[i];
367  }
368 
369  // create our filter for low frequency pressure changes
370  // instatiate our digital filter
371  // 1st order chebychev. 0.8 to 5 hz bandpass. 0.5 r. (3 terms for chebychev?)
372  float b_vfilt[] = { 0.6323, 0, -0.6323};
373  float a_vfilt[] = {1.0, -0.6294, -0.2647};
374  for(int i=0; i < 22; i++)
375  {
376  pressureLFFilt_left[i] = new digitalFilter(1+1, true,b_vfilt,a_vfilt);
377  pressureLFFilt_right[i] = new digitalFilter(1+1, true,b_vfilt,a_vfilt);
378  }
379 }
380 
381 
382 // destructor
384 {
385  delete[] pressureLFFilt_left;
386  delete[] pressureLFFilt_right;
387 }
digitalFilter * pressureLFFilt_right[22]
pr2_hardware_interface::PressureSensor * right_finger
bool checkSlip(double slip_motion_limit=0.007, double slip_force_limit=0.18)
bool checkPlaceContact(double dF)
pr2_hardware_interface::PressureSensor * left_finger
double padForce_left_cur_nonbiased
bool graspContact(int contactsDesired)
#define UNITS_PER_N
void getPadCentroid(boost::array< double, 22 > pressureArray, double *x, double *y)
pr2_gripper_sensor_msgs::PR2GripperPressureData pressure_cur_bias
pr2_gripper_sensor_msgs::PR2GripperPressureData pressure_bp
pressureObserver(pr2_hardware_interface::PressureSensor *left, pr2_hardware_interface::PressureSensor *right)
pr2_gripper_sensor_msgs::PR2GripperPressureData pressure_current
float getNextFilteredValue(float u_current)
pr2_gripper_sensor_msgs::PR2GripperPressureData pressure_now
double getPadForce(boost::array< double, 22 > pressureArray)
pr2_gripper_sensor_msgs::PR2GripperPressureData zero_offset
pr2_gripper_sensor_msgs::PR2GripperPressureData pressure_current_zerod
pr2_gripper_sensor_msgs::PR2GripperPressureData pressure_prev_bias
pr2_gripper_sensor_msgs::PR2GripperPressureData pressure_prev_zerod
static Time now()
int checkSideImpact(double dF)
double padForce_right_cur_nonbiased
pr2_gripper_sensor_msgs::PR2GripperPressureData pressure_prev
digitalFilter * pressureLFFilt_left[22]


pr2_gripper_sensor_controller
Author(s): Joe Romano
autogenerated on Wed Apr 1 2020 03:58:23