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