Daniel Petti | aece37f | 2014-10-25 17:13:44 -0700 | [diff] [blame^] | 1 | #include <inttypes.h> |
| 2 | |
| 3 | #include "aos/linux_code/init.h" |
| 4 | #include "aos/common/logging/logging.h" |
| 5 | #include "aos/common/util/wrapping_counter.h" |
| 6 | #include "aos/common/time.h" |
| 7 | #include "aos/common/logging/queue_logging.h" |
| 8 | #include "aos/common/controls/output_check.q.h" |
| 9 | |
| 10 | #include "bbb/sensor_reader.h" |
| 11 | |
| 12 | #include "bot3/control_loops/drivetrain/drivetrain.q.h" |
| 13 | #include "bot3/control_loops/drivetrain/drivetrain_constants.h" |
| 14 | #include "bot3/queues/to_log.q.h" |
| 15 | #include "frc971/queues/other_sensors.q.h" |
| 16 | #include "frc971/shifter_hall_effect.h" |
| 17 | |
| 18 | #ifndef M_PI |
| 19 | #define M_PI 3.14159265358979323846 |
| 20 | #endif |
| 21 | |
| 22 | using ::bot3::control_loops::drivetrain; |
| 23 | using ::frc971::sensors::gyro_reading; |
| 24 | using ::aos::util::WrappingCounter; |
| 25 | |
| 26 | namespace bot3 { |
| 27 | namespace { |
| 28 | |
| 29 | // TODO (danielp): Find out the real ratios here. |
| 30 | double drivetrain_translate(int32_t in) { |
| 31 | return static_cast<double>(in) |
| 32 | / (256.0 /*cpr*/ * 4.0 /*quad*/) |
| 33 | * (18.0 / 50.0 /*output stage*/) * (56.0 / 30.0 /*encoder gears*/) |
| 34 | // * constants::GetValues().drivetrain_encoder_ratio |
| 35 | * (3.5 /*wheel diameter*/ * 2.54 / 100.0 * M_PI); |
| 36 | } |
| 37 | |
| 38 | static const double kVcc = 5.15; |
| 39 | |
| 40 | // Translates values from the ADC into voltage. |
| 41 | double adc_translate(uint16_t in) { |
| 42 | if (false) { |
| 43 | // This is the simple theoretical math. |
| 44 | static const uint16_t kMaximumValue = 0x3FF; |
| 45 | static const double kR1 = 5, kR2 = 6.65; |
| 46 | const double raw = |
| 47 | (kVcc * static_cast<double>(in) / static_cast<double>(kMaximumValue)); |
| 48 | return (raw * (kR1 + kR2) - (kVcc / 2) * kR2) / kR1; |
| 49 | } else { |
| 50 | // This is from a linear regression calculated with some actual data points. |
| 51 | static const double kM = 0.012133, kB = -3.6813; |
| 52 | return static_cast<double>(in) * kM + kB; |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | double battery_translate(uint16_t in_high, uint16_t in_low) { |
| 57 | const double high = adc_translate(in_high), low = adc_translate(in_low); |
| 58 | static const double kDividerBig = 5.55, kDividerSmall = 2.66; |
| 59 | return (high - low) * (kDividerBig + kDividerSmall) / kDividerSmall + |
| 60 | kDividerBig / kDividerSmall * kVcc; |
| 61 | } |
| 62 | |
| 63 | double gyro_translate(int64_t in) { |
| 64 | return in / 16.0 / 1000.0 / (180.0 / M_PI); |
| 65 | } |
| 66 | |
| 67 | double hall_translate(const ::frc971::constants::ShifterHallEffect &k, uint16_t in_low, |
| 68 | uint16_t in_high) { |
| 69 | const double low_ratio = |
| 70 | 0.5 * (in_low - static_cast<double>(k.low_gear_low)) / |
| 71 | static_cast<double>(k.low_gear_middle - k.low_gear_low); |
| 72 | const double high_ratio = |
| 73 | 0.5 + 0.5 * (in_high - static_cast<double>(k.high_gear_middle)) / |
| 74 | static_cast<double>(k.high_gear_high - k.high_gear_middle); |
| 75 | |
| 76 | // Return low when we are below 1/2, and high when we are above 1/2. |
| 77 | if (low_ratio + high_ratio < 1.0) { |
| 78 | return low_ratio; |
| 79 | } else { |
| 80 | return high_ratio; |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | void PacketReceived(const ::bbb::DataStruct *data, |
| 85 | const ::aos::time::Time &cape_timestamp) { |
| 86 | ::aos::time::TimeFreezer time_freezer; |
| 87 | |
| 88 | ::frc971::logging_structs::CapeReading reading_to_log( |
| 89 | cape_timestamp, static_cast<uint16_t>(sizeof(*data)), |
| 90 | data->main.low_left_drive_hall, data->main.high_left_drive_hall, |
| 91 | data->main.low_right_drive_hall, data->main.high_right_drive_hall); |
| 92 | LOG_STRUCT(DEBUG, "cape reading", reading_to_log); |
| 93 | bool bad_gyro; |
| 94 | // TODO(brians): Switch to LogInterval for these things. |
| 95 | if (data->uninitialized_gyro) { |
| 96 | LOG(DEBUG, "uninitialized gyro\n"); |
| 97 | bad_gyro = true; |
| 98 | } else if (data->zeroing_gyro) { |
| 99 | LOG(DEBUG, "zeroing gyro\n"); |
| 100 | bad_gyro = true; |
| 101 | } else if (data->bad_gyro) { |
| 102 | LOG(ERROR, "bad gyro\n"); |
| 103 | bad_gyro = true; |
| 104 | } else if (data->old_gyro_reading) { |
| 105 | LOG(WARNING, "old/bad gyro reading\n"); |
| 106 | bad_gyro = true; |
| 107 | } else { |
| 108 | bad_gyro = false; |
| 109 | } |
| 110 | |
| 111 | if (!bad_gyro) { |
| 112 | gyro_reading.MakeWithBuilder() |
| 113 | .angle(gyro_translate(data->gyro_angle)) |
| 114 | .Send(); |
| 115 | } |
| 116 | |
| 117 | if (data->analog_errors != 0) { |
| 118 | LOG(WARNING, "%" PRIu8 " analog errors\n", data->analog_errors); |
| 119 | } |
| 120 | |
| 121 | if (data->main.output_check_pulse_length != 0) { |
| 122 | auto message = ::aos::controls::output_check_received.MakeMessage(); |
| 123 | // TODO(brians): Fix this math to match what the cRIO actually does. |
| 124 | // It's close but not quite right. |
| 125 | message->pulse_length = |
| 126 | static_cast<double>(data->main.output_check_pulse_length) / 10000.0; |
| 127 | if (message->pulse_length > 2.7) { |
| 128 | LOG(WARNING, "insane PWM pulse length %fms\n", message->pulse_length); |
| 129 | } else { |
| 130 | message->pwm_value = (message->pulse_length - 0.5) / 2.0 * 255.0 + 0.5; |
| 131 | LOG_STRUCT(DEBUG, "received", *message); |
| 132 | message.Send(); |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | drivetrain.position.MakeWithBuilder() |
| 137 | .right_encoder(drivetrain_translate(data->main.right_drive)) |
| 138 | .left_encoder(-drivetrain_translate(data->main.left_drive)) |
| 139 | .left_shifter_position(hall_translate(control_loops::kBot3LeftDriveShifter, |
| 140 | data->main.low_left_drive_hall, |
| 141 | data->main.high_left_drive_hall)) |
| 142 | .right_shifter_position(hall_translate(control_loops::kBot3RightDriveShifter, |
| 143 | data->main.low_right_drive_hall, |
| 144 | data->main.high_right_drive_hall)) |
| 145 | .battery_voltage(battery_translate(data->main.battery_voltage_high, |
| 146 | data->main.battery_voltage_low)) |
| 147 | .Send(); |
| 148 | } |
| 149 | |
| 150 | } // namespace |
| 151 | } // namespace bot3 |
| 152 | |
| 153 | int main() { |
| 154 | ::aos::Init(::bbb::SensorReader::kRelativePriority); |
| 155 | ::bbb::SensorReader reader("comp"); |
| 156 | while (true) { |
| 157 | ::bot3::PacketReceived(reader.ReadPacket(), reader.GetCapeTimestamp()); |
| 158 | } |
| 159 | ::aos::Cleanup(); |
| 160 | } |