00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <vamos/body/Tire.h>
00022 #include <vamos/geometry/Conversions.h>
00023
00024 #include <algorithm>
00025 #include <cassert>
00026 #include <cmath>
00027 #include <iostream>
00028
00029 using namespace Vamos_Geometry;
00030
00031 #define MINSLIP 1.0e-4
00032
00033
00034
00035
00036
00037 Vamos_Body::
00038 Tire_Friction::Tire_Friction (const std::vector <double>& long_parameters,
00039 const std::vector <double>& trans_parameters,
00040 const std::vector <double>& align_parameters) :
00041 m_longitudital_parameters (long_parameters),
00042 m_transverse_parameters (trans_parameters),
00043 m_aligning_parameters (align_parameters),
00044 m_slide (0.0)
00045 {
00046 assert (m_longitudital_parameters.size () == 11);
00047 assert (m_transverse_parameters.size () == 15);
00048 assert (m_aligning_parameters.size () == 18);
00049 }
00050
00051 double Vamos_Body::Tire_Friction::Pacejka_Fx(double sigma, double Fz, double friction_factor)
00052 {
00053
00054
00055
00056 const std::vector <double>& b = m_longitudital_parameters;
00057
00058
00059
00060
00061
00062
00063
00064 double D = (b[1]*Fz + b[2])*Fz*friction_factor;
00065 double B = (b[3]*Fz+b[4])*exp(-b[5]*Fz)/(b[0]*(b[1]*Fz+b[2]));
00066 double E = (b[6]*Fz*Fz+b[7]*Fz+b[8]);
00067 double S = (100*sigma + b[9]*Fz+b[10]);
00068 double Fx = D*sin(b[0] * atan(S*B+E*(atan(S*B)-S*B)));
00069 return Fx;
00070 }
00071
00072 double Vamos_Body::Tire_Friction::Pacejka_Fy(double alpha, double Fz, double gamma, double friction_factor)
00073 {
00074
00075
00076 const std::vector <double>& a = m_transverse_parameters;
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 double D = (a[1]*Fz+a[2])*Fz*friction_factor;
00088 double B = a[3]*sin(2.0*atan(Fz/a[4]))*(1.0-a[5]*std::abs(gamma))/(a[0]*(a[1]*Fz+a[2])*Fz);
00089 double E = a[6]*Fz+a[7];
00090 double S = alpha + a[8]*gamma+a[9]*Fz+a[10];
00091
00092
00093 double Fy = D*sin(a[0]*atan(S*B+E*(atan(S*B)-S*B)));
00094 return Fy;
00095 }
00096
00097 double Vamos_Body::Tire_Friction::Pacejka_Mz(double sigma, double alpha, double Fz, double gamma, double friction_factor)
00098 {
00099 const std::vector <double>& c = m_aligning_parameters;
00100
00101 double D = (c[1]*Fz+c[2])*Fz*friction_factor;
00102 double B = (c[3]*Fz*Fz+c[4]*Fz)*(1.0-c[6]*std::abs(gamma))*exp(-c[5]*Fz)/(c[0]*D);
00103 double E = (c[7]*Fz*Fz+c[8]*Fz+c[9])*(1.0-c[10]*std::abs(gamma));
00104 double S = alpha + c[11]*gamma+c[12]*Fz+c[13];
00105
00106
00107 double Mz = D*sin(c[0]*atan(S*B+E*(atan(S*B)-S*B)));
00108 return Mz;
00109 }
00110
00111
00112
00113
00114
00115 Three_Vector Vamos_Body::
00116 Tire_Friction::friction_forces (double normal_force, double friction_factor,
00117 const Three_Vector& hub_velocity,
00118 double patch_speed, double current_camber,
00119 double sigma_hat, double alpha_hat)
00120 {
00121 double Fz = normal_force / 1000.0;
00122
00123
00124
00125
00126
00127
00128 double sigma = 0.0;
00129 double tan_alpha = 0.0;
00130 double alpha = 0.0;
00131
00132 double V = hub_velocity[0];
00133
00134 {
00135 double denom = std::max (std::abs (hub_velocity [0]), 1.0);
00136
00137
00138 sigma = (patch_speed - V)/denom;
00139
00140
00141
00142 tan_alpha = hub_velocity [1] / denom;
00143
00144 alpha = -rad_to_deg(atan2(hub_velocity[1],denom));
00145 }
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 double gamma = rad_to_deg (current_camber);
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 double s = sigma / sigma_hat;
00169 double a = alpha / alpha_hat;
00170 double rho = sqrt(s*s+a*a);
00171
00172 double Fx = (s / rho)*Pacejka_Fx(rho*sigma_hat, Fz, friction_factor);
00173 double Fy = (a / rho)*Pacejka_Fy(rho*alpha_hat, Fz, gamma, friction_factor);
00174 double Mz = Pacejka_Mz(sigma, alpha, Fz, gamma, friction_factor);
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 double slip_x = -sigma / (1.0 + std::abs (sigma));
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 double slip_y = tan_alpha / (1.0+std::abs (sigma-1.0));
00201
00202 double total_slip = std::sqrt (slip_x * slip_x + slip_y * slip_y);
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 const std::vector <double>& b = m_longitudital_parameters;
00215 double maxforce = b[2] * 7.0;
00216 double combforce = sqrt(Fx*Fx + Fy*Fy);
00217
00218 if (combforce > maxforce && combforce > 1.0e-3)
00219 {
00220
00221 Fx *= maxforce / combforce;
00222 Fy *= maxforce / combforce;
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 if (hub_velocity.abs () < 0.1)
00235 {
00236 m_slide = 0.0;
00237 }
00238 else
00239 {
00240 m_slide = total_slip;
00241 if (m_slide > 1.0)
00242 m_slide = 1.0;
00243 }
00244
00245
00246
00247
00248
00249 return Three_Vector (Fx, Fy, Mz);
00250 }
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 Vamos_Body::
00401 Tire::Tire (double radius, double rolling_resistance_1,
00402 double rolling_resistance_2, const Tire_Friction& friction,
00403 double inertia, double tread) :
00404 m_radius (radius),
00405 m_rolling_resistance_1 (rolling_resistance_1),
00406 m_rolling_resistance_2 (rolling_resistance_2),
00407 m_tire_friction (friction),
00408 m_inertia (inertia),
00409 m_rotational_speed (0.0),
00410 m_last_rotational_speed (0.0),
00411 m_slide (0.0),
00412 m_velocity (0.0, 0.0, 0.0),
00413 m_normal_ang_velocity (0.0),
00414 m_normal_force (0.0),
00415 m_camber (0.0),
00416 m_applied_torque (0.0),
00417 m_is_locked (false),
00418 m_material (0),
00419 m_feedback (0),
00420 m_tread (tread),
00421 m_friction1 (1.0),
00422 m_friction2 (1.0)
00423 {
00424 }
00425
00426
00427 void Vamos_Body::
00428 Tire::input (const Three_Vector& velocity,
00429 double normal_ang_velocity,
00430 const Three_Vector& normal_force,
00431 double camber,
00432 double torque,
00433 bool is_locked,
00434 Material_Handle material)
00435 {
00436 orient_frame_with_unit_vector (normal_force.unit ());
00437
00438 m_velocity = rotate_in (velocity);
00439 m_normal_ang_velocity = normal_ang_velocity;
00440 m_normal_force = normal_force.abs ();
00441 m_camber = camber;
00442 m_applied_torque = torque;
00443 m_is_locked = is_locked;
00444 m_material = material;
00445 }
00446
00447
00448 void Vamos_Body::
00449 Tire::orient_frame_with_unit_vector (const Three_Vector& normal_unit_vector)
00450 {
00451 Three_Vector rotation_axis =
00452 Three_Vector (-normal_unit_vector [1], normal_unit_vector [0], 0.0);
00453
00454 double length = sqrt (normal_unit_vector [0] * normal_unit_vector [0]
00455 + normal_unit_vector [1] * normal_unit_vector [1]);
00456 double rotation_angle = asin (length);
00457
00458 orient (Three_Matrix (1.0));
00459 rotate (rotation_axis.unit () * rotation_angle);
00460 }
00461
00462 void Vamos_Body::
00463 Tire::find_forces ()
00464 {
00465
00466
00467
00468
00469
00470
00471
00472 if (m_material.null ())
00473 return;
00474
00475 m_slide = 0.0;
00476
00477 if (m_normal_force <= 0.0)
00478 {
00479 m_force.zero ();
00480 m_torque.zero ();
00481 return;
00482 }
00483
00484 double sh, ah, nf;
00485 nf = (m_normal_force / 1000.0);
00486 if (nf < HAT_LOAD)
00487 {
00488 sh = sigma_hat[0];
00489 ah = alpha_hat[0];
00490 }
00491 else if (nf > HAT_LOAD*HAT_ITERATIONS)
00492 {
00493 sh = sigma_hat[HAT_ITERATIONS-1];
00494 ah = alpha_hat[HAT_ITERATIONS-1];
00495 }
00496 else
00497 {
00498 int lbound;
00499 double blend;
00500 lbound = (int)(nf/HAT_LOAD);
00501 lbound--;
00502 if (lbound < 0)
00503 lbound = 0;
00504 blend = (nf-HAT_LOAD*(lbound+1))/HAT_LOAD;
00505 sh = sigma_hat[lbound]*(1.0-blend)+sigma_hat[lbound+1]*blend;
00506 ah = alpha_hat[lbound]*(1.0-blend)+alpha_hat[lbound+1]*blend;
00507 }
00508
00509
00510
00511
00512 double surface_friction_factor = (1.0-m_tread)*m_friction1 + m_tread*m_friction2;
00513
00514
00515 Three_Vector friction_force = m_tire_friction.
00516
00517 friction_forces (m_normal_force, surface_friction_factor, m_velocity, speed(), m_camber, sh, ah);
00518
00519
00520
00521
00522 if (0)
00523 {
00524 ofstream of("/home/joe/temp/y.txt");
00525 double x;
00526 double load = 2.500;
00527 of << "Fx = c(";
00528 for (x = -2; x < 2; x += 0.01)
00529 {
00530
00531
00532
00533
00534
00535
00536
00537
00538 of << m_tire_friction.Pacejka_Fx(x, load, 1.0) << ",";
00539 }
00540 of << "0)" << endl;
00541
00542
00543
00544
00545 of << "Fy = c(";
00546 for (x = -20; x < 20; x += 0.1)
00547 {
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557 of << m_tire_friction.Pacejka_Fy(x, load, 0, 1.0) << ",";
00558 }
00559 of << "0)" << endl;
00560
00561
00562
00563
00564 of << "Mz = c(";
00565 for (x = -20; x < 20; x += 0.1)
00566 {
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 of << m_tire_friction.Pacejka_Mz(0, x, load, 0, 1.0) << ",";
00578 }
00579 of << "0)" << endl;
00580
00581 of.close();
00582
00583
00584 }
00585
00586
00587 m_force = Three_Vector (friction_force [0], friction_force [1], 0.0);
00588
00589
00590
00591
00592
00593
00594
00595 double reaction = m_force [0] * m_radius;
00596 if (((m_applied_torque > 0.0) && (reaction > m_applied_torque))
00597 || ((m_applied_torque < 0.0) && (reaction < m_applied_torque)))
00598 {
00599 reaction = m_applied_torque;
00600 }
00601
00602
00603
00604
00605
00606 m_torque = Three_Vector (0.0, reaction, friction_force [2]);
00607
00608 double feedbackcoeff = 0.05;
00609 m_feedback = m_feedback*(1.0-feedbackcoeff) + friction_force[2]*feedbackcoeff;
00610
00611 if (!m_is_locked)
00612 {
00613 double rolling_1 = m_rolling_resistance_1;
00614 if (speed () < 0.0)
00615 rolling_1 *= -1.0;
00616
00617 double rolling = m_rolling_resistance_factor
00618 * (rolling_1 + m_rolling_resistance_2 * speed () * speed ());
00619 m_applied_torque -= (m_force [0] + rolling) * m_radius;
00620 }
00621
00622
00623 m_force [0] -= m_rolling_drag * m_velocity [0];
00624 m_force [1] -= m_rolling_drag * m_velocity [1];
00625
00626 m_slide = m_tire_friction.slide ();
00627
00628 bool nan = false;
00629 if (!(m_force[0] < 0 || m_force[0] >= 0))
00630 {
00631 m_force[0] = 0;
00632 nan = true;
00633 }
00634 if (!(m_force[1] < 0 || m_force[1] >= 0))
00635 {
00636 m_force[1] = 0;
00637 nan = true;
00638 }
00639 if (!(m_force[2] < 0 || m_force[2] >= 0))
00640 {
00641 m_force[2] = 0;
00642 nan = true;
00643 }
00644
00645 if (nan)
00646 m_force.zero();
00647
00648 nan = false;
00649
00650 if (!(m_torque[0] < 0 || m_torque[0] >= 0))
00651 {
00652 m_torque[0] = 0;
00653 nan = true;
00654 }
00655 if (!(m_torque[1] < 0 || m_torque[1] >= 0))
00656 {
00657 m_torque[1] = 0;
00658 nan = true;
00659 }
00660 if (!(m_torque[2] < 0 || m_torque[2] >= 0))
00661 {
00662 m_torque[2] = 0;
00663 nan = true;
00664 }
00665
00666 if (nan)
00667 m_torque.zero();
00668 }
00669
00670
00671 void Vamos_Body::
00672 Tire::propagate (double time)
00673 {
00674 m_last_rotational_speed = m_rotational_speed;
00675 if (m_is_locked)
00676 {
00677
00678 m_rotational_speed = 0.0;
00679 }
00680 else
00681 {
00682 m_rotational_speed += m_applied_torque * time / m_inertia;
00683 }
00684 }
00685
00686 void Vamos_Body::
00687 Tire::rewind ()
00688 {
00689 m_rotational_speed = m_last_rotational_speed;
00690 }
00691
00692
00693
00694 Three_Vector Vamos_Body::
00695 Tire::contact_position () const
00696 {
00697 return Three_Vector (0.0, 0.0, -m_radius);
00698 }
00699
00700
00701 void Vamos_Body::
00702 Tire::reset ()
00703 {
00704
00705 m_rotational_speed = 0.0;
00706 m_force.zero ();
00707 m_torque.zero ();
00708
00709 int i;
00710 for (i = 0; i < HAT_ITERATIONS; i++)
00711 {
00712 FindSigmaHatAlphaHat((double)(i+1)*HAT_LOAD, sigma_hat[i], alpha_hat[i]);
00713
00714 }
00715 }
00716
00717 void Vamos_Body::
00718 Tire::FindSigmaHatAlphaHat(double load, double & sh, double & ah)
00719 {
00720 double x, y, ymax;
00721 ymax = 0;
00722 for (x = -2; x < 2; x += 0.01)
00723 {
00724 y = m_tire_friction.Pacejka_Fx(x, load, 1.0);
00725 if (y > ymax)
00726 {
00727 sh = x;
00728 ymax = y;
00729 }
00730 }
00731
00732 ymax = 0;
00733 for (x = -20; x < 20; x += 0.1)
00734 {
00735 y = m_tire_friction.Pacejka_Fy(x, load, 0, 1.0);
00736 if (y > ymax)
00737 {
00738 ah = x;
00739 ymax = y;
00740 }
00741 }
00742 }