mirror of
https://github.com/bjoernellens1/cps_microros_imu.git
synced 2024-11-24 00:45:06 +00:00
149 lines
4.8 KiB
C++
149 lines
4.8 KiB
C++
|
// Copyright (c) 2021 Juan Miguel Jimeno
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
#include "Arduino.h"
|
||
|
#include "kinematics.h"
|
||
|
|
||
|
Kinematics::Kinematics(base robot_base, int motor_max_rpm, float max_rpm_ratio,
|
||
|
float motor_operating_voltage, float motor_power_max_voltage,
|
||
|
float wheel_diameter, float wheels_y_distance):
|
||
|
base_platform_(robot_base),
|
||
|
wheels_y_distance_(wheels_y_distance),
|
||
|
wheel_circumference_(PI * wheel_diameter),
|
||
|
total_wheels_(getTotalWheels(robot_base))
|
||
|
{
|
||
|
motor_power_max_voltage = constrain(motor_power_max_voltage, 0, motor_operating_voltage);
|
||
|
max_rpm_ = ((motor_power_max_voltage / motor_operating_voltage) * motor_max_rpm) * max_rpm_ratio;
|
||
|
}
|
||
|
|
||
|
Kinematics::rpm Kinematics::calculateRPM(float linear_x, float linear_y, float angular_z)
|
||
|
{
|
||
|
|
||
|
float tangential_vel = angular_z * (wheels_y_distance_ / 2.0);
|
||
|
|
||
|
//convert m/s to m/min
|
||
|
float linear_vel_x_mins = linear_x * 60.0;
|
||
|
float linear_vel_y_mins = linear_y * 60.0;
|
||
|
//convert rad/s to rad/min
|
||
|
float tangential_vel_mins = tangential_vel * 60.0;
|
||
|
|
||
|
float x_rpm = linear_vel_x_mins / wheel_circumference_;
|
||
|
float y_rpm = linear_vel_y_mins / wheel_circumference_;
|
||
|
float tan_rpm = tangential_vel_mins / wheel_circumference_;
|
||
|
|
||
|
float a_x_rpm = fabs(x_rpm);
|
||
|
float a_y_rpm = fabs(y_rpm);
|
||
|
float a_tan_rpm = fabs(tan_rpm);
|
||
|
|
||
|
float xy_sum = a_x_rpm + a_y_rpm;
|
||
|
float xtan_sum = a_x_rpm + a_tan_rpm;
|
||
|
|
||
|
//calculate the scale value how much each target velocity
|
||
|
//must be scaled down in such cases where the total required RPM
|
||
|
//is more than the motor's max RPM
|
||
|
//this is to ensure that the required motion is achieved just with slower speed
|
||
|
if(xy_sum >= max_rpm_ && angular_z == 0)
|
||
|
{
|
||
|
float vel_scaler = max_rpm_ / xy_sum;
|
||
|
|
||
|
x_rpm *= vel_scaler;
|
||
|
y_rpm *= vel_scaler;
|
||
|
}
|
||
|
|
||
|
else if(xtan_sum >= max_rpm_ && linear_y == 0)
|
||
|
{
|
||
|
float vel_scaler = max_rpm_ / xtan_sum;
|
||
|
|
||
|
x_rpm *= vel_scaler;
|
||
|
tan_rpm *= vel_scaler;
|
||
|
}
|
||
|
|
||
|
Kinematics::rpm rpm;
|
||
|
|
||
|
//calculate for the target motor RPM and direction
|
||
|
//front-left motor
|
||
|
rpm.motor1 = x_rpm - y_rpm - tan_rpm;
|
||
|
rpm.motor1 = constrain(rpm.motor1, -max_rpm_, max_rpm_);
|
||
|
|
||
|
//front-right motor
|
||
|
rpm.motor2 = x_rpm + y_rpm + tan_rpm;
|
||
|
rpm.motor2 = constrain(rpm.motor2, -max_rpm_, max_rpm_);
|
||
|
|
||
|
//rear-left motor
|
||
|
rpm.motor3 = x_rpm + y_rpm - tan_rpm;
|
||
|
rpm.motor3 = constrain(rpm.motor3, -max_rpm_, max_rpm_);
|
||
|
|
||
|
//rear-right motor
|
||
|
rpm.motor4 = x_rpm - y_rpm + tan_rpm;
|
||
|
rpm.motor4 = constrain(rpm.motor4, -max_rpm_, max_rpm_);
|
||
|
|
||
|
return rpm;
|
||
|
}
|
||
|
|
||
|
Kinematics::rpm Kinematics::getRPM(float linear_x, float linear_y, float angular_z)
|
||
|
{
|
||
|
if(base_platform_ == DIFFERENTIAL_DRIVE || base_platform_ == SKID_STEER)
|
||
|
{
|
||
|
linear_y = 0;
|
||
|
}
|
||
|
|
||
|
return calculateRPM(linear_x, linear_y, angular_z);;
|
||
|
}
|
||
|
|
||
|
Kinematics::velocities Kinematics::getVelocities(float rpm1, float rpm2, float rpm3, float rpm4)
|
||
|
{
|
||
|
Kinematics::velocities vel;
|
||
|
float average_rps_x;
|
||
|
float average_rps_y;
|
||
|
float average_rps_a;
|
||
|
|
||
|
if(base_platform_ == DIFFERENTIAL_DRIVE)
|
||
|
{
|
||
|
rpm3 = 0.0;
|
||
|
rpm4 = 0.0;
|
||
|
}
|
||
|
|
||
|
//convert average revolutions per minute to revolutions per second
|
||
|
average_rps_x = ((float)(rpm1 + rpm2 + rpm3 + rpm4) / total_wheels_) / 60.0; // RPM
|
||
|
vel.linear_x = average_rps_x * wheel_circumference_; // m/s
|
||
|
|
||
|
//convert average revolutions per minute in y axis to revolutions per second
|
||
|
average_rps_y = ((float)(-rpm1 + rpm2 + rpm3 - rpm4) / total_wheels_) / 60.0; // RPM
|
||
|
if(base_platform_ == MECANUM)
|
||
|
vel.linear_y = average_rps_y * wheel_circumference_; // m/s
|
||
|
else
|
||
|
vel.linear_y = 0;
|
||
|
|
||
|
//convert average revolutions per minute to revolutions per second
|
||
|
average_rps_a = ((float)(-rpm1 + rpm2 - rpm3 + rpm4) / total_wheels_) / 60.0;
|
||
|
vel.angular_z = (average_rps_a * wheel_circumference_) / (wheels_y_distance_ / 2.0); // rad/s
|
||
|
|
||
|
return vel;
|
||
|
}
|
||
|
|
||
|
int Kinematics::getTotalWheels(base robot_base)
|
||
|
{
|
||
|
switch(robot_base)
|
||
|
{
|
||
|
case DIFFERENTIAL_DRIVE: return 2;
|
||
|
case SKID_STEER: return 4;
|
||
|
case MECANUM: return 4;
|
||
|
default: return 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float Kinematics::getMaxRPM()
|
||
|
{
|
||
|
return max_rpm_;
|
||
|
}
|