@@ -376,7 +376,7 @@ Linear 2D translational spring damper model
376376 @variables begin
377377 v_relx (t)
378378 v_rely (t)
379- ω_rel (t) = 0
379+ w_rel (t) = 0
380380 s_relx (t)
381381 s_rely (t)
382382 phi_rel (t) = 0
@@ -397,9 +397,9 @@ Linear 2D translational spring damper model
397397 phi_rel ~ frame_b. phi - frame_a. phi
398398 v_relx ~ D (s_relx)
399399 v_rely ~ D (s_rely)
400- ω_rel ~ D (phi_rel)
400+ w_rel ~ D (phi_rel)
401401
402- tau ~ c_phi * (phi_rel - phi_rel0) + d_phi * ω_rel
402+ tau ~ c_phi * (phi_rel - phi_rel0) + d_phi * w_rel
403403 frame_a. tau ~ - tau
404404 frame_b. tau ~ tau
405405 f_x ~ c_x * (s_relx - s_relx0) + d_x * v_relx
@@ -412,3 +412,189 @@ Linear 2D translational spring damper model
412412 # lossPower ~ d_x * v_relx * v_relx + d_y * v_rely * v_rely
413413 end
414414end
415+
416+
417+ @mtkmodel SimpleWheel begin
418+ @structural_parameters begin
419+ friction_model = :viscous
420+ end
421+ @parameters begin
422+ (radius = 0.3 ), [description = " Radius of the wheel" ]
423+ (color[1 : 4 ] = [1 , 0 , 0 , 1 ]), [description = " Color of the wheel in animations" ]
424+ μ = 1e9 , [description = " Viscous friction coefficient" ]
425+ # Fy0 = 1e4, [description = "Lateral friction force at zero longitudinal force"]
426+ # μx = Fy0, [description = "Maximum longitudinal friction force"]
427+ end
428+ @variables begin
429+ θ (t), [guess= 0 , description= " wheel angle" ] # wheel angle
430+ Vx (t), [guess= 0 , description= " longitudinal velocity (resolved in local frame)" ]
431+ Vy (t)= 0 , [description= " lateral velocity (resolved in local frame)" ]
432+ Fy (t), [guess= 0 , description= " lateral friction force" ]
433+ Fx (t), [guess= 0 , description= " applied longitudinal wheel force" ]
434+ end
435+ @components begin
436+ frame_a = Frame ()
437+ thrust = Blocks. RealInput ()
438+ end
439+ begin
440+ R_W_F = ori_2d (frame_a) # rotation matrix, local to global
441+ veqs = R_W_F' * [D (frame_a. x), D (frame_a. y)] # ~ [Vx, Vy]
442+ feqs = R_W_F' * [frame_a. fx, frame_a. fy] # ~ [Fx, Fy]
443+ end
444+
445+
446+ @equations begin
447+ θ ~ frame_a. phi
448+
449+ # road friction
450+ Fx ~ thrust. u
451+ # if friction_model == :viscous
452+ Fy ~ μ* Vy
453+ # elseif friction_model == :ellipse
454+ # Fy ~ Fy0*sqrt(1 - (Fx/μ)^2)*Vy
455+ # end
456+ veqs[1 ] ~ Vx
457+ veqs[2 ] ~ Vy
458+ feqs[1 ] ~ Fx
459+ feqs[2 ] ~ Fy
460+
461+ # R'*[D(frame.x), D(frame.y)] ~ [Vx, Vy]
462+ # R'*[frame.fx, frame.fy] ~ [Fx, Fy]
463+
464+ frame_a. tau ~ 0 # Assume that wheel does not transmit any torque
465+ end
466+ end
467+
468+ """
469+ limit_S_triple(x_max, x_sat, y_max, y_sat, x)
470+
471+ Returns a point-symmetric Triple S-Function
472+
473+ A point symmetric interpolation between points `(0, 0), (x_max, y_max) and (x_sat, y_sat)`, provided `x_max < x_sat`. The approximation is done in such a way that the 1st function's derivative is zero at points `(x_max, y_max)` and `(x_sat, y_sat)`. Thus, the 1st function's derivative is continuous for all `x`. The higher derivatives are discontinuous at these points.
474+ """
475+ function limit_S_triple (x_max, x_sat, y_max, y_sat, x)
476+ if x > x_max
477+ return limit_S_form (x_max, x_sat, y_max, y_sat, x)
478+ elseif x < - x_max
479+ return limit_S_form (- x_max, - x_sat, - y_max, - y_sat, x)
480+ else
481+ return limit_S_form (- x_max, x_max, - y_max, y_max, x)
482+ end
483+ end
484+
485+
486+ """
487+ limit_S_form(x_min, x_max, y_min, y_max, x)
488+
489+ Returns a S-shaped transition
490+
491+ A smooth transition between points `(x_min, y_min)` and `(x_max, y_max)`. The transition is done in such a way that the 1st function's derivative is continuous for all `x`. The higher derivatives are discontinuous at input points.
492+ """
493+ function limit_S_form (x_min, x_max, y_min, y_max, x)
494+ x2 = x - x_max/ 2 - x_min/ 2
495+ x2 = x2* 2 / (x_max- x_min)
496+ y = clamp (- 0.5 * x2^ 3 + 1.5 * x2, - 1 , 1 )
497+ y = y* (y_max- y_min)/ 2
498+ y = y + y_max/ 2 + y_min/ 2
499+ return y
500+ end
501+
502+
503+ @register_symbolic limit_S_triple (x_max:: Real , x_sat:: Real , y_max:: Real , y_sat:: Real , x:: Real )
504+ @register_symbolic limit_S_form (x_min:: Real , x_max:: Real , y_min:: Real , y_max:: Real , x:: Real )
505+
506+
507+ @component function SlipBasedWheelJoint (;
508+ name,
509+ r = [1 , 0 ],
510+ N,
511+ vAdhesion_min,
512+ vSlide_min,
513+ sAdhesion,
514+ sSlide,
515+ mu_A,
516+ mu_S,
517+ render = true ,
518+ color = [0.1 , 0.1 , 0.1 , 1 ],
519+ z = 0 ,
520+ diameter = 0.1 ,
521+ width = diameter * 0.6 ,
522+ radius = 0.1 ,
523+ w_roll = nothing ,
524+ )
525+ systems = @named begin
526+ frame_a = Frame ()
527+ flange_a = Rotational. Flange ()
528+ dynamicLoad = Blocks. RealInput ()
529+ end
530+ pars = @parameters begin
531+ r[1 : 2 ] = r, [description = " Driving direction of the wheel at angle phi = 0" ]
532+ N = N, [description = " Base normal load" ]
533+ vAdhesion_min = vAdhesion_min, [description = " Minimum adhesion velocity" ]
534+ vSlide_min = vSlide_min, [description = " Minimum sliding velocity" ]
535+ sAdhesion = sAdhesion, [description = " Adhesion slippage" ]
536+ sSlide = sSlide, [description = " Sliding slippage" ]
537+ mu_A = mu_A, [description = " Friction coefficient at adhesion" ]
538+ mu_S = mu_S, [description = " Friction coefficient at sliding" ]
539+ render = render, [description = " Render the wheel in animations" ]
540+ color[1 : 4 ] = color, [description = " Color of the wheel in animations" ]
541+ z = 0 , [description = " Position z of the body" ]
542+ diameter = diameter, [description = " Diameter of the rims" ]
543+ width = width, [description = " Width of the wheel" ]
544+ radius = radius, [description = " Radius of the wheel" ]
545+ end
546+ r = collect (r)
547+ l = Multibody. _norm (r)
548+ e = Multibody. _normalize (r) # Unit vector in direction of r
549+
550+ vars = @variables begin
551+ e0 (t)[1 : 2 ], [description= " Unit vector in direction of r resolved w.r.t. inertial frame" ]
552+ phi_roll (t), [guess= 0 , description= " wheel angle" ] # wheel angle
553+ (w_roll (t)= w_roll), [guess= 0 , description= " Roll velocity of wheel" ]
554+ v (t)[1 : 2 ], [description= " velocity" ]
555+ v_lat (t), [guess= 0 , description= " Driving in lateral direction" ]
556+ v_long (t), [guess= 0 , description= " Velocity in longitudinal direction" ]
557+ v_slip_long (t), [guess= 0 , description= " Slip velocity in longitudinal direction" ]
558+ v_slip_lat (t), [guess= 0 , description= " Slip velocity in lateral direction" ]
559+ v_slip (t), [description= " Slip velocity" ]
560+ f (t), [description= " Longitudinal force" ]
561+ f_lat (t), [description= " Longitudinal force" ]
562+ f_long (t), [description= " Longitudinal force" ]
563+ fN (t), [description= " Base normal load" ]
564+ vAdhesion (t), [description= " Adhesion velocity" ]
565+ vSlide (t), [description= " Sliding velocity" ]
566+ end
567+ e0 = collect (e0)
568+ v = collect (v)
569+ vars = [
570+ e0; phi_roll; w_roll; v; v_lat; v_long; v_slip_long; v_slip_lat; v_slip; f; f_lat; f_long; fN; vAdhesion; vSlide
571+ ]
572+
573+ R = ori_2d (frame_a)
574+
575+ equations = [
576+ e0 .~ R * e
577+ v .~ D .([frame_a. x, frame_a. y])
578+
579+ phi_roll ~ flange_a. phi
580+ w_roll ~ D (phi_roll)
581+ v_long ~ v' * e0
582+ v_lat ~ - v[1 ] * e0[2 ] + v[2 ] * e0[1 ]
583+ v_slip_lat ~ v_lat - 0
584+ v_slip_long ~ v_long - radius * w_roll
585+ v_slip ~ sqrt (v_slip_long^ 2 + v_slip_lat^ 2 ) + 0.0001
586+ - f_long * radius ~ flange_a. tau
587+ frame_a. tau ~ 0
588+ vAdhesion ~ max (vAdhesion_min, sAdhesion * abs (radius * w_roll))
589+ vSlide ~ max (vSlide_min, sSlide * abs (radius * w_roll))
590+ fN ~ max (0 , N + dynamicLoad. u)
591+ f ~ fN * limit_S_triple (vAdhesion, vSlide, mu_A, mu_S, v_slip)
592+ f_long ~ f * v_slip_long / v_slip
593+ f_lat ~ f * v_slip_lat / v_slip
594+ f_long ~ [frame_a. fx, frame_a. fy]' e0
595+ f_lat ~ [frame_a. fy, - frame_a. fx]' e0
596+ ]
597+
598+ return ODESystem (equations, t, vars, pars; name, systems)
599+
600+ end
0 commit comments