Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SITL: add Omni3Mecanum vehicle to SIM_Rover #27581

Merged
merged 2 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions Tools/autotest/default_params/rover-omni3mecanum.parm
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
ACRO_TURN_RATE 300.000000
ATC_SPEED_P 0.200000
ATC_SPEED_D 0.000010
ATC_STR_RAT_D 0.000010
ATC_STR_RAT_FF 0.100000
ATC_STR_RAT_I 0.010000
ATC_STR_RAT_MAX 360.000000
ATC_STR_RAT_P 0.030000
CRUISE_SPEED 1.0
CRUISE_THROTTLE 42.0
FRAME_TYPE 4
PSC_VEL_P 0.500000
RC2_MAX 2000
RC2_MIN 1000
RC4_MAX 2000
RC4_MIN 1000
SERVO1_FUNCTION 33
SERVO2_FUNCTION 34
SERVO2_MAX 2000
SERVO2_MIN 1000
SERVO3_FUNCTION 35
WP_PIVOT_RATE 120.0
WP_SPEED 1.0


5 changes: 5 additions & 0 deletions Tools/autotest/pysim/vehicleinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,11 @@ def __init__(self):
"default_params_filename": ["default_params/rover.parm",
"default_params/rover-skid.parm"],
},
"rover-omni3mecanum": {
"waf_target": "bin/ardurover",
"default_params_filename": ["default_params/rover.parm",
"default_params/rover-omni3mecanum.parm"],
},
"rover-vectored": {
"waf_target": "bin/ardurover",
"default_params_filename": ["default_params/rover.parm",
Expand Down
142 changes: 116 additions & 26 deletions libraries/SITL/SIM_Rover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <string.h>
#include <stdio.h>

#include <AP_Math/AP_Math.h>

namespace SITL {

SimRover::SimRover(const char *frame_str) :
Expand All @@ -41,10 +43,14 @@ SimRover::SimRover(const char *frame_str) :
if (vectored_thrust) {
printf("Vectored Thrust Rover Simulation Started\n");
}
lock_step_scheduled = true;
}

omni3 = strstr(frame_str, "omni3mecanum") != nullptr;
if (omni3) {
printf("Omni3 Mecanum Rover Simulation Started\n");
}

lock_step_scheduled = true;
}

/*
return turning circle (diameter) in meters for steering angle proportion in degrees
Expand Down Expand Up @@ -92,6 +98,50 @@ float SimRover::calc_lat_accel(float steering_angle, float speed)
update the rover simulation by one time step
*/
void SimRover::update(const struct sitl_input &input)
{
// how much time has passed?
float delta_time = frame_time_us * 1.0e-6f;

// update gyro and accel_body according to frame type
if (omni3) {
update_omni3(input, delta_time);
} else {
update_ackermann_or_skid(input, delta_time);
}

// common to all rovers

// now in earth frame
Vector3f accel_earth = dcm * accel_body;
accel_earth += Vector3f(0, 0, GRAVITY_MSS);

// we are on the ground, so our vertical accel is zero
accel_earth.z = 0;

// work out acceleration as seen by the accelerometers. It sees the kinematic
// acceleration (ie. real movement), plus gravity
accel_body = dcm.transposed() * (accel_earth + Vector3f(0, 0, -GRAVITY_MSS));

// new velocity vector
velocity_ef += accel_earth * delta_time;

// new position vector
position += (velocity_ef * delta_time).todouble();

update_external_payload(input);

// update lat/lon/altitude
update_position();
time_advance();

// update magnetic field
update_mag_field_bf();
}

/*
update the ackermann or skid rover simulation by one time step
*/
void SimRover::update_ackermann_or_skid(const struct sitl_input &input, float delta_time)
{
float steering, throttle;

Expand All @@ -113,9 +163,6 @@ void SimRover::update(const struct sitl_input &input)
}
}

// how much time has passed?
float delta_time = frame_time_us * 1.0e-6f;

// speed in m/s in body frame
Vector3f velocity_body = dcm.transposed() * velocity_ef;

Expand All @@ -137,37 +184,80 @@ void SimRover::update(const struct sitl_input &input)
dcm.rotate(gyro * delta_time);
dcm.normalize();

// accel in body frame due to motor
// accel in body frame due to motor (excluding gravity)
accel_body = Vector3f(accel, 0, 0);

// add in accel due to direction change
accel_body.y += radians(yaw_rate) * speed;
}

// now in earth frame
Vector3f accel_earth = dcm * accel_body;
accel_earth += Vector3f(0, 0, GRAVITY_MSS);

// we are on the ground, so our vertical accel is zero
accel_earth.z = 0;

