Add a translator for imu can values
This provides a translation layer between the raw CAN frames from the
IMU and a flatbuffer filled with the information being sent.
Signed-off-by: Maxwell Henderson <mxwhenderson@gmail.com>
Change-Id: Ifd295e7353da8ca622e334569ed58dcae0d59a70
diff --git a/frc971/imu_fdcan/BUILD b/frc971/imu_fdcan/BUILD
index deb6a7e..b47f367 100644
--- a/frc971/imu_fdcan/BUILD
+++ b/frc971/imu_fdcan/BUILD
@@ -1,3 +1,4 @@
+load("//aos:config.bzl", "aos_config")
load("//aos/flatbuffers:generate.bzl", "static_flatbuffer")
static_flatbuffer(
@@ -5,3 +6,69 @@
srcs = ["dual_imu.fbs"],
visibility = ["//visibility:public"],
)
+
+static_flatbuffer(
+ name = "can_translator_status_fbs",
+ srcs = ["can_translator_status.fbs"],
+ visibility = ["//visibility:public"],
+)
+
+cc_binary(
+ name = "can_translator",
+ srcs = ["can_translator_main.cc"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":can_translator_lib",
+ "//aos:init",
+ "//aos/events:shm_event_loop",
+ ],
+)
+
+cc_library(
+ name = "can_translator_lib",
+ srcs = [
+ "can_translator_lib.cc",
+ ],
+ hdrs = [
+ "can_translator_lib.h",
+ ],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":can_translator_status_fbs",
+ ":dual_imu_fbs",
+ "//aos/events:event_loop",
+ "//frc971/can_logger:can_logging_fbs",
+ ],
+)
+
+cc_test(
+ name = "can_translator_lib_test",
+ srcs = [
+ "can_translator_lib_test.cc",
+ ],
+ data = [
+ ":can_translator_test_config",
+ ],
+ deps = [
+ ":can_translator_lib",
+ ":can_translator_status_fbs",
+ ":dual_imu_fbs",
+ "//aos/events:simulated_event_loop",
+ "//aos/testing:googletest",
+ "//frc971/can_logger:can_logging_fbs",
+ "@com_github_google_glog//:glog",
+ ],
+)
+
+aos_config(
+ name = "can_translator_test_config",
+ src = "can_translator_test_config_source.json",
+ flatbuffers = [
+ "//aos/logging:log_message_fbs",
+ ":dual_imu_fbs",
+ ":can_translator_status_fbs",
+ "//frc971/can_logger:can_logging_fbs",
+ "//aos/events:event_loop_fbs",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+)
diff --git a/frc971/imu_fdcan/can_translator_lib.cc b/frc971/imu_fdcan/can_translator_lib.cc
new file mode 100644
index 0000000..b5e5576
--- /dev/null
+++ b/frc971/imu_fdcan/can_translator_lib.cc
@@ -0,0 +1,125 @@
+#include "frc971/imu_fdcan/can_translator_lib.h"
+
+using frc971::imu_fdcan::CANTranslator;
+
+constexpr std::size_t kCanFrameSize = 64;
+constexpr int kImuCanId = 1;
+
+CANTranslator::CANTranslator(aos::EventLoop *event_loop,
+ std::string_view canframe_channel)
+ : dual_imu_sender_(
+ event_loop->MakeSender<frc971::imu::DualImuStatic>("/imu")),
+ can_translator_status_sender_(
+ event_loop->MakeSender<frc971::imu::CanTranslatorStatusStatic>(
+ "/imu")) {
+ // TODO(max): Update this with a proper priority
+ event_loop->SetRuntimeRealtimePriority(15);
+
+ event_loop->MakeWatcher(
+ canframe_channel, [this](const frc971::can_logger::CanFrame &can_frame) {
+ if (can_frame.data()->size() / sizeof(uint8_t) != 64) {
+ invalid_packet_count_++;
+ }
+
+ if (can_frame.can_id() != kImuCanId) {
+ invalid_can_id_count_++;
+ return;
+ }
+
+ if (can_frame.data()->size() / sizeof(uint8_t) == 64) {
+ valid_packet_count_++;
+ HandleFrame(&can_frame);
+ }
+ });
+
+ event_loop->AddPhasedLoop(
+ [this](int) {
+ aos::Sender<frc971::imu::CanTranslatorStatusStatic>::StaticBuilder
+ status_builder = can_translator_status_sender_.MakeStaticBuilder();
+
+ status_builder->set_valid_packet_count(valid_packet_count_);
+ status_builder->set_invalid_packet_count(invalid_packet_count_);
+ status_builder->set_invalid_can_id_count(invalid_can_id_count_);
+
+ status_builder.CheckOk(status_builder.Send());
+ },
+ std::chrono::milliseconds(100));
+}
+
+// Gets the data from the span and iterates it to the next section of bytes.
+template <typename T>
+T GetAndPopDataFromBuffer(std::span<const uint8_t> &span) {
+ T value = 0;
+
+ std::memcpy(&value, span.data(), sizeof(T));
+ span = span.subspan(sizeof(T));
+
+ return value;
+}
+
+// Values from the data field mapping table in
+// https://docs.google.com/document/d/12AJUruW7DZ2pIrDzTyPC0qqFoia4QOSVlax6Jd7m4H0/edit?usp=sharing
+void CANTranslator::HandleFrame(const frc971::can_logger::CanFrame *can_frame) {
+ aos::Sender<frc971::imu::DualImuStatic>::StaticBuilder dual_imu_builder =
+ dual_imu_sender_.MakeStaticBuilder();
+
+ std::span can_data(can_frame->data()->data(), kCanFrameSize);
+
+ frc971::imu::SingleImuStatic *murata = dual_imu_builder->add_murata();
+
+ auto *murata_chip_states = murata->add_chip_states();
+ frc971::imu::ChipStateStatic *murata_uno_chip_state =
+ murata_chip_states->emplace_back();
+ frc971::imu::ChipStateStatic *murata_due_chip_state =
+ murata_chip_states->emplace_back();
+
+ frc971::imu::SingleImuStatic *tdk = dual_imu_builder->add_tdk();
+
+ auto tdk_chip_states = tdk->add_chip_states();
+ frc971::imu::ChipStateStatic *tdk_chip_state =
+ tdk_chip_states->emplace_back();
+
+ dual_imu_builder->set_board_timestamp_us(
+ GetAndPopDataFromBuffer<uint32_t>(can_data));
+
+ dual_imu_builder->set_packet_counter(
+ GetAndPopDataFromBuffer<uint16_t>(can_data));
+
+ tdk_chip_state->set_counter(GetAndPopDataFromBuffer<uint16_t>(can_data));
+ murata_uno_chip_state->set_counter(
+ GetAndPopDataFromBuffer<uint16_t>(can_data));
+ murata_due_chip_state->set_counter(
+ GetAndPopDataFromBuffer<uint16_t>(can_data));
+
+ tdk->set_accelerometer_x(GetAndPopDataFromBuffer<float>(can_data));
+ tdk->set_accelerometer_y(GetAndPopDataFromBuffer<float>(can_data));
+ tdk->set_accelerometer_z(GetAndPopDataFromBuffer<float>(can_data));
+
+ tdk->set_gyro_x(GetAndPopDataFromBuffer<float>(can_data));
+ tdk->set_gyro_y(GetAndPopDataFromBuffer<float>(can_data));
+ tdk->set_gyro_z(GetAndPopDataFromBuffer<float>(can_data));
+
+ murata->set_accelerometer_x(GetAndPopDataFromBuffer<float>(can_data));
+ murata->set_accelerometer_y(GetAndPopDataFromBuffer<float>(can_data));
+ murata->set_accelerometer_z(GetAndPopDataFromBuffer<float>(can_data));
+
+ murata->set_gyro_x(GetAndPopDataFromBuffer<float>(can_data));
+ murata->set_gyro_y(GetAndPopDataFromBuffer<float>(can_data));
+ murata->set_gyro_z(GetAndPopDataFromBuffer<float>(can_data));
+
+ tdk_chip_state->set_temperature(GetAndPopDataFromBuffer<uint8_t>(can_data));
+ murata_uno_chip_state->set_temperature(
+ GetAndPopDataFromBuffer<uint8_t>(can_data));
+ murata_due_chip_state->set_temperature(
+ GetAndPopDataFromBuffer<uint8_t>(can_data));
+
+ murata_uno_chip_state->set_max_counter(std::numeric_limits<uint16_t>::max());
+ murata_due_chip_state->set_max_counter(std::numeric_limits<uint16_t>::max());
+ tdk_chip_state->set_max_counter(std::numeric_limits<uint16_t>::max());
+ dual_imu_builder->set_max_packet_counter(
+ std::numeric_limits<uint16_t>::max());
+
+ dual_imu_builder->set_kernel_timestamp(can_frame->monotonic_timestamp_ns());
+
+ dual_imu_builder.CheckOk(dual_imu_builder.Send());
+}
diff --git a/frc971/imu_fdcan/can_translator_lib.h b/frc971/imu_fdcan/can_translator_lib.h
new file mode 100644
index 0000000..47a3638
--- /dev/null
+++ b/frc971/imu_fdcan/can_translator_lib.h
@@ -0,0 +1,30 @@
+#ifndef FRC971_IMU_FDCAN_CAN_TRANSLATOR_LIB_H_
+#define FRC971_IMU_FDCAN_CAN_TRANSLATOR_LIB_H_
+#include "aos/events/event_loop.h"
+#include "frc971/can_logger/can_logging_generated.h"
+#include "frc971/imu_fdcan/can_translator_status_static.h"
+#include "frc971/imu_fdcan/dual_imu_static.h"
+
+namespace frc971::imu_fdcan {
+
+// Translates the CanFrames from the IMU into a DualIMU message based on the
+// spec defined in this doc:
+// https://docs.google.com/document/d/12AJUruW7DZ2pIrDzTyPC0qqFoia4QOSVlax6Jd7m4H0/edit?usp=sharing
+class CANTranslator {
+ public:
+ CANTranslator(aos::EventLoop *event_loop, std::string_view canframe_channel);
+
+ private:
+ void HandleFrame(const can_logger::CanFrame *can_frame);
+
+ aos::Sender<imu::DualImuStatic> dual_imu_sender_;
+ aos::Sender<imu::CanTranslatorStatusStatic> can_translator_status_sender_;
+
+ uint64_t valid_packet_count_ = 0;
+ uint64_t invalid_packet_count_ = 0;
+ uint64_t invalid_can_id_count_ = 0;
+};
+
+} // namespace frc971::imu_fdcan
+
+#endif // FRC971_IMU_FDCAN_CAN_TRANSLATOR_LIB_H_
diff --git a/frc971/imu_fdcan/can_translator_lib_test.cc b/frc971/imu_fdcan/can_translator_lib_test.cc
new file mode 100644
index 0000000..ce9dd59
--- /dev/null
+++ b/frc971/imu_fdcan/can_translator_lib_test.cc
@@ -0,0 +1,191 @@
+#include "frc971/imu_fdcan/can_translator_lib.h"
+
+#include "glog/logging.h"
+#include "gtest/gtest.h"
+
+#include "aos/events/simulated_event_loop.h"
+#include "frc971/can_logger/can_logging_static.h"
+#include "frc971/imu_fdcan/can_translator_status_generated.h"
+#include "frc971/imu_fdcan/dual_imu_generated.h"
+
+class CANTranslatorTest : public ::testing::Test {
+ public:
+ CANTranslatorTest()
+ : config_(aos::configuration::ReadConfig(
+ "frc971/imu_fdcan/can_translator_test_config.json")),
+ event_loop_factory_(&config_.message()),
+ can_translator_event_loop_(
+ event_loop_factory_.MakeEventLoop("can_translator")),
+ can_frame_event_loop_(event_loop_factory_.MakeEventLoop("can_frame")),
+ dual_imu_fetcher_(
+ can_translator_event_loop_->MakeFetcher<frc971::imu::DualImu>(
+ "/imu")),
+ can_translator_status_fetcher_(
+ can_translator_event_loop_
+ ->MakeFetcher<frc971::imu::CanTranslatorStatus>("/imu")),
+ can_frame_sender_(
+ can_frame_event_loop_
+ ->MakeSender<frc971::can_logger::CanFrameStatic>("/can")),
+ can_translator_(can_translator_event_loop_.get(), "/can") {}
+
+ protected:
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
+ aos::SimulatedEventLoopFactory event_loop_factory_;
+
+ std::unique_ptr<aos::EventLoop> can_translator_event_loop_;
+ std::unique_ptr<aos::EventLoop> can_frame_event_loop_;
+
+ aos::Fetcher<frc971::imu::DualImu> dual_imu_fetcher_;
+ aos::Fetcher<frc971::imu::CanTranslatorStatus> can_translator_status_fetcher_;
+
+ aos::Sender<frc971::can_logger::CanFrameStatic> can_frame_sender_;
+
+ frc971::imu_fdcan::CANTranslator can_translator_;
+};
+
+TEST_F(CANTranslatorTest, CheckValidFrame) {
+ can_frame_event_loop_->OnRun([this] {
+ aos::Sender<frc971::can_logger::CanFrameStatic>::StaticBuilder
+ can_frame_builder = can_frame_sender_.MakeStaticBuilder();
+
+ can_frame_builder->set_can_id(1);
+ can_frame_builder->set_monotonic_timestamp_ns(100);
+ auto can_data = can_frame_builder->add_data();
+ CHECK(can_data->reserve(sizeof(uint8_t) * 64));
+
+ CHECK(can_data->emplace_back(226));
+ CHECK(can_data->emplace_back(100));
+ CHECK(can_data->emplace_back(108));
+ CHECK(can_data->emplace_back(8));
+ CHECK(can_data->emplace_back(152));
+ CHECK(can_data->emplace_back(40));
+ CHECK(can_data->emplace_back(202));
+ CHECK(can_data->emplace_back(121));
+ CHECK(can_data->emplace_back(202));
+ CHECK(can_data->emplace_back(121));
+ CHECK(can_data->emplace_back(202));
+ CHECK(can_data->emplace_back(121));
+ CHECK(can_data->emplace_back(85));
+ CHECK(can_data->emplace_back(85));
+ CHECK(can_data->emplace_back(81));
+ CHECK(can_data->emplace_back(189));
+ CHECK(can_data->emplace_back(0));
+ CHECK(can_data->emplace_back(0));
+ CHECK(can_data->emplace_back(8));
+ CHECK(can_data->emplace_back(189));
+ CHECK(can_data->emplace_back(85));
+ CHECK(can_data->emplace_back(213));
+ CHECK(can_data->emplace_back(127));
+ CHECK(can_data->emplace_back(191));
+ CHECK(can_data->emplace_back(12));
+ CHECK(can_data->emplace_back(189));
+ CHECK(can_data->emplace_back(34));
+ CHECK(can_data->emplace_back(187));
+ CHECK(can_data->emplace_back(255));
+ CHECK(can_data->emplace_back(219));
+ CHECK(can_data->emplace_back(220));
+ CHECK(can_data->emplace_back(59));
+ CHECK(can_data->emplace_back(147));
+ CHECK(can_data->emplace_back(173));
+ CHECK(can_data->emplace_back(5));
+ CHECK(can_data->emplace_back(61));
+ CHECK(can_data->emplace_back(88));
+ CHECK(can_data->emplace_back(68));
+ CHECK(can_data->emplace_back(205));
+ CHECK(can_data->emplace_back(188));
+ CHECK(can_data->emplace_back(230));
+ CHECK(can_data->emplace_back(92));
+ CHECK(can_data->emplace_back(24));
+ CHECK(can_data->emplace_back(189));
+ CHECK(can_data->emplace_back(235));
+ CHECK(can_data->emplace_back(1));
+ CHECK(can_data->emplace_back(127));
+ CHECK(can_data->emplace_back(191));
+ CHECK(can_data->emplace_back(210));
+ CHECK(can_data->emplace_back(7));
+ CHECK(can_data->emplace_back(34));
+ CHECK(can_data->emplace_back(54));
+ CHECK(can_data->emplace_back(86));
+ CHECK(can_data->emplace_back(103));
+ CHECK(can_data->emplace_back(133));
+ CHECK(can_data->emplace_back(186));
+ CHECK(can_data->emplace_back(100));
+ CHECK(can_data->emplace_back(205));
+ CHECK(can_data->emplace_back(101));
+ CHECK(can_data->emplace_back(185));
+ CHECK(can_data->emplace_back(29));
+ CHECK(can_data->emplace_back(26));
+ CHECK(can_data->emplace_back(26));
+ CHECK(can_data->emplace_back(0));
+
+ can_frame_builder.CheckOk(can_frame_builder.Send());
+ });
+
+ event_loop_factory_.RunFor(std::chrono::milliseconds(200));
+
+ ASSERT_TRUE(can_translator_status_fetcher_.Fetch());
+ ASSERT_TRUE(dual_imu_fetcher_.Fetch());
+
+ ASSERT_FALSE(can_translator_status_fetcher_->invalid_packet_count() > 0);
+ ASSERT_FALSE(can_translator_status_fetcher_->invalid_can_id_count() > 0);
+ EXPECT_EQ(can_translator_status_fetcher_->valid_packet_count(), 1);
+
+ EXPECT_EQ(dual_imu_fetcher_->board_timestamp_us(), 141321442);
+ EXPECT_EQ(dual_imu_fetcher_->packet_counter(), 10392);
+
+ EXPECT_NEAR(dual_imu_fetcher_->murata()->gyro_x(), 2.41444e-06, 0.00001);
+ EXPECT_NEAR(dual_imu_fetcher_->murata()->gyro_y(), -0.00101779, 0.00001);
+ EXPECT_NEAR(dual_imu_fetcher_->murata()->gyro_z(), -0.000219157, 0.00001);
+
+ EXPECT_NEAR(dual_imu_fetcher_->murata()->accelerometer_x(), -0.025057,
+ 0.00001);
+ EXPECT_NEAR(dual_imu_fetcher_->murata()->accelerometer_y(), -0.037198,
+ 0.00001);
+ EXPECT_NEAR(dual_imu_fetcher_->murata()->accelerometer_z(), -0.996123,
+ 0.00001);
+
+ EXPECT_EQ(dual_imu_fetcher_->murata()->chip_states()->Get(0)->counter(),
+ 31178);
+ EXPECT_EQ(dual_imu_fetcher_->murata()->chip_states()->Get(0)->temperature(),
+ 26);
+
+ EXPECT_EQ(dual_imu_fetcher_->murata()->chip_states()->Get(1)->counter(),
+ 31178);
+ EXPECT_EQ(dual_imu_fetcher_->murata()->chip_states()->Get(1)->temperature(),
+ 26);
+
+ EXPECT_NEAR(dual_imu_fetcher_->tdk()->gyro_x(), -0.00248319, 0.00001);
+ EXPECT_NEAR(dual_imu_fetcher_->tdk()->gyro_y(), 0.00674009, 0.00001);
+ EXPECT_NEAR(dual_imu_fetcher_->tdk()->gyro_z(), 0.0326362, 0.00001);
+
+ EXPECT_NEAR(dual_imu_fetcher_->tdk()->accelerometer_x(), -0.0511068, 0.00001);
+ EXPECT_NEAR(dual_imu_fetcher_->tdk()->accelerometer_y(), -0.0332031, 0.00001);
+ EXPECT_NEAR(dual_imu_fetcher_->tdk()->accelerometer_z(), -0.999349, 0.00001);
+
+ EXPECT_EQ(dual_imu_fetcher_->tdk()->chip_states()->Get(0)->counter(), 31178);
+ EXPECT_EQ(dual_imu_fetcher_->tdk()->chip_states()->Get(0)->temperature(), 29);
+}
+
+TEST_F(CANTranslatorTest, CheckInvalidFrame) {
+ can_frame_event_loop_->OnRun([this] {
+ aos::Sender<frc971::can_logger::CanFrameStatic>::StaticBuilder
+ can_frame_builder = can_frame_sender_.MakeStaticBuilder();
+
+ can_frame_builder->set_can_id(2);
+ can_frame_builder->set_monotonic_timestamp_ns(100);
+ auto can_data = can_frame_builder->add_data();
+ CHECK(can_data->reserve(sizeof(uint8_t) * 1));
+
+ CHECK(can_data->emplace_back(0));
+
+ can_frame_builder.CheckOk(can_frame_builder.Send());
+ });
+
+ event_loop_factory_.RunFor(std::chrono::milliseconds(200));
+
+ ASSERT_TRUE(can_translator_status_fetcher_.Fetch());
+ ASSERT_FALSE(dual_imu_fetcher_.Fetch());
+
+ EXPECT_EQ(can_translator_status_fetcher_->invalid_packet_count(), 1);
+ EXPECT_EQ(can_translator_status_fetcher_->invalid_can_id_count(), 1);
+}
diff --git a/frc971/imu_fdcan/can_translator_main.cc b/frc971/imu_fdcan/can_translator_main.cc
new file mode 100644
index 0000000..fdb7107
--- /dev/null
+++ b/frc971/imu_fdcan/can_translator_main.cc
@@ -0,0 +1,22 @@
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "frc971/imu_fdcan/can_translator_lib.h"
+
+DEFINE_string(channel, "/can", "The CAN channel to use");
+
+using frc971::imu_fdcan::CANTranslator;
+
+int main(int argc, char **argv) {
+ ::aos::InitGoogle(&argc, &argv);
+
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig("aos_config.json");
+
+ ::aos::ShmEventLoop event_loop(&config.message());
+
+ CANTranslator translator(&event_loop, FLAGS_channel);
+
+ event_loop.Run();
+
+ return 0;
+}
diff --git a/frc971/imu_fdcan/can_translator_status.fbs b/frc971/imu_fdcan/can_translator_status.fbs
new file mode 100644
index 0000000..232f3ba
--- /dev/null
+++ b/frc971/imu_fdcan/can_translator_status.fbs
@@ -0,0 +1,12 @@
+namespace frc971.imu;
+
+table CanTranslatorStatus {
+ // Number of times we've gotten valid packets at 64 bytes
+ valid_packet_count: uint64 (id: 0);
+ // Number of times we've gotten packets under 64 bytes
+ invalid_packet_count: uint64 (id: 1);
+ // Number of times we've gotten an invalid can id
+ invalid_can_id_count: uint64 (id: 2);
+}
+
+root_type CanTranslatorStatus;
diff --git a/frc971/imu_fdcan/can_translator_test_config_source.json b/frc971/imu_fdcan/can_translator_test_config_source.json
new file mode 100644
index 0000000..e82c87d
--- /dev/null
+++ b/frc971/imu_fdcan/can_translator_test_config_source.json
@@ -0,0 +1,28 @@
+{
+ "channels": [
+ {
+ "name": "/aos",
+ "type": "aos.timing.Report"
+ },
+ {
+ "name": "/aos",
+ "type": "aos.logging.LogMessageFbs",
+ "frequency": 400
+ },
+ {
+ "name": "/imu",
+ "type": "frc971.imu.DualImu",
+ "frequency": 200
+ },
+ {
+ "name": "/can",
+ "type": "frc971.can_logger.CanFrame",
+ "frequency": 200
+ },
+ {
+ "name": "/imu",
+ "type": "frc971.imu.CanTranslatorStatus",
+ "frequency": 100
+ },
+ ]
+}
diff --git a/frc971/imu_fdcan/dual_imu.fbs b/frc971/imu_fdcan/dual_imu.fbs
index 7236acf..88f02df 100644
--- a/frc971/imu_fdcan/dual_imu.fbs
+++ b/frc971/imu_fdcan/dual_imu.fbs
@@ -1,5 +1,7 @@
namespace frc971.imu;
+attribute "static_length";
+
table ChipState {
// Counter indicating how many samples have been taken on this IMU.
// Note that because averaging occurs on the microcontroller, this
@@ -28,14 +30,14 @@
accelerometer_z:double (id: 5);
// State for the individual ASIC(s) for this IMU.
- chip_states:[ChipState] (id: 6);
+ chip_states:[ChipState] (id: 6, static_length: 2);
}
table DualImu {
- // Timestamp from the board corresponding to these samples.
+ // Timestamp from the board corresponding to these samples in nanoseconds.
// Future changes may lead us to add per-chip timestamps, but for now
// we treat them as being sampled at the same time.
- board_timestamp_us:uint32 (id: 0);
+ kernel_timestamp:uint64 (id: 0);
// Packet counter that should increment by 1 for every incoming packet.
packet_counter:uint64 (id: 1);
// Value at which the packet counter wraps, such that
@@ -45,6 +47,8 @@
murata:SingleImu (id: 3);
// Readings associated with the TDK IMU.
tdk:SingleImu (id: 4);
+ // Timestamp from the IMU in microseconds
+ board_timestamp_us:uint32 (id: 5);
}
root_type DualImu;
diff --git a/y2024/BUILD b/y2024/BUILD
index d8d0db7..45ff96c 100644
--- a/y2024/BUILD
+++ b/y2024/BUILD
@@ -71,6 +71,7 @@
],
start_binaries = [
"//aos/events/logging:logger_main",
+ "//frc971/imu_fdcan:can_translator",
"//aos/network:message_bridge_client",
"//aos/network:message_bridge_server",
"//aos/network:web_proxy_main",
@@ -111,6 +112,8 @@
flatbuffers = [
"//aos/network:message_bridge_client_fbs",
"//aos/network:message_bridge_server_fbs",
+ "//frc971/imu_fdcan:dual_imu_fbs",
+ "//frc971/imu_fdcan:can_translator_status_fbs",
"//y2024/constants:constants_fbs",
"//frc971/can_logger:can_logging_fbs",
"//aos/network:timestamp_fbs",
diff --git a/y2024/y2024_imu.json b/y2024/y2024_imu.json
index 5dd4710..6a611ff 100644
--- a/y2024/y2024_imu.json
+++ b/y2024/y2024_imu.json
@@ -160,6 +160,22 @@
"max_size": 200
},
{
+ "name": "/imu",
+ "type": "frc971.imu.DualImu",
+ "source_node": "imu",
+ "frequency": 1100,
+ "num_senders": 1,
+ "max_size": 496
+ },
+ {
+ "name": "/imu",
+ "type": "frc971.imu.CanTranslatorStatus",
+ "source_node": "imu",
+ "frequency": 1000,
+ "num_senders": 1,
+ "max_size": 200
+ },
+ {
"name": "/can/cana",
"type": "frc971.can_logger.CanFrame",
"source_node": "imu",
@@ -260,6 +276,17 @@
"imu"
]
},
+ // TODO(max): Update the channel value with whatever channel the IMU is on.
+ {
+ "name": "can_translator",
+ "executable_name": "can_translator",
+ "args": [
+ "--channel=/can/canb"
+ ],
+ "nodes": [
+ "imu"
+ ]
+ },
{
"name": "web_proxy",
"executable_name": "web_proxy_main",