LCOV - code coverage report
Current view: top level - SITL - SIM_BalanceBot.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 74 74 100.0 %
Date: 2026-09-09 11:02:08 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :    This program is free software: you can redistribute it and/or modify
       3             :    it under the terms of the GNU General Public License as published by
       4             :    the Free Software Foundation, either version 3 of the License, or
       5             :    (at your option) any later version.
       6             : 
       7             :    This program is distributed in the hope that it will be useful,
       8             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10             :    GNU General Public License for more details.
      11             : 
      12             :    You should have received a copy of the GNU General Public License
      13             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  */
      15             : /*
      16             :   Balance Bot simulator class
      17             : */
      18             : 
      19             : #include "SIM_BalanceBot.h"
      20             : #include <stdio.h>
      21             : 
      22             : extern const AP_HAL::HAL& hal;
      23             : 
      24             : namespace SITL {
      25             : 
      26          32 : BalanceBot::BalanceBot(const char *frame_str) :
      27             :     Aircraft(frame_str),
      28          32 :     skid_turn_rate(0.15708) // meters/sec
      29             : {
      30          32 :     dcm.from_euler(0,0,0); // initial yaw, pitch and roll in radians
      31          32 :     lock_step_scheduled = true;
      32          32 :     printf("Balance Bot Simulation Started\n");
      33          32 : }
      34             : 
      35             : /*
      36             :    return yaw rate in degrees/second given steering_angle
      37             : */
      38     1410742 : float BalanceBot::calc_yaw_rate(float steering) const
      39             : {
      40     1410742 :     float wheel_base_length = 0.15f;
      41     1410742 :     return steering * degrees( skid_turn_rate/wheel_base_length );
      42             : }
      43             : 
      44             : 
      45             : /*
      46             :   update the Balance Bot simulation by one time step
      47             :  */
      48             : /*
      49             :  * The balance bot is physically modeled as an inverted pendulum(cuboid) on wheels
      50             :  * Further details on the equations used can be found here:
      51             :  * 1) http://robotics.ee.uwa.edu.au/theses/2003-Balance-Ooi.pdf page 33 onwards
      52             :  * 2) http://journals.sagepub.com/doi/pdf/10.5772/63933
      53             :  */
      54     1410742 : void BalanceBot::update(const struct sitl_input &input)
      55             : {
      56             :     // pendulum/chassis constants
      57     1410742 :     const float m_p = 3.0f; //pendulum mass(kg)
      58             :     // const float width = 0.0650f; //width(m)
      59             :     // const float height = 0.240f; //height(m)
      60     1410742 :     const float l = 0.10f; //height of center of mass from base(m)
      61     1410742 :     const float i_p = 0.01250f; //Moment of inertia about pitch axis(SI units)
      62             : 
      63             :     // wheel constants
      64     1410742 :     const float r_w = 0.05f; //wheel radius(m)
      65     1410742 :     const float m_w = 0.1130f; //wheel mass(kg)
      66     1410742 :     const float i_w = 0.00015480f; // moment of inertia of wheel(SI units)
      67             : 
      68             :     // motor constants
      69     1410742 :     const float R = 3.0f; //Winding resistance(ohm)
      70     1410742 :     const float k_e = 0.240f; //back-emf constant(SI units)
      71     1410742 :     const float k_t = 0.240f; //torque constant(SI units)
      72     1410742 :     const float v_max = 12.0f; //max input voltage(V)
      73     1410742 :     const float gear_ratio = 50.0f;
      74             : 
      75             :     // balance bot uses skid steering
      76     1410742 :     float motor1 = input.servos[0] ? normalise_servo_input(input.servos[0]) : 0;
      77     1410742 :     float motor2 = input.servos[2] ? normalise_servo_input(input.servos[2]) : 0;
      78     1410742 :     const float steering = motor1 - motor2;
      79     1410742 :     const float throttle = 0.5 * (motor1 + motor2);
      80             : 
      81             :     // motor input voltage: (throttle/max_throttle)*v_max
      82     1410742 :     const float v = throttle*v_max;
      83             : 
      84             :     // how much time has passed?
      85     1410742 :     const float delta_time = frame_time_us * 1.0e-6f;
      86             : 
      87             :     // yaw rate in degrees/s
      88     1410742 :     float yaw_rate = calc_yaw_rate(steering);
      89             : 
      90             :     // obtain roll, pitch, yaw from dcm
      91             :     float r, p, y;
      92     1410742 :     dcm.to_euler(&r, &p, &y);
      93     1410742 :     float theta = p; //radians
      94             : 
      95     1410742 :     float ang_vel = gyro.y; //radians/s
      96     1410742 :     if (!hal.util->get_soft_armed()) {
      97             :         // simulated fingers uprighting the vehicle
      98      826949 :         const float p_gain = 200;
      99      826949 :         const float pitch_response = -sin(p) * p_gain * delta_time;
     100      826949 :         ang_vel += pitch_response;
     101             : 
     102             :         // simulated fingers rotating the vehicle
     103      826949 :         const float y_gain = 100000;
     104      826949 :         const float yaw_response = -sin(wrap_180(y)) * y_gain * delta_time;
     105      826949 :         yaw_rate += yaw_response;
     106             :     }
     107             : 
     108             :     // t1,t2,t3 are terms in the equation to find vehicle frame x acceleration
     109     1410742 :     const float t1 = ((2.0f*gear_ratio*k_t*v/(R*r_w)) - (2.0f*gear_ratio*k_t*k_e*velocity_vf_x/(R*r_w*r_w)) - (m_p*l*ang_vel*ang_vel*sin(theta))) * (i_p + m_p*l*l);
     110     1410742 :     const float t2 = -m_p*l*cos(theta)*((2.0f*gear_ratio*k_t*k_e*velocity_vf_x/(R*r_w)) - (2.0f*gear_ratio*k_t*v/(R)) + (m_p*GRAVITY_MSS*l*sin(theta)));
     111     1410742 :     const float t3 = ( ((2.0f*m_w + 2.0f*i_w/(r_w*r_w) + m_p) * (i_p + m_p*l*l)) - (m_p*m_p*l*l*cos(theta)*cos(theta)) );
     112             : 
     113             :     //vehicle frame x acceleration
     114     1410742 :     const float accel_vf_x = (t1-t2)/t3;
     115             : 
     116     1410742 :     const float angular_accel_bf_y = ((2.0f*gear_ratio*k_t*k_e*velocity_vf_x/(R*r_w)) - (2.0f*gear_ratio*k_t*v/(R)) + m_p*l*accel_vf_x*cos(theta) + m_p*GRAVITY_MSS*l*sin(theta))
     117     1410742 :                                      / (i_p + m_p*l*l);
     118             : 
     119             :     // accel in body frame due to motor
     120     1410742 :     accel_body = Vector3f(accel_vf_x*cos(theta), 0, -accel_vf_x*sin(theta));
     121             : 
     122             :     // update angular velocity (theta is re-derived from the attitude each
     123             :     // step via the DCM below, so it is not integrated here)
     124     1410742 :     ang_vel += angular_accel_bf_y * delta_time;
     125             : 
     126     1410742 :     gyro = Vector3f(0, ang_vel, radians(yaw_rate));
     127             : 
     128             :     // update attitude
     129     1410742 :     dcm.rotate(gyro * delta_time);
     130     1410742 :     dcm.normalize();
     131             : 
     132             :     // add in accel due to direction change
     133     1410742 :     accel_body.y += radians(yaw_rate) * velocity_vf_x;
     134             : 
     135             :     // update x velocity in vehicle frame
     136     1410742 :     velocity_vf_x += accel_vf_x * delta_time;
     137             : 
     138             :     // now in earth frame
     139     1410742 :     Vector3f accel_earth = dcm * accel_body;
     140     1410742 :     accel_earth += Vector3f(0, 0, GRAVITY_MSS);
     141             : 
     142             :     // we are on the ground, so our vertical accel is zero
     143     1410742 :     accel_earth.z = 0;
     144             : 
     145     2237691 :     if (!hal.util->get_soft_armed() &&
     146      826949 :         p < radians(2)) {
     147             :         // reset to vertical when not armed for faster testing
     148      826949 :         accel_earth.zero();
     149      826949 :         velocity_ef.zero();
     150      826949 :         velocity_vf_x =0;
     151      826949 :         gyro[1] = 0; // no pitch rate
     152      826949 :         if (y < radians(2)) {
     153             :             // no rates at all:
     154      820618 :             dcm.identity();
     155      820618 :             gyro.zero();
     156             :         }
     157             :     }
     158             : 
     159             :     // work out acceleration as seen by the accelerometers. It sees the kinematic
     160             :     // acceleration (ie. real movement), plus gravity
     161     1410742 :     accel_body += dcm.transposed() * (Vector3f(0, 0, -GRAVITY_MSS));
     162             : 
     163             :     // new velocity vector
     164     1410742 :     velocity_ef += accel_earth * delta_time;
     165             : 
     166             :     // new position vector
     167     1410742 :     position += (velocity_ef * delta_time).todouble();
     168             : 
     169             :     // neglect roll
     170     1410742 :     dcm.to_euler(&r, &p, &y);
     171     1410742 :     dcm.from_euler(0.0f, p, y);
     172     1410742 :     use_smoothing = true;
     173             : 
     174             :     // update lat/lon/altitude
     175     1410742 :     update_position();
     176     1410742 :     time_advance();
     177             : 
     178             :     // update magnetic field
     179     1410742 :     update_mag_field_bf();
     180             : 
     181     1410742 :     update_battery();
     182     1410742 : }
     183             : 
     184             : }// namespace SITL

Generated by: LCOV version 1.14