// work out acceleration as seen by the accelerometers. It sees the kinematic
// acceleration (ie. real movement), plus gravity
accel_body = dcm.transposed() * (accel_earth + Vector3f(0, 0, -GRAVITY_MSS));
/*
update the omni3 rover simulation by one time step
*/
void SimRover::update_omni3(const struct sitl_input &input, float delta_time)
{
// in omni3 mode the first three servos are motor speeds
float motor1 = 2*((input.servos[0]-1000)/1000.0f - 0.5f);
float motor2 = 2*((input.servos[1]-1000)/1000.0f - 0.5f);
float motor3 = 2*((input.servos[2]-1000)/1000.0f - 0.5f);

// use forward kinematics to calculate body frame velocity
Vector3f wheel_ang_vel(
motor1 * omni3_wheel_max_ang_vel,
motor2 * omni3_wheel_max_ang_vel,
motor3 * omni3_wheel_max_ang_vel
);

// derivation of forward kinematics for an Omni3Mecanum rover
// A. Gfrerrer. "Geometry and kinematics of the Mecanum wheel",
// Computer Aided Geometric Design 25 (2008) 784–791.
// Retrieved from https://www.geometrie.tugraz.at/gfrerrer/publications/MecanumWheel.pdf.
//
// the frame is equilateral triangle
//
// d[i] = 0.18 m is distance from frame centre to each wheel
// r_w = 0.04725 m is the wheel radius.
// delta = radians(-45) is angle of the roller to the direction of forward rotation
// alpha[i] is the angle the wheel axis is rotated about the body z-axis
// c[i] = cos(alpha[i] + delta)
// s[i] = sin(alpha[i] + delta)
//
// wheel d[i] alpha[i] a_x[i] a_y[i] c[i] s[i]
// 1 0.18 1.04719 0.09 0.15588 0.965925 0.258819
// 2 0.18 3.14159 -0.18 0.0 -0.707106 0.707106
// 3 0.18 5.23598 0.09 -0.15588 -0.258819 -0.965925
//
// k = 1/(r_w * sin(delta)) = -29.930445 is a scale factor
//
// inverse kinematic matrix
// M[i, 0] = k * c[i]
// M[i, 1] = k * s[i]
// M[i, 2] = k * (a_x[i] s[i] - a_y[i] c[i])
//
// forward kinematics matrix: Minv = M^-1
constexpr Matrix3f Minv(
-0.0215149, 0.01575, 0.0057649,
-0.0057649, -0.01575, 0.0215149,
0.0875, 0.0875, 0.0875);

// twist - this is the target linear and angular velocity
Vector3f twist = Minv * wheel_ang_vel;

// new velocity vector
velocity_ef += accel_earth * delta_time;
// speed in m/s in body frame
Vector3f velocity_body = dcm.transposed() * velocity_ef;

// new position vector
position += (velocity_ef * delta_time).todouble();
// linear acceleration in m/s/s - very crude model
float accel_x = omni3_max_accel * (twist.x - velocity_body.x) / omni3_max_speed;
float accel_y = omni3_max_accel * (twist.y - velocity_body.y) / omni3_max_speed;

update_external_payload(input);
gyro = Vector3f(0, 0, twist.z);

// update lat/lon/altitude
update_position();
time_advance();
// update attitude
dcm.rotate(gyro * delta_time);
dcm.normalize();

// update magnetic field
update_mag_field_bf();
// accel in body frame due to motors (excluding gravity)
accel_body = Vector3f(accel_x, accel_y, 0);
}

} // namespace SITL
9 changes: 9 additions & 0 deletions libraries/SITL/SIM_Rover.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ class SimRover : public Aircraft {
float vectored_angle_max = 90.0f; // maximum angle (in degrees) to which thrust can be turned
float vectored_turn_rate_max = 90.0f; // maximum turn rate (in deg/sec) with full throttle angled at 90deg

// omni3 Mecanum related members
bool omni3; // true if vehicle is omni-directional with 3 Mecanum wheels
float omni3_max_speed = 2.3625f; // omni vehicle's maximum forward speed in m/s
float omni3_max_accel = 1.0f; // omni vehicle's maximum forward acceleration in m/s/s
float omni3_wheel_max_ang_vel = 50.0f; // omni vehicle's wheel maximum angular velocity in rad/s

void update_ackermann_or_skid(const struct sitl_input &input, float delta_time);
void update_omni3(const struct sitl_input &input, float delta_time);

float turn_circle(float steering) const;
float calc_yaw_rate(float steering, float speed);
float calc_lat_accel(float steering_angle, float speed);
Expand Down
Loading