UndercarriageCtrlGeom.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
19 
20 #include <math.h>
21 #include <angles/angles.h>
22 #include <stdexcept>
23 #include <boost/shared_ptr.hpp>
24 
25 
26 namespace MathSup {
27  const double PI = 3.14159265358979323846;
28  void normalizePi(double &val) { val = angles::normalize_angle(val); }
29 
30  double atan4quad(double y, double x)
31  {
32  if((x==0.0) && (y==0.0)) return 0; // special case (?)
33  return atan2(y,x);
34  }
35 }
36 
37 double getWeightedDelta(double current_position, double old_target, double new_target){
38  // current_position = angles::normalize_angle(current_position); not needed if current Pos is alread normalized
39 
40  // Calculate differences between current config to possible set-points
41  double dtempDeltaPhi1RAD = angles::normalize_angle( new_target - current_position );
42  double dtempDeltaPhiCmd1RAD = angles::normalize_angle(new_target - old_target);
43 
44  // determine optimal setpoint value
45  // 1st which set point is closest to current cinfog
46  // but: avoid permanent switching (if next target is about PI/2 from current config)
47  // 2nd which set point is closest to last set point
48  // "fitness criteria" to choose optimal set point:
49  // calculate accumulted (+ weighted) difference between targets, current config. and last command
50  return 0.6*fabs(dtempDeltaPhi1RAD) + 0.4*fabs(dtempDeltaPhiCmd1RAD);
51 }
52 
54  state_ = state;
55 
56  // calculate current geometry of robot (exact wheel position, taking into account steering offset of wheels)
57  m_dExWheelXPosMM = geom_.dWheelXPosMM + geom_.dDistSteerAxisToDriveWheelMM * sin(state_.dAngGearSteerRad);
58  m_dExWheelYPosMM = geom_.dWheelYPosMM - geom_.dDistSteerAxisToDriveWheelMM * cos(state_.dAngGearSteerRad);
59 
60  // calculate distance from platform center to wheel center
61  m_dExWheelDistMM = sqrt( (m_dExWheelXPosMM * m_dExWheelXPosMM) + (m_dExWheelYPosMM * m_dExWheelYPosMM) );
62 
63  // calculate direction of rotational vector
64  m_dExWheelAngRad = MathSup::atan4quad( m_dExWheelYPosMM, m_dExWheelXPosMM);
65 
66  m_dVelWheelMMS = geom_.dRadiusWheelMM * (state_.dVelGearDriveRadS - dFactorVel* state_.dVelGearSteerRadS);
67 }
68 
69 double WheelData::mergeRotRobRadS(const WheelData &wheel1, const WheelData &wheel2){
70  // calc Parameters (Dist,Phi) of virtual linking axis of the two considered wheels
71  double dtempDiffXMM = wheel2.m_dExWheelXPosMM - wheel1.m_dExWheelXPosMM;
72  double dtempDiffYMM = wheel2.m_dExWheelYPosMM - wheel1.m_dExWheelYPosMM;
73 
74  double dtempRelDistWheelsMM = sqrt( dtempDiffXMM*dtempDiffXMM + dtempDiffYMM*dtempDiffYMM );
75  double dtempRelPhiWheelsRAD = MathSup::atan4quad( dtempDiffYMM, dtempDiffXMM );
76 
77  // transform velocity of wheels into relative coordinate frame of linking axes -> subtract angles
78  double dtempRelPhiWheel1RAD = wheel1.state_.dAngGearSteerRad - dtempRelPhiWheelsRAD;
79  double dtempRelPhiWheel2RAD = wheel2.state_.dAngGearSteerRad - dtempRelPhiWheelsRAD;
80 
81  return (wheel2.m_dVelWheelMMS * sin(dtempRelPhiWheel2RAD) - wheel1.m_dVelWheelMMS * sin(dtempRelPhiWheel1RAD))/dtempRelDistWheelsMM;
82 }
83 
84 double WheelData::getVelX() const {
85  return m_dVelWheelMMS*cos(state_.dAngGearSteerRad);
86 }
87 double WheelData::getVelY() const {
88  return m_dVelWheelMMS*sin(state_.dAngGearSteerRad);
89 }
90 UndercarriageGeom::UndercarriageGeom(const std::vector<WheelParams> &params){
91  for(std::vector<WheelParams>::const_iterator it = params.begin(); it != params.end(); ++it){
92  wheels_.push_back(boost::make_shared<WheelData>(it->geom));
93  }
94 }
95 
97  UndercarriageGeomBase::calcDirect(state, wheels_);
98 }
99 
100 void UndercarriageGeom::updateWheelStates(const std::vector<WheelState> &states){
102 }
103 
104 void CtrlData::setTarget(const PlatformState &plt_state){
105  // check if zero movement commanded -> keep orientation of wheels, set wheel velocity to zero
106  if((plt_state.dVelLongMMS == 0) && (plt_state.dVelLatMMS == 0) && (plt_state.dRotRobRadS == 0))
107  {
108  m_dVelGearDriveTargetRadS = 0.0;
109  m_dAngGearSteerTargetRad = state_.dAngGearSteerRad;
110  return;
111  }
112 
113  // calculate velocity and direction of single wheel motion
114  // Translational Portion
115  double dtempAxVelXRobMMS = plt_state.dVelLongMMS;
116  double dtempAxVelYRobMMS = plt_state.dVelLatMMS;
117  // Rotational Portion
118  dtempAxVelXRobMMS += plt_state.dRotRobRadS * m_dExWheelDistMM * -sin(m_dExWheelAngRad);
119  dtempAxVelYRobMMS += plt_state.dRotRobRadS * m_dExWheelDistMM * cos(m_dExWheelAngRad);
120 
121  // calculate resulting steering angle
122  // Wheel has to move in direction of resulting velocity vector of steering axis
123  double dAngGearSteerTarget1Rad = MathSup::atan4quad(dtempAxVelYRobMMS, dtempAxVelXRobMMS);
124  // calculate corresponding angle in opposite direction (+180 degree)
125  double dAngGearSteerTarget2Rad = dAngGearSteerTarget1Rad + MathSup::PI;
126  MathSup::normalizePi(dAngGearSteerTarget2Rad);
127 
128  // calculate absolute value of rotational rate of driving wheels in rad/s
129  double dVelGearDriveTarget1RadS = sqrt( (dtempAxVelXRobMMS * dtempAxVelXRobMMS) +
130  (dtempAxVelYRobMMS * dtempAxVelYRobMMS) ) / geom_.dRadiusWheelMM;
131  // now adapt to direction (forward/backward) of wheel
132  double dVelGearDriveTarget2RadS = -dVelGearDriveTarget1RadS;
133 
134 
135  if(getWeightedDelta(state_.dAngGearSteerRad, m_dAngGearSteerTargetRad, dAngGearSteerTarget1Rad)
136  <= getWeightedDelta(state_.dAngGearSteerRad, m_dAngGearSteerTargetRad, dAngGearSteerTarget2Rad))
137  {
138  // Target1 is "optimal"
139  m_dVelGearDriveTargetRadS = dVelGearDriveTarget1RadS;
140  m_dAngGearSteerTargetRad = dAngGearSteerTarget1Rad;
141  }
142  else
143  {
144  // Target2 is "optimal"
145  m_dVelGearDriveTargetRadS = dVelGearDriveTarget2RadS;
146  m_dAngGearSteerTargetRad = dAngGearSteerTarget2Rad;
147  }
148 
149 }
150 
151 double limitValue(double value, double limit){
152  if(limit != 0){
153  if (value > limit){
154  value = limit;
155  } else if (value < -limit) {
156  value = -limit;
157  }
158  }
159  return value;
160 }
161 
162 void CtrlData::calcControlStep(WheelCommand &command, double dCmdRateS, bool reset){
163  if(reset){
164  this->reset();
165  command.dVelGearDriveRadS = 0.0;
166  command.dVelGearSteerRadS = 0.0;
167  command.dAngGearSteerRad = state_.dAngGearSteerRad;
168  command.dAngGearSteerRadDelta = 0.0;
169  return;
170  }
171 
172  // Normalize Actual Wheel Position before calculation
173  double dCurrentPosWheelRAD = angles::normalize_angle(state_.dAngGearSteerRad);
174  command.dAngGearSteerRadDelta = angles::normalize_angle(m_dAngGearSteerTargetRad - dCurrentPosWheelRAD);
175 
176  // set outputs
177  command.dVelGearDriveRadS = limitValue(m_dVelGearDriveTargetRadS + m_dAngGearSteerTargetRad * dFactorVel, params_.dMaxDriveRateRadpS);
178 
179  // provisorial --> skip interpolation and always take Target
180  command.dAngGearSteerRad = m_dAngGearSteerTargetRad;
181 }
182 
183 void PosCtrlData::calcControlStep(WheelCommand &command, double dCmdRateS, bool reset){
184  CtrlData::calcControlStep(command, dCmdRateS, reset);
185  if(!reset){
186  // Impedance-Ctrl
187  // Calculate resulting desired forces, velocities
188  // double dForceDamp, dForceProp, dAccCmd, dVelCmdInt;
189  double dForceDamp = - pos_params_.dDamp *m_dCtrlVelCmdInt;
190  double dForceProp = pos_params_.dSpring * command.dAngGearSteerRadDelta;
191 
192  double dAccCmd = (dForceDamp + dForceProp) / pos_params_.dVirtM;
193  dAccCmd = limitValue(dAccCmd, pos_params_.dDDPhiMax);
194 
195  double dVelCmdInt =m_dCtrlVelCmdInt + dCmdRateS * dAccCmd;
196  dVelCmdInt = limitValue(dVelCmdInt, pos_params_.dDPhiMax);
197 
198  // Store internal ctrlr-states
199  m_dCtrlVelCmdInt = dVelCmdInt;
200 
201  // set outputs
202  command.dVelGearSteerRadS = limitValue(dVelCmdInt, params_.dMaxSteerRateRadpS);
203  }
204 }
206 }
208  m_dCtrlVelCmdInt = 0.0;
209 }
210 
211 void UndercarriageCtrl::configure(const std::vector<PosCtrlParams> &pos_ctrls){
212  assert(wheels_.size() == pos_ctrls.size());
213  for(size_t i = 0; i < wheels_.size(); ++i){
214  wheels_[i]->pos_params_ = pos_ctrls[i];
215  }
216 }
double limitValue(double value, double limit)
double atan4quad(double y, double x)
static double mergeRotRobRadS(const WheelData &wheel1, const WheelData &wheel2)
void setTarget(const PlatformState &state)
void configure(const std::vector< PosCtrlParams > &pos_ctrl)
double getVelX() const
virtual void calcControlStep(WheelCommand &command, double dCmdRateS, bool reset)
void updateState(const WheelState &state)
double getWeightedDelta(double current_position, double old_target, double new_target)
UndercarriageGeom(const std::vector< WheelParams > &params)
WheelState state_
virtual void reset()
def normalize_angle(angle)
virtual void reset()
const double PI
void normalizePi(double &val)
virtual void calcDirect(PlatformState &state) const
double getVelY() const
virtual void updateWheelStates(const std::vector< WheelState > &states)=0
virtual void calcControlStep(WheelCommand &command, double dCmdRateS, bool reset)
virtual void calcDirect(PlatformState &state) const =0
virtual void updateWheelStates(const std::vector< WheelState > &states)


cob_omni_drive_controller
Author(s): Christian Connette, Mathias Lüdtke
autogenerated on Thu Apr 8 2021 02:39:52