Merge "Some cleanup of target_mapping"
diff --git a/WORKSPACE b/WORKSPACE
index c603581..0c98e3f 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -251,11 +251,11 @@
load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm", "llvm_toolchain")
-llvm_version = "13.0.0"
+llvm_version = "16.0.3"
llvm(
name = "llvm_k8",
- distribution = "clang+llvm-%s-x86_64-linux-gnu-ubuntu-16.04.tar.xz" % llvm_version,
+ distribution = "clang+llvm-%s-x86_64-linux-gnu-ubuntu-22.04.tar.xz" % llvm_version,
llvm_version = llvm_version,
)
diff --git a/aos/aos_dump.cc b/aos/aos_dump.cc
index 1dbcd44..18d2ce1 100644
--- a/aos/aos_dump.cc
+++ b/aos/aos_dump.cc
@@ -51,8 +51,6 @@
return 0;
}
- uint64_t message_count = 0;
-
aos::monotonic_clock::time_point next_send_time =
aos::monotonic_clock::min_time;
@@ -74,7 +72,6 @@
cli_info.event_loop->MakeRawFetcher(channel);
if (fetcher->Fetch()) {
printer.PrintMessage(channel, fetcher->context());
- ++message_count;
}
}
diff --git a/aos/events/event_loop.h b/aos/events/event_loop.h
index 1ed4337..827dd46 100644
--- a/aos/events/event_loop.h
+++ b/aos/events/event_loop.h
@@ -113,15 +113,15 @@
public:
using SharedSpan = std::shared_ptr<const absl::Span<const uint8_t>>;
- enum class [[nodiscard]] Error{
- // Represents success and no error
- kOk,
+ enum class [[nodiscard]] Error {
+ // Represents success and no error
+ kOk,
- // Error for messages on channels being sent faster than their
- // frequency and channel storage duration allow
- kMessagesSentTooFast,
- // Access to Redzone was attempted in Sender Queue
- kInvalidRedzone,
+ // Error for messages on channels being sent faster than their
+ // frequency and channel storage duration allow
+ kMessagesSentTooFast,
+ // Access to Redzone was attempted in Sender Queue
+ kInvalidRedzone,
};
RawSender(EventLoop *event_loop, const Channel *channel);
diff --git a/aos/events/event_loop_tmpl.h b/aos/events/event_loop_tmpl.h
index 9a5fe19..132da04 100644
--- a/aos/events/event_loop_tmpl.h
+++ b/aos/events/event_loop_tmpl.h
@@ -408,7 +408,8 @@
void set_timing_report(timing::Watcher *watcher);
void ResetReport();
- virtual void Startup(EventLoop *event_loop) = 0;
+ virtual void Construct() = 0;
+ virtual void Startup() = 0;
protected:
const int channel_index_;
diff --git a/aos/events/logging/BUILD b/aos/events/logging/BUILD
index c33606c..a9c8497 100644
--- a/aos/events/logging/BUILD
+++ b/aos/events/logging/BUILD
@@ -183,18 +183,18 @@
target_compatible_with = ["@platforms//os:linux"],
visibility = ["//visibility:public"],
deps = [
- ":file_operations",
":boot_timestamp",
- ":snappy_encoder",
":buffer_encoder",
- ":logger_fbs",
+ ":file_operations",
":log_backend",
- "//aos:sha256",
- "//aos:uuid",
+ ":logger_fbs",
+ ":snappy_encoder",
"//aos:configuration",
- "//aos/containers:error_list",
"//aos:flatbuffer_merge",
"//aos:flatbuffers",
+ "//aos:sha256",
+ "//aos:uuid",
+ "//aos/containers:error_list",
"//aos/containers:resizeable_buffer",
"//aos/events:event_loop",
"//aos/network:remote_message_fbs",
diff --git a/aos/events/logging/logfile_validator.cc b/aos/events/logging/logfile_validator.cc
index 19d11c8..05c881c 100644
--- a/aos/events/logging/logfile_validator.cc
+++ b/aos/events/logging/logfile_validator.cc
@@ -37,12 +37,12 @@
multinode_estimator.set_reboot_found(
[config](distributed_clock::time_point reboot_time,
const std::vector<logger::BootTimestamp> &node_times) {
- LOG(INFO) << "Rebooted at distributed " << reboot_time;
+ VLOG(1) << "Rebooted at distributed " << reboot_time;
size_t node_index = 0;
for (const logger::BootTimestamp &time : node_times) {
- LOG(INFO) << " "
- << config->nodes()->Get(node_index)->name()->string_view()
- << " " << time;
+ VLOG(1) << " "
+ << config->nodes()->Get(node_index)->name()->string_view()
+ << " " << time;
++node_index;
}
});
@@ -94,7 +94,7 @@
// logger on purpose. It loads in *all* the timestamps in 1 go per node,
// ignoring memory usage.
for (const Node *node : configuration::GetNodes(config)) {
- LOG(INFO) << "Reading all data for " << node->name()->string_view();
+ VLOG(1) << "Reading all data for " << node->name()->string_view();
const size_t node_index = configuration::GetNodeIndex(config, node);
TimestampMapper *timestamp_mapper = mappers[node_index].get();
if (timestamp_mapper == nullptr) {
@@ -117,11 +117,11 @@
if (!next_timestamp.has_value() || !next_timestamp.value().has_value()) {
return preempt_destructor(false);
}
- LOG(INFO) << "Starting at:";
+ VLOG(1) << "Starting at:";
for (const Node *node : configuration::GetNodes(config)) {
const size_t node_index = configuration::GetNodeIndex(config, node);
- LOG(INFO) << " " << node->name()->string_view() << " -> "
- << std::get<1>(*next_timestamp.value().value())[node_index].time;
+ VLOG(1) << " " << node->name()->string_view() << " -> "
+ << std::get<1>(*next_timestamp.value().value())[node_index].time;
}
std::vector<monotonic_clock::time_point> just_monotonic(
@@ -148,7 +148,7 @@
std::get<0>(*next_timestamp.value().value()));
}
- LOG(INFO) << "Done";
+ VLOG(1) << "Done";
return preempt_destructor(true);
}
diff --git a/aos/events/logging/multinode_logger_test_lib.cc b/aos/events/logging/multinode_logger_test_lib.cc
index 64dd1cd..9b3e00c 100644
--- a/aos/events/logging/multinode_logger_test_lib.cc
+++ b/aos/events/logging/multinode_logger_test_lib.cc
@@ -544,14 +544,12 @@
}
std::vector<std::tuple<std::string, std::string, int>> result;
- int channel = 0;
for (size_t i = 0; i < counts.size(); ++i) {
if (counts[i] != 0) {
const Channel *channel = config->channels()->Get(i);
result.push_back(std::make_tuple(channel->name()->str(),
channel->type()->str(), counts[i]));
}
- ++channel;
}
return result;
diff --git a/aos/events/shm_event_loop.cc b/aos/events/shm_event_loop.cc
index 3126265..7f06ee0 100644
--- a/aos/events/shm_event_loop.cc
+++ b/aos/events/shm_event_loop.cc
@@ -159,7 +159,7 @@
}
}
- bool FetchNext() { return FetchNextIf(std::ref(should_fetch_)); }
+ bool FetchNext() { return FetchNextIf(should_fetch_); }
bool FetchNextIf(std::function<bool(const Context &)> fn) {
const ipc_lib::LocklessQueueReader::Result read_result =
@@ -192,7 +192,7 @@
return read_result == ipc_lib::LocklessQueueReader::Result::GOOD;
}
- bool Fetch() { return FetchIf(std::ref(should_fetch_)); }
+ bool Fetch() { return FetchIf(should_fetch_); }
Context context() const { return context_; }
@@ -557,10 +557,14 @@
event_loop_->RemoveEvent(&event_);
}
- void Startup(EventLoop *event_loop) override {
+ void Construct() override {
+ event_loop_->CheckCurrentThread();
+ CHECK(RegisterWakeup(event_loop_->runtime_realtime_priority()));
+ }
+
+ void Startup() override {
event_loop_->CheckCurrentThread();
simple_shm_fetcher_.PointAtNextQueueIndex();
- CHECK(RegisterWakeup(event_loop->runtime_realtime_priority()));
}
// Returns true if there is new data available.
@@ -1048,6 +1052,16 @@
if (!CPU_EQUAL(&affinity_, &default_affinity)) {
::aos::SetCurrentThreadAffinity(affinity_);
}
+
+ // Construct the watchers, but don't update the next pointer. This also
+ // cleans up any watchers that previously died, and puts the nonrt work
+ // before going realtime. After this happens, we will start queueing
+ // signals (which may be a bit of extra work to process, but won't cause any
+ // messages to be lost).
+ for (::std::unique_ptr<WatcherState> &watcher : watchers_) {
+ watcher->Construct();
+ }
+
// Now, all the callbacks are setup. Lock everything into memory and go RT.
if (priority_ != 0) {
::aos::InitRT();
@@ -1059,9 +1073,10 @@
set_is_running(true);
// Now that we are realtime (but before the OnRun handlers run), snap the
- // queue index.
+ // queue index pointer to the newest message. This happens in RT so that we
+ // minimize the risk of losing messages.
for (::std::unique_ptr<WatcherState> &watcher : watchers_) {
- watcher->Startup(this);
+ watcher->Startup();
}
// Now that we are RT, run all the OnRun handlers.
diff --git a/aos/events/shm_event_loop_test.cc b/aos/events/shm_event_loop_test.cc
index 6b40b9d..2382f07 100644
--- a/aos/events/shm_event_loop_test.cc
+++ b/aos/events/shm_event_loop_test.cc
@@ -26,12 +26,12 @@
}
// Clean up anything left there before.
- unlink((FLAGS_shm_base + "/test/aos.TestMessage.v5").c_str());
- unlink((FLAGS_shm_base + "/test1/aos.TestMessage.v5").c_str());
- unlink((FLAGS_shm_base + "/test2/aos.TestMessage.v5").c_str());
- unlink((FLAGS_shm_base + "/test2/aos.TestMessage.v5").c_str());
- unlink((FLAGS_shm_base + "/aos/aos.timing.Report.v5").c_str());
- unlink((FLAGS_shm_base + "/aos/aos.logging.LogMessageFbs.v5").c_str());
+ unlink((FLAGS_shm_base + "/test/aos.TestMessage.v6").c_str());
+ unlink((FLAGS_shm_base + "/test1/aos.TestMessage.v6").c_str());
+ unlink((FLAGS_shm_base + "/test2/aos.TestMessage.v6").c_str());
+ unlink((FLAGS_shm_base + "/test2/aos.TestMessage.v6").c_str());
+ unlink((FLAGS_shm_base + "/aos/aos.timing.Report.v6").c_str());
+ unlink((FLAGS_shm_base + "/aos/aos.logging.LogMessageFbs.v6").c_str());
}
~ShmEventLoopTestFactory() { FLAGS_override_hostname = ""; }
diff --git a/aos/events/simulated_event_loop.cc b/aos/events/simulated_event_loop.cc
index 7b84380..5cb67b4 100644
--- a/aos/events/simulated_event_loop.cc
+++ b/aos/events/simulated_event_loop.cc
@@ -100,7 +100,8 @@
void Handle() noexcept override;
- void Startup(EventLoop * /*event_loop*/) override {}
+ void Construct() override {}
+ void Startup() override {}
void Schedule(std::shared_ptr<SimulatedMessage> message);
diff --git a/aos/events/simulated_network_bridge.cc b/aos/events/simulated_network_bridge.cc
index c8a8150..3ed39fa 100644
--- a/aos/events/simulated_network_bridge.cc
+++ b/aos/events/simulated_network_bridge.cc
@@ -234,7 +234,7 @@
// channel within the same callback.
LOG(WARNING) << "Not forwarding message on "
<< configuration::CleanedChannelToString(fetcher_->channel())
- << " because we aren't running. Set at "
+ << " because we aren't running. Sent at "
<< fetcher_->context().monotonic_event_time << " now is "
<< fetch_node_factory_->monotonic_now();
sent_ = true;
diff --git a/aos/ipc_lib/BUILD b/aos/ipc_lib/BUILD
index d67616f..75bbd4d 100644
--- a/aos/ipc_lib/BUILD
+++ b/aos/ipc_lib/BUILD
@@ -193,10 +193,12 @@
"lockless_queue.cc",
"lockless_queue_memory.h",
"memory_mapped_queue.cc",
+ "robust_ownership_tracker.cc",
],
hdrs = [
"lockless_queue.h",
"memory_mapped_queue.h",
+ "robust_ownership_tracker.h",
],
target_compatible_with = ["@platforms//os:linux"],
visibility = ["//visibility:public"],
@@ -210,6 +212,7 @@
"//aos/events:context",
"//aos/time",
"//aos/util:compiler_memory_barrier",
+ "//aos/util:top",
"@com_github_google_glog//:glog",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/types:span",
@@ -250,6 +253,16 @@
)
cc_test(
+ name = "robust_ownership_tracker_test",
+ srcs = ["robust_ownership_tracker_test.cc"],
+ target_compatible_with = ["@platforms//os:linux"],
+ deps = [
+ ":lockless_queue",
+ "//aos/testing:googletest",
+ ],
+)
+
+cc_test(
name = "lockless_queue_test",
timeout = "eternal",
srcs = ["lockless_queue_test.cc"],
diff --git a/aos/ipc_lib/lockless_queue.cc b/aos/ipc_lib/lockless_queue.cc
index fd3a305..f033e60 100644
--- a/aos/ipc_lib/lockless_queue.cc
+++ b/aos/ipc_lib/lockless_queue.cc
@@ -172,9 +172,7 @@
size_t valid_senders = 0;
for (size_t i = 0; i < num_senders; ++i) {
Sender *sender = memory->GetSender(i);
- const uint32_t tid =
- __atomic_load_n(&(sender->tid.futex), __ATOMIC_ACQUIRE);
- if (!(tid & FUTEX_OWNER_DIED)) {
+ if (!sender->ownership_tracker.OwnerIsDefinitelyAbsolutelyDead()) {
// Not dead.
++valid_senders;
continue;
@@ -227,7 +225,7 @@
// always be a NOP if it's in 1), verified by a DCHECK.
memory->GetMessage(scratch_index)->header.queue_index.RelaxedInvalidate();
- __atomic_store_n(&(sender->tid.futex), 0, __ATOMIC_RELEASE);
+ sender->ownership_tracker.ForceClear();
++valid_senders;
continue;
}
@@ -245,7 +243,7 @@
aos_compiler_memory_barrier();
// And mark that we succeeded.
- __atomic_store_n(&(sender->tid.futex), 0, __ATOMIC_RELEASE);
+ sender->ownership_tracker.ForceClear();
++valid_senders;
continue;
}
@@ -259,13 +257,11 @@
// read it before it's set.
for (size_t i = 0; i < num_pinners; ++i) {
Pinner *const pinner = memory->GetPinner(i);
- const uint32_t tid =
- __atomic_load_n(&(pinner->tid.futex), __ATOMIC_ACQUIRE);
- if (!(tid & FUTEX_OWNER_DIED)) {
+ if (!pinner->ownership_tracker.OwnerIsDefinitelyAbsolutelyDead()) {
continue;
}
pinner->pinned.Invalidate();
- __atomic_store_n(&(pinner->tid.futex), 0, __ATOMIC_RELEASE);
+ pinner->ownership_tracker.ForceClear();
}
// If all the senders are (or were made) good, there is no need to do the hard
@@ -284,9 +280,7 @@
num_missing = 0;
for (size_t i = 0; i < num_senders; ++i) {
Sender *const sender = memory->GetSender(i);
- const uint32_t tid =
- __atomic_load_n(&(sender->tid.futex), __ATOMIC_ACQUIRE);
- if (tid & FUTEX_OWNER_DIED) {
+ if (sender->ownership_tracker.OwnerIsDefinitelyAbsolutelyDead()) {
if (!need_recovery[i]) {
return false;
}
@@ -331,9 +325,7 @@
const size_t starting_num_missing = num_missing;
for (size_t i = 0; i < num_senders; ++i) {
Sender *sender = memory->GetSender(i);
- const uint32_t tid =
- __atomic_load_n(&(sender->tid.futex), __ATOMIC_ACQUIRE);
- if (!(tid & FUTEX_OWNER_DIED)) {
+ if (!sender->ownership_tracker.OwnerIsDefinitelyAbsolutelyDead()) {
CHECK(!need_recovery[i]) << ": Somebody else recovered a sender: " << i;
continue;
}
@@ -368,7 +360,7 @@
->header.queue_index.RelaxedInvalidate();
// And then mark this sender clean.
- __atomic_store_n(&(sender->tid.futex), 0, __ATOMIC_RELEASE);
+ sender->ownership_tracker.ForceClear();
need_recovery[i] = false;
// And account for scratch_index.
@@ -394,7 +386,7 @@
sender->to_replace.Invalidate();
// And then mark this sender clean.
- __atomic_store_n(&(sender->tid.futex), 0, __ATOMIC_RELEASE);
+ sender->ownership_tracker.ForceClear();
need_recovery[i] = false;
// And account for to_replace.
@@ -437,6 +429,14 @@
} // namespace
+bool PretendThatOwnerIsDeadForTesting(aos_mutex *mutex, pid_t tid) {
+ if (static_cast<pid_t>(mutex->futex & FUTEX_TID_MASK) == tid) {
+ mutex->futex = FUTEX_OWNER_DIED;
+ return true;
+ }
+ return false;
+}
+
size_t LocklessQueueConfiguration::message_size() const {
// Round up the message size so following data is aligned appropriately.
// Make sure to leave space to align the message data. It will be aligned
@@ -685,11 +685,10 @@
CHECK_NE(watcher_index_, -1);
// Make sure we still own the slot we are supposed to.
- CHECK(
- death_notification_is_held(&(memory_->GetWatcher(watcher_index_)->tid)));
+ CHECK(memory_->GetWatcher(watcher_index_)->ownership_tracker.IsHeldBySelf());
// The act of unlocking invalidates the entry. Invalidate it.
- death_notification_release(&(memory_->GetWatcher(watcher_index_)->tid));
+ memory_->GetWatcher(watcher_index_)->ownership_tracker.Release();
// And internally forget the slot.
watcher_index_ = -1;
@@ -699,7 +698,7 @@
// And confirm that nothing is owned by us.
const int num_watchers = memory_->num_watchers();
for (int i = 0; i < num_watchers; ++i) {
- CHECK(!death_notification_is_held(&(memory_->GetWatcher(i)->tid)))
+ CHECK(!memory_->GetWatcher(i)->ownership_tracker.IsHeldBySelf())
<< ": " << i;
}
}
@@ -732,14 +731,15 @@
for (int i = 0; i < num_watchers; ++i) {
// If we see a slot the kernel has marked as dead, everything we do reusing
// it needs to happen-after whatever that process did before dying.
- auto *const futex = &(memory_->GetWatcher(i)->tid.futex);
- const uint32_t tid = __atomic_load_n(futex, __ATOMIC_ACQUIRE);
- if (tid == 0 || (tid & FUTEX_OWNER_DIED)) {
+ auto *const ownership_tracker =
+ &(memory_->GetWatcher(i)->ownership_tracker);
+ if (ownership_tracker->LoadAcquire().IsUnclaimed() ||
+ ownership_tracker->OwnerIsDefinitelyAbsolutelyDead()) {
watcher_index_ = i;
// Relaxed is OK here because we're the only task going to touch it
// between here and the write in death_notification_init below (other
// recovery is blocked by us holding the setup lock).
- __atomic_store_n(futex, 0, __ATOMIC_RELAXED);
+ ownership_tracker->ForceClear();
break;
}
}
@@ -756,7 +756,7 @@
// Grabbing a mutex is a compiler and memory barrier, so nothing before will
// get rearranged afterwords.
- death_notification_init(&(w->tid));
+ w->ownership_tracker.Acquire();
}
LocklessQueueWakeUpper::LocklessQueueWakeUpper(LocklessQueue queue)
@@ -778,25 +778,25 @@
// creating a pidfd is likely not RT.
for (size_t i = 0; i < num_watchers; ++i) {
const Watcher *w = memory_->GetWatcher(i);
- watcher_copy_[i].tid = __atomic_load_n(&(w->tid.futex), __ATOMIC_RELAXED);
+ watcher_copy_[i].ownership_snapshot = w->ownership_tracker.LoadRelaxed();
// Force the load of the TID to come first.
aos_compiler_memory_barrier();
watcher_copy_[i].pid = w->pid.load(std::memory_order_relaxed);
watcher_copy_[i].priority = w->priority.load(std::memory_order_relaxed);
// Use a priority of -1 to mean an invalid entry to make sorting easier.
- if (watcher_copy_[i].tid & FUTEX_OWNER_DIED || watcher_copy_[i].tid == 0) {
+ if (watcher_copy_[i].ownership_snapshot.OwnerIsDead() ||
+ watcher_copy_[i].ownership_snapshot.IsUnclaimed()) {
watcher_copy_[i].priority = -1;
} else {
// Ensure all of this happens after we're done looking at the pid+priority
// in shared memory.
aos_compiler_memory_barrier();
- if (watcher_copy_[i].tid != static_cast<pid_t>(__atomic_load_n(
- &(w->tid.futex), __ATOMIC_RELAXED))) {
+ if (watcher_copy_[i].ownership_snapshot !=
+ w->ownership_tracker.LoadRelaxed()) {
// Confirm that the watcher hasn't been re-used and modified while we
// read it. If it has, mark it invalid again.
watcher_copy_[i].priority = -1;
- watcher_copy_[i].tid = 0;
}
}
}
@@ -835,8 +835,8 @@
// Send the signal. Target just the thread that sent it so that we can
// support multiple watchers in a process (when someone creates multiple
// event loops in different threads).
- rt_tgsigqueueinfo(watcher_copy.pid, watcher_copy.tid, kWakeupSignal,
- &uinfo);
+ rt_tgsigqueueinfo(watcher_copy.pid, watcher_copy.ownership_snapshot.tid(),
+ kWakeupSignal, &uinfo);
++count;
}
@@ -872,8 +872,7 @@
// This doesn't need synchronization because we're the only process doing
// initialization right now, and nobody else will be touching senders which
// we're interested in.
- const uint32_t tid = __atomic_load_n(&(s->tid.futex), __ATOMIC_RELAXED);
- if (tid == 0) {
+ if (s->ownership_tracker.LoadRelaxed().IsUnclaimed()) {
sender_index_ = i;
break;
}
@@ -888,7 +887,7 @@
// Indicate that we are now alive by taking over the slot. If the previous
// owner died, we still want to do this.
- death_notification_init(&(sender->tid));
+ sender->ownership_tracker.Acquire();
const Index scratch_index = sender->scratch_index.RelaxedLoad();
Message *const message = memory_->GetMessage(scratch_index);
@@ -899,7 +898,7 @@
LocklessQueueSender::~LocklessQueueSender() {
if (sender_index_ != -1) {
CHECK(memory_ != nullptr);
- death_notification_release(&(memory_->GetSender(sender_index_)->tid));
+ memory_->GetSender(sender_index_)->ownership_tracker.Release();
}
}
@@ -1183,8 +1182,7 @@
// This doesn't need synchronization because we're the only process doing
// initialization right now, and nobody else will be touching pinners which
// we're interested in.
- const uint32_t tid = __atomic_load_n(&(p->tid.futex), __ATOMIC_RELAXED);
- if (tid == 0) {
+ if (p->ownership_tracker.LoadRelaxed().IsUnclaimed()) {
pinner_index_ = i;
break;
}
@@ -1200,7 +1198,7 @@
// Indicate that we are now alive by taking over the slot. If the previous
// owner died, we still want to do this.
- death_notification_init(&(p->tid));
+ p->ownership_tracker.Acquire();
}
LocklessQueuePinner::~LocklessQueuePinner() {
@@ -1208,7 +1206,7 @@
CHECK(memory_ != nullptr);
memory_->GetPinner(pinner_index_)->pinned.Invalidate();
aos_compiler_memory_barrier();
- death_notification_release(&(memory_->GetPinner(pinner_index_)->tid));
+ memory_->GetPinner(pinner_index_)->ownership_tracker.Release();
}
}
@@ -1622,8 +1620,8 @@
for (size_t i = 0; i < memory->num_senders(); ++i) {
const Sender *s = memory->GetSender(i);
::std::cout << " [" << i << "] -> Sender {" << ::std::endl;
- ::std::cout << " aos_mutex tid = " << PrintMutex(&s->tid)
- << ::std::endl;
+ ::std::cout << " RobustOwnershipTracker ownership_tracker = "
+ << s->ownership_tracker.DebugString() << ::std::endl;
::std::cout << " AtomicIndex scratch_index = "
<< s->scratch_index.Load().DebugString() << ::std::endl;
::std::cout << " AtomicIndex to_replace = "
@@ -1637,8 +1635,8 @@
for (size_t i = 0; i < memory->num_pinners(); ++i) {
const Pinner *p = memory->GetPinner(i);
::std::cout << " [" << i << "] -> Pinner {" << ::std::endl;
- ::std::cout << " aos_mutex tid = " << PrintMutex(&p->tid)
- << ::std::endl;
+ ::std::cout << " RobustOwnershipTracker ownership_tracker = "
+ << p->ownership_tracker.DebugString() << ::std::endl;
::std::cout << " AtomicIndex scratch_index = "
<< p->scratch_index.Load().DebugString() << ::std::endl;
::std::cout << " AtomicIndex pinned = "
@@ -1653,8 +1651,8 @@
for (size_t i = 0; i < memory->num_watchers(); ++i) {
const Watcher *w = memory->GetWatcher(i);
::std::cout << " [" << i << "] -> Watcher {" << ::std::endl;
- ::std::cout << " aos_mutex tid = " << PrintMutex(&w->tid)
- << ::std::endl;
+ ::std::cout << " RobustOwnershipTracker ownership_tracker = "
+ << w->ownership_tracker.DebugString() << ::std::endl;
::std::cout << " pid_t pid = " << w->pid << ::std::endl;
::std::cout << " int priority = " << w->priority << ::std::endl;
::std::cout << " }" << ::std::endl;
diff --git a/aos/ipc_lib/lockless_queue.h b/aos/ipc_lib/lockless_queue.h
index 01f2b7c..14a11b6 100644
--- a/aos/ipc_lib/lockless_queue.h
+++ b/aos/ipc_lib/lockless_queue.h
@@ -14,6 +14,7 @@
#include "aos/ipc_lib/aos_sync.h"
#include "aos/ipc_lib/data_alignment.h"
#include "aos/ipc_lib/index.h"
+#include "aos/ipc_lib/robust_ownership_tracker.h"
#include "aos/time/time.h"
#include "aos/uuid.h"
@@ -29,7 +30,7 @@
// Note: this is only modified with the queue_setup_lock lock held, but may
// always be read.
// Any state modification should happen before the lock is acquired.
- aos_mutex tid;
+ RobustOwnershipTracker ownership_tracker;
// PID of the watcher.
std::atomic<pid_t> pid;
@@ -46,7 +47,7 @@
//
// Note: this is only modified with the queue_setup_lock lock held, but may
// always be read.
- aos_mutex tid;
+ RobustOwnershipTracker ownership_tracker;
// Index of the message we will be filling out.
AtomicIndex scratch_index;
@@ -59,7 +60,7 @@
// Structure to hold the state required to pin messages.
struct Pinner {
// The same as Sender::tid. See there for docs.
- aos_mutex tid;
+ RobustOwnershipTracker ownership_tracker;
// Queue index of the message we have pinned, or Invalid if there isn't one.
AtomicQueueIndex pinned;
@@ -200,6 +201,10 @@
const static unsigned int kWakeupSignal = SIGRTMIN + 2;
+// Sets FUTEX_OWNER_DIED if the owner was tid. This fakes what the kernel does
+// with a robust mutex.
+bool PretendThatOwnerIsDeadForTesting(aos_mutex *mutex, pid_t tid);
+
// A convenient wrapper for accessing a lockless queue.
class LocklessQueue {
public:
@@ -268,7 +273,7 @@
// up. This isn't a copy of Watcher since tid is simpler to work with here
// than the futex above.
struct WatcherCopy {
- pid_t tid;
+ ThreadOwnerStatusSnapshot ownership_snapshot;
pid_t pid;
int priority;
};
diff --git a/aos/ipc_lib/lockless_queue_death_test.cc b/aos/ipc_lib/lockless_queue_death_test.cc
index 2a95b31..92ad8a8 100644
--- a/aos/ipc_lib/lockless_queue_death_test.cc
+++ b/aos/ipc_lib/lockless_queue_death_test.cc
@@ -102,12 +102,13 @@
bool print = false;
// TestShmRobustness doesn't handle robust futexes. It is happy to just
- // not crash with them. We know what they are, and what the tid of the
- // holder is. So go pretend to be the kernel and fix it for it.
- PretendOwnerDied(&memory->queue_setup_lock, tid.Get());
+ // not crash with them. We know what the futexes are, and what the tid
+ // of the corresponding holder is. So go pretend to be the kernel and
+ // fix the futex.
+ PretendThatOwnerIsDeadForTesting(&memory->queue_setup_lock, tid.Get());
for (size_t i = 0; i < config.num_senders; ++i) {
- if (PretendOwnerDied(&memory->GetSender(i)->tid, tid.Get())) {
+ if (memory->GetSender(i)->ownership_tracker.IsHeldBy(tid.Get())) {
// Print out before and after results if a sender died. That is the
// more fun case.
print = true;
diff --git a/aos/ipc_lib/lockless_queue_stepping.cc b/aos/ipc_lib/lockless_queue_stepping.cc
index 0ec5214..e819795 100644
--- a/aos/ipc_lib/lockless_queue_stepping.cc
+++ b/aos/ipc_lib/lockless_queue_stepping.cc
@@ -458,14 +458,6 @@
pid_t SharedTid::Get() { return *tid_; }
-bool PretendOwnerDied(aos_mutex *mutex, pid_t tid) {
- if ((mutex->futex & FUTEX_TID_MASK) == tid) {
- mutex->futex = FUTEX_OWNER_DIED;
- return true;
- }
- return false;
-}
-
} // namespace testing
} // namespace ipc_lib
} // namespace aos
diff --git a/aos/ipc_lib/lockless_queue_stepping.h b/aos/ipc_lib/lockless_queue_stepping.h
index b3eb6e3..7aab193 100644
--- a/aos/ipc_lib/lockless_queue_stepping.h
+++ b/aos/ipc_lib/lockless_queue_stepping.h
@@ -140,10 +140,6 @@
pid_t *tid_;
};
-// Sets FUTEX_OWNER_DIED if the owner was tid. This fakes what the kernel does
-// with a robust mutex.
-bool PretendOwnerDied(aos_mutex *mutex, pid_t tid);
-
#endif
} // namespace testing
diff --git a/aos/ipc_lib/lockless_queue_test.cc b/aos/ipc_lib/lockless_queue_test.cc
index 58e093f..14701e2 100644
--- a/aos/ipc_lib/lockless_queue_test.cc
+++ b/aos/ipc_lib/lockless_queue_test.cc
@@ -538,7 +538,7 @@
::aos::ipc_lib::LocklessQueueMemory *const memory =
reinterpret_cast<::aos::ipc_lib::LocklessQueueMemory *>(raw_memory);
LocklessQueue queue(memory, memory, config);
- PretendOwnerDied(&memory->queue_setup_lock, tid.Get());
+ PretendThatOwnerIsDeadForTesting(&memory->queue_setup_lock, tid.Get());
if (VLOG_IS_ON(1)) {
PrintLocklessQueueMemory(memory);
diff --git a/aos/ipc_lib/memory_mapped_queue.cc b/aos/ipc_lib/memory_mapped_queue.cc
index 79f27d9..594febb 100644
--- a/aos/ipc_lib/memory_mapped_queue.cc
+++ b/aos/ipc_lib/memory_mapped_queue.cc
@@ -17,7 +17,7 @@
std::string ShmPath(std::string_view shm_base, const Channel *channel) {
CHECK(channel->has_type());
- return ShmFolder(shm_base, channel) + channel->type()->str() + ".v5";
+ return ShmFolder(shm_base, channel) + channel->type()->str() + ".v6";
}
void PageFaultDataWrite(char *data, size_t size) {
diff --git a/aos/ipc_lib/robust_ownership_tracker.cc b/aos/ipc_lib/robust_ownership_tracker.cc
new file mode 100644
index 0000000..f106113
--- /dev/null
+++ b/aos/ipc_lib/robust_ownership_tracker.cc
@@ -0,0 +1,25 @@
+#include "aos/ipc_lib/robust_ownership_tracker.h"
+
+#include "aos/ipc_lib/lockless_queue.h"
+
+namespace aos {
+namespace ipc_lib {
+
+::std::string RobustOwnershipTracker::DebugString() const {
+ ::std::stringstream s;
+ s << "{.tid=aos_mutex(" << ::std::hex << mutex_.futex;
+
+ if (mutex_.futex != 0) {
+ s << ":";
+ if (mutex_.futex & FUTEX_OWNER_DIED) {
+ s << "FUTEX_OWNER_DIED|";
+ }
+ s << "tid=" << (mutex_.futex & FUTEX_TID_MASK);
+ }
+
+ s << "),}";
+ return s.str();
+}
+
+} // namespace ipc_lib
+} // namespace aos
diff --git a/aos/ipc_lib/robust_ownership_tracker.h b/aos/ipc_lib/robust_ownership_tracker.h
new file mode 100644
index 0000000..a8bbca3
--- /dev/null
+++ b/aos/ipc_lib/robust_ownership_tracker.h
@@ -0,0 +1,177 @@
+#ifndef AOS_IPC_LIB_ROBUST_OWNERSHIP_TRACKER_H_
+#define AOS_IPC_LIB_ROBUST_OWNERSHIP_TRACKER_H_
+
+#include <linux/futex.h>
+#include <sys/syscall.h>
+
+#include <string>
+
+#include "aos/ipc_lib/aos_sync.h"
+#include "aos/util/top.h"
+
+namespace aos::ipc_lib {
+namespace testing {
+class RobustOwnershipTrackerTest;
+} // namespace testing
+
+// Results of atomically loading the ownership state via RobustOwnershipTracker
+// below. This allows the state to be compared and queried later.
+class ThreadOwnerStatusSnapshot {
+ public:
+ ThreadOwnerStatusSnapshot() : futex_(0) {}
+ ThreadOwnerStatusSnapshot(aos_futex futex) : futex_(futex) {}
+ ThreadOwnerStatusSnapshot(const ThreadOwnerStatusSnapshot &) = default;
+ ThreadOwnerStatusSnapshot &operator=(const ThreadOwnerStatusSnapshot &) =
+ default;
+ ThreadOwnerStatusSnapshot(ThreadOwnerStatusSnapshot &&) = default;
+ ThreadOwnerStatusSnapshot &operator=(ThreadOwnerStatusSnapshot &&) = default;
+
+ // Returns if the owner died as noticed by the robust futex using Acquire
+ // memory ordering.
+ bool OwnerIsDead() const { return (futex_ & FUTEX_OWNER_DIED) != 0; }
+
+ // Returns true if no one has claimed ownership.
+ bool IsUnclaimed() const { return futex_ == 0; }
+
+ // Returns the thread ID (a.k.a. "tid") of the owning thread. Use this when
+ // trying to access the /proc entry that corresponds to the owning thread for
+ // example. Do not use the futex value directly.
+ pid_t tid() const { return futex_ & FUTEX_TID_MASK; }
+
+ bool operator==(const ThreadOwnerStatusSnapshot &other) const {
+ return other.futex_ == futex_;
+ }
+
+ private:
+ aos_futex futex_;
+};
+
+// This object reliably tracks a thread owning a resource. A single thread may
+// possess multiple resources like senders and receivers. Each resource can have
+// its own instance of this class. These instances are responsible for
+// monitoring the thread that owns them. Each resource can use its instance of
+// this class to reliably check whether the owning thread is no longer alive.
+//
+// All methods other than Load* must be accessed under a mutex.
+class RobustOwnershipTracker {
+ public:
+ static constexpr uint64_t kNoStartTimeTicks =
+ std::numeric_limits<uint64_t>::max();
+
+ static uint64_t ReadStartTimeTicks(pid_t tid) {
+ if (tid == 0) {
+ return kNoStartTimeTicks;
+ }
+ std::optional<aos::util::ProcStat> proc_stat = util::ReadProcStat(tid);
+ if (!proc_stat.has_value()) {
+ return kNoStartTimeTicks;
+ }
+ return proc_stat->start_time_ticks;
+ }
+
+ // Loads the realtime-compatible contents of the ownership tracker with
+ // Acquire memory ordering.
+ ThreadOwnerStatusSnapshot LoadAcquire() const {
+ return ThreadOwnerStatusSnapshot(
+ __atomic_load_n(&(mutex_.futex), __ATOMIC_ACQUIRE));
+ }
+
+ // Loads all the realtime-compatible contents of the ownership tracker with
+ // Relaxed memory order.
+ ThreadOwnerStatusSnapshot LoadRelaxed() const {
+ return ThreadOwnerStatusSnapshot(
+ __atomic_load_n(&(mutex_.futex), __ATOMIC_RELAXED));
+ }
+
+ // Checks both the robust futex and dredges through /proc to see if the thread
+ // is alive. As per the class description, this must only be called under a
+ // mutex. This must not be called in a realtime context and it is slow.
+ bool OwnerIsDefinitelyAbsolutelyDead() const {
+ auto loaded = LoadAcquire();
+ if (loaded.OwnerIsDead()) {
+ return true;
+ }
+ if (loaded.IsUnclaimed()) {
+ return false;
+ }
+ const uint64_t proc_start_time_ticks = ReadStartTimeTicks(loaded.tid());
+ if (proc_start_time_ticks == kNoStartTimeTicks) {
+ LOG(ERROR) << "Detected that PID " << loaded.tid() << " died.";
+ return true;
+ }
+
+ if (proc_start_time_ticks != start_time_ticks_) {
+ LOG(ERROR) << "Detected that PID " << loaded.tid()
+ << " died from a starttime missmatch.";
+ return true;
+ }
+ return false;
+ }
+
+ // Clears all ownership state.
+ //
+ // This should only really be called if you are 100% certain that the owner is
+ // dead. Use `LoadAquire().OwnerIsDead()` to determine this.
+ void ForceClear() {
+ // Must be opposite order of Acquire.
+ // We only deal with the futex here because we don't want to change anything
+ // about the linked list. We just want to release ownership here. We still
+ // want the kernel to know about this element via the linked list the next
+ // time someone takes ownership.
+ __atomic_store_n(&(mutex_.futex), 0, __ATOMIC_RELEASE);
+ start_time_ticks_ = kNoStartTimeTicks;
+ }
+
+ // Returns true if this thread holds ownership.
+ bool IsHeldBySelf() { return death_notification_is_held(&mutex_); }
+
+ // Returns true if the mutex is held by the provided tid. This is primarily
+ // intended for testing. There should be no need to call this in production
+ // code.
+ bool IsHeldBy(pid_t tid) { return LoadRelaxed().tid() == tid; }
+
+ // Acquires ownership. Other threads will know that this thread holds the
+ // ownership or be notified if this thread dies.
+ void Acquire() {
+ pid_t tid = syscall(SYS_gettid);
+ assert(tid > 0);
+ const uint64_t proc_start_time_ticks = ReadStartTimeTicks(tid);
+ CHECK_NE(proc_start_time_ticks, kNoStartTimeTicks);
+
+ start_time_ticks_ = proc_start_time_ticks;
+ death_notification_init(&mutex_);
+ }
+
+ // Releases ownership.
+ //
+ // This should only be called from the owning thread.
+ void Release() {
+ // Must be opposite order of Acquire.
+ death_notification_release(&mutex_);
+ start_time_ticks_ = kNoStartTimeTicks;
+ }
+
+ // Returns a string representing this object.
+ std::string DebugString() const;
+
+ private:
+ friend class testing::RobustOwnershipTrackerTest;
+
+ // Robust futex to track ownership the normal way. The futex is inside the
+ // mutex here. We use the wrapper mutex because the death_notification_*
+ // functions operate on that instead of the futex directly.
+ //
+ // We use a futex here because:
+ // - futexes are fast.
+ // - The kernel can atomically clean up a dead thread and mark the futex
+ // appropriately.
+ // - Owners can clean up after dead threads.
+ aos_mutex mutex_;
+
+ // Thread's start time ticks.
+ std::atomic<uint64_t> start_time_ticks_;
+};
+
+} // namespace aos::ipc_lib
+
+#endif // AOS_IPC_LIB_ROBUST_OWNERSHIP_TRACKER_H_
diff --git a/aos/ipc_lib/robust_ownership_tracker_test.cc b/aos/ipc_lib/robust_ownership_tracker_test.cc
new file mode 100644
index 0000000..b204886
--- /dev/null
+++ b/aos/ipc_lib/robust_ownership_tracker_test.cc
@@ -0,0 +1,155 @@
+#include "aos/ipc_lib/robust_ownership_tracker.h"
+
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+#include "gtest/gtest.h"
+
+namespace aos::ipc_lib::testing {
+
+// Capture RobustOwnershipTracker in shared memory so it is shared across a
+// fork.
+class SharedRobustOwnershipTracker {
+ public:
+ SharedRobustOwnershipTracker() {
+ tracker_ = static_cast<RobustOwnershipTracker *>(
+ mmap(nullptr, sizeof(RobustOwnershipTracker), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0));
+ PCHECK(MAP_FAILED != tracker_);
+ };
+ ~SharedRobustOwnershipTracker() {
+ PCHECK(munmap(tracker_, sizeof(RobustOwnershipTracker)) != -1);
+ }
+
+ // Captures the tid.
+ RobustOwnershipTracker &tracker() const { return *tracker_; }
+
+ private:
+ RobustOwnershipTracker *tracker_;
+};
+
+class RobustOwnershipTrackerTest : public ::testing::Test {
+ public:
+ // Runs a function in a child process, and then exits afterwards. Waits for
+ // the child to finish before resuming.
+ template <typename T>
+ void RunInChildAndBlockUntilComplete(T fn) {
+ pid_t pid = fork();
+ if (pid == 0) {
+ fn();
+ LOG(INFO) << "Child exiting normally.";
+ exit(0);
+ return;
+ }
+
+ LOG(INFO) << "Child has pid " << pid;
+
+ while (true) {
+ LOG(INFO) << "Waiting for child.";
+ int status;
+ const pid_t waited_on = waitpid(pid, &status, 0);
+ // Check for failure.
+ if (waited_on == -1) {
+ if (errno == EINTR) continue;
+ PLOG(FATAL) << ": waitpid(" << pid << ", " << &status << ", 0) failed";
+ }
+ CHECK_EQ(waited_on, pid)
+ << ": waitpid() got child " << waited_on << " instead of " << pid;
+ CHECK(WIFEXITED(status));
+ LOG(INFO) << "Status " << WEXITSTATUS(status);
+ CHECK(WEXITSTATUS(status) == 0);
+ return;
+ }
+ }
+
+ // Returns the robust mutex.
+ aos_mutex &GetMutex(RobustOwnershipTracker &tracker) {
+ return tracker.mutex_;
+ }
+
+ // Returns the current start time in ticks.
+ uint64_t GetStartTimeTicks(RobustOwnershipTracker &tracker) {
+ return tracker.start_time_ticks_.load();
+ }
+
+ // Sets the current start time in ticks.
+ void SetStartTimeTicks(RobustOwnershipTracker &tracker, uint64_t start_time) {
+ tracker.start_time_ticks_ = start_time;
+ }
+};
+
+// Tests that acquiring the futex doesn't erroneously report the owner (i.e.
+// "us") as dead.
+TEST_F(RobustOwnershipTrackerTest, AcquireWorks) {
+ SharedRobustOwnershipTracker shared_tracker;
+
+ EXPECT_FALSE(shared_tracker.tracker().OwnerIsDefinitelyAbsolutelyDead());
+
+ // Run acquire in the this process, and expect it should not be dead until
+ // after the test finishes.
+ shared_tracker.tracker().Acquire();
+
+ // We have ownership. Since we are alive, the owner should not be marked as
+ // dead. We can use relaxed ordering since we are the only ones touching the
+ // data here.
+ EXPECT_FALSE(shared_tracker.tracker().LoadRelaxed().OwnerIsDead());
+ EXPECT_FALSE(shared_tracker.tracker().OwnerIsDefinitelyAbsolutelyDead());
+}
+
+// Tests that child death without unlocking results in the futex being marked as
+// dead, and the owner being very dead.
+TEST_F(RobustOwnershipTrackerTest, FutexRecovers) {
+ SharedRobustOwnershipTracker shared_tracker;
+
+ RunInChildAndBlockUntilComplete(
+ [&]() { shared_tracker.tracker().Acquire(); });
+
+ // Since the child that took ownership died, we expect that death to be
+ // reported.
+ EXPECT_TRUE(shared_tracker.tracker().LoadRelaxed().OwnerIsDead());
+ EXPECT_TRUE(shared_tracker.tracker().OwnerIsDefinitelyAbsolutelyDead());
+}
+
+// Tests that a PID which doesn't exist results in the process being noticed as
+// dead when we inspect /proc.
+TEST_F(RobustOwnershipTrackerTest, NoMatchingPID) {
+ SharedRobustOwnershipTracker shared_tracker;
+
+ shared_tracker.tracker().Acquire();
+ EXPECT_FALSE(shared_tracker.tracker().LoadRelaxed().OwnerIsDead());
+ EXPECT_FALSE(shared_tracker.tracker().OwnerIsDefinitelyAbsolutelyDead());
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-attributes"
+ GetMutex(shared_tracker.tracker()).futex =
+ std::numeric_limits<aos_futex>::max() & FUTEX_TID_MASK;
+#pragma GCC diagnostic pop
+
+ // Since we're only pretending that the owner died (by changing the TID in the
+ // futex), we only notice that the owner is dead when spending the time
+ // walking through /proc.
+ EXPECT_FALSE(shared_tracker.tracker().LoadRelaxed().OwnerIsDead());
+ EXPECT_TRUE(shared_tracker.tracker().OwnerIsDefinitelyAbsolutelyDead());
+}
+
+// Tests that a mismatched start time results in the process being marked as
+// dead.
+TEST_F(RobustOwnershipTrackerTest, NoMatchingStartTime) {
+ SharedRobustOwnershipTracker shared_tracker;
+
+ shared_tracker.tracker().Acquire();
+ EXPECT_FALSE(shared_tracker.tracker().LoadRelaxed().OwnerIsDead());
+ EXPECT_FALSE(shared_tracker.tracker().OwnerIsDefinitelyAbsolutelyDead());
+
+ EXPECT_NE(GetStartTimeTicks(shared_tracker.tracker()), 0);
+ EXPECT_NE(GetStartTimeTicks(shared_tracker.tracker()),
+ RobustOwnershipTracker::kNoStartTimeTicks);
+ SetStartTimeTicks(shared_tracker.tracker(), 1);
+
+ // Since we're only pretending that the owner died (by changing the tracked
+ // start time ticks in the tracker), we only notice that the owner is dead
+ // when spending the time walking through /proc.
+ EXPECT_FALSE(shared_tracker.tracker().LoadRelaxed().OwnerIsDead());
+ EXPECT_TRUE(shared_tracker.tracker().OwnerIsDefinitelyAbsolutelyDead());
+}
+
+} // namespace aos::ipc_lib::testing
diff --git a/aos/json_to_flatbuffer_test.cc b/aos/json_to_flatbuffer_test.cc
index d2b88f0..a145364 100644
--- a/aos/json_to_flatbuffer_test.cc
+++ b/aos/json_to_flatbuffer_test.cc
@@ -41,7 +41,11 @@
printf("Back to string via TypeTable: %s\n", back_typetable.c_str());
printf("Back to string via reflection: %s\n", back_reflection.c_str());
- return back_typetable == out && back_reflection == out;
+ const bool as_expected = back_typetable == out && back_reflection == out;
+ if (!as_expected) {
+ printf("But expected: %s\n", out.c_str());
+ }
+ return as_expected;
}
};
@@ -230,9 +234,33 @@
EXPECT_TRUE(JsonAndBack("{ }"));
}
-// Tests that comments get stripped.
-TEST_F(JsonToFlatbufferTest, Comments) {
- EXPECT_TRUE(JsonAndBack("{ /* foo */ \"vector_foo_double\": [ 9, 7, 1 ] }",
+// Tests that C style comments get stripped.
+TEST_F(JsonToFlatbufferTest, CStyleComments) {
+ EXPECT_TRUE(JsonAndBack(R"({
+ /* foo */
+ "vector_foo_double": [ 9, 7, 1 ] /* foo */
+} /* foo */)",
+ "{ \"vector_foo_double\": [ 9.0, 7.0, 1.0 ] }"));
+}
+
+// Tests that C++ style comments get stripped.
+TEST_F(JsonToFlatbufferTest, CppStyleComments) {
+ EXPECT_TRUE(JsonAndBack(R"({
+ // foo
+ "vector_foo_double": [ 9, 7, 1 ] // foo
+} // foo)",
+ "{ \"vector_foo_double\": [ 9.0, 7.0, 1.0 ] }"));
+}
+
+// Tests that mixed style comments get stripped.
+TEST_F(JsonToFlatbufferTest, MixedStyleComments) {
+ // Weird comments do not throw us off.
+ EXPECT_TRUE(JsonAndBack(R"({
+ // foo /* foo */
+ "vector_foo_double": [ 9, 7, 1 ] /* // foo */
+}
+// foo
+/* foo */)",
"{ \"vector_foo_double\": [ 9.0, 7.0, 1.0 ] }"));
}
diff --git a/aos/json_tokenizer.cc b/aos/json_tokenizer.cc
index b3c6620..eab7fcc 100644
--- a/aos/json_tokenizer.cc
+++ b/aos/json_tokenizer.cc
@@ -23,6 +23,19 @@
}
ConsumeChar();
}
+ } else if (Consume("//")) {
+ // C++ style comment. Keep consuming chars until newline, or until the
+ // end of the file if this is the last line (no newline at end of file).
+ while (true) {
+ ConsumeChar();
+ if (AtEnd()) {
+ return;
+ }
+ if (Char() == '\n') {
+ ++linenumber_;
+ break;
+ }
+ }
} else {
// There is no fail. Once we are out of whitespace (including 0 of it),
// declare success.
diff --git a/aos/logging/logging.h b/aos/logging/logging.h
index c71e5c4..8d83037 100644
--- a/aos/logging/logging.h
+++ b/aos/logging/logging.h
@@ -51,7 +51,7 @@
// It's currently using __PRETTY_FUNCTION__ because both GCC and Clang support
// that and it gives nicer results in C++ than the standard __func__ (which
// would also work).
-//#define LOG_CURRENT_FUNCTION __PRETTY_FUNCTION__
+// #define LOG_CURRENT_FUNCTION __PRETTY_FUNCTION__
#define LOG_CURRENT_FUNCTION __func__
#define LOG_SOURCENAME __FILE__
diff --git a/aos/network/BUILD b/aos/network/BUILD
index d1a79d0..e8dd75f 100644
--- a/aos/network/BUILD
+++ b/aos/network/BUILD
@@ -194,6 +194,7 @@
tags = [
# Fakeroot is required to enable "net.sctp.auth_enable".
"requires-fakeroot",
+ "no-remote-exec",
],
target_compatible_with = ["@platforms//cpu:x86_64"],
deps = [
diff --git a/aos/network/message_bridge_client_lib.cc b/aos/network/message_bridge_client_lib.cc
index 19f3420..34f578e 100644
--- a/aos/network/message_bridge_client_lib.cc
+++ b/aos/network/message_bridge_client_lib.cc
@@ -62,7 +62,6 @@
const Node *my_node,
const Node *other_node) {
std::vector<bool> stream_reply_with_timestamp;
- int channel_index = 0;
for (const Channel *channel : *config->channels()) {
if (configuration::ChannelIsSendableOnNode(channel, other_node)) {
const Connection *connection =
@@ -78,7 +77,6 @@
configuration::ChannelMessageIsLoggedOnNode(channel, my_node));
}
}
- ++channel_index;
}
return stream_reply_with_timestamp;
diff --git a/aos/network/multinode_timestamp_filter.cc b/aos/network/multinode_timestamp_filter.cc
index 85ee12c..b4ebef4 100644
--- a/aos/network/multinode_timestamp_filter.cc
+++ b/aos/network/multinode_timestamp_filter.cc
@@ -459,7 +459,8 @@
return result;
}
-Eigen::VectorXd NewtonSolver::Newton(const Problem::Derivatives &derivatives,
+Eigen::VectorXd NewtonSolver::Newton(const Eigen::Ref<const Eigen::VectorXd> y,
+ const Problem::Derivatives &derivatives,
size_t iteration) {
// https://www.cs.purdue.edu/homes/jhonorio/16spring-cs52000-equality.pdf
// https://web.stanford.edu/~boyd/cvxbook/bv_cvxbook.pdf chapter 10 is good
@@ -479,6 +480,10 @@
Eigen::VectorXd b = Eigen::VectorXd::Zero(a.rows());
b.block(0, 0, derivatives.gradient.rows(), 1) = -derivatives.gradient;
if (derivatives.Axmb.rows()) {
+ const Eigen::Ref<const Eigen::VectorXd> v =
+ y.block(derivatives.hessian.rows(), 0, derivatives.A.rows(), 1);
+ b.block(0, 0, derivatives.gradient.rows(), 1) -=
+ derivatives.A.transpose() * v;
b.block(derivatives.gradient.rows(), 0, derivatives.Axmb.rows(), 1) =
-derivatives.Axmb;
}
@@ -508,6 +513,34 @@
return step;
}
+double NewtonSolver::RSquaredUnconstrained(
+ const Problem::Derivatives &derivatives,
+ Eigen::Ref<const Eigen::VectorXd> y, Eigen::Ref<const Eigen::VectorXd> step,
+ double t) {
+ // See https://web.stanford.edu/~boyd/cvxbook/bv_cvxbook.pdf section 10.3.1
+ //
+ // Note: all the prints are transposed so they fit on one line instead of
+ // having a ton of massive column vectors being printed all the time.
+ SOLVE_VLOG(my_solve_number_, 2)
+ << " r_dual: " << std::setprecision(12) << std::fixed
+ << std::setfill(' ')
+ << derivatives.gradient.transpose().format(kHeavyFormat) << " + "
+ << ((y.block(derivatives.gradient.rows(), 0, 1, 1) +
+ t * step.block(derivatives.gradient.rows(), 0, 1, 1))
+ .transpose() *
+ derivatives.A)
+ .format(kHeavyFormat);
+ SOLVE_VLOG(my_solve_number_, 2)
+ << " r_primal: " << std::setprecision(12) << std::fixed
+ << std::setfill(' ') << derivatives.Axmb.transpose().format(kHeavyFormat);
+ return (derivatives.gradient +
+ derivatives.A.transpose() *
+ (y.block(derivatives.gradient.rows(), 0, 1, 1) +
+ t * step.block(derivatives.gradient.rows(), 0, 1, 1)))
+ .squaredNorm() +
+ derivatives.Axmb.squaredNorm();
+}
+
std::tuple<Eigen::VectorXd, size_t, size_t> NewtonSolver::SolveNewton(
Problem *problem, const size_t max_iterations) {
SOLVE_VLOG(my_solve_number_, 2)
@@ -515,25 +548,35 @@
problem->Prepare(my_solve_number_);
- Eigen::VectorXd data = Eigen::VectorXd::Zero(problem->states());
+ Eigen::VectorXd y = Eigen::VectorXd::Zero(problem->states() + 1);
size_t iteration = 0;
size_t solution_node;
+
+ // The derivatives and squared norm of r(y).
+ Problem::Derivatives derivatives = problem->ComputeDerivatives(
+ my_solve_number_, y, false, false, absl::Span<const size_t>());
+ double r_orig_squared = RSquaredUnconstrained(derivatives, y, y, 0.0);
while (true) {
- const Problem::Derivatives derivatives = problem->ComputeDerivatives(
- my_solve_number_, data, false, false, absl::Span<const size_t>());
- const Eigen::VectorXd step = Newton(derivatives, iteration);
+ SOLVE_VLOG(my_solve_number_, 1) << "Starting iteration " << iteration;
+
+ const Eigen::VectorXd step = Newton(y, derivatives, iteration);
solution_node = derivatives.solution_node;
+ SOLVE_VLOG(my_solve_number_, 1)
+ << " y(" << iteration << ") is " << y.transpose().format(kHeavyFormat);
+ PrintDerivatives(derivatives, y, "", 3);
SOLVE_VLOG(my_solve_number_, 2)
- << "Step " << iteration << " -> " << std::setprecision(12) << std::fixed
- << std::setfill(' ') << step.transpose().format(kHeavyFormat);
+ << " initial step(" << iteration << ") -> " << std::setprecision(12)
+ << std::fixed << std::setfill(' ')
+ << step.transpose().format(kHeavyFormat);
// We now have a search direction. Line search and go.
+ double t = 1.0;
- // We got there if the max step is small (this is strongly correlated to the
- // gradient since the Hessian is constant), and our solution node's time is
- // also close.
+ // We got there if the max step is small (this is strongly correlated to
+ // the gradient since the Hessian is constant), and our solution node's
+ // time is also close.
// Grad is < epsilon.
// Dual is < epsilon too.
@@ -543,7 +586,44 @@
break;
}
- data += step.block(0, 0, problem->states(), 1);
+ SOLVE_VLOG(my_solve_number_, 2)
+ << " Not close enough, "
+ << step.block(0, 0, problem->states(), 1).lpNorm<Eigen::Infinity>()
+ << " >= 1e-4 || " << derivatives.Axmb.squaredNorm() << " >= 1e-8";
+
+ // Now, do line search.
+ while (true) {
+ Problem::Derivatives new_derivatives =
+ problem->ComputeDerivatives(my_solve_number_, y + t * step, false,
+ false, absl::Span<const size_t>());
+ const double r_squared =
+ RSquaredUnconstrained(new_derivatives, y, step, t);
+ SOLVE_VLOG(my_solve_number_, 2)
+ << std::setprecision(12) << std::setfill(' ') << " |r| < |r+1| "
+ << r_orig_squared << " < " << r_squared << " for step size " << t;
+ // See Boyd, section 10.3.2, algorithm 10.2
+ if (r_squared <=
+ std::pow(1.0 - kUnconstrainedAlpha * t, 2.0) * r_orig_squared ||
+ t < kLineSearchStopThreshold) {
+ // This is modified because we have seen cases where the way we handle
+ // equality constraints sometimes ends up increasing the cost slightly.
+ // We are better off taking a small step and trying again than shrinking
+ // our step forever.
+ //
+ // Save the derivatives and norm computed for the next iteration to save
+ // CPU.
+ derivatives = std::move(new_derivatives);
+ r_orig_squared = r_squared;
+ SOLVE_VLOG(my_solve_number_, 3)
+ << " Line search terminated with a step of " << t;
+ break;
+ } else {
+ CHECK_NE(t, 0.0) << ": Failed on solve " << my_solve_number_;
+ }
+ t *= kBeta;
+ }
+
+ y += t * step;
++iteration;
@@ -555,8 +635,8 @@
// true for the first solution. Because we control the solver, as we
// determine that the double is getting too big, we can move that
// information to the int64 base clock. Threshold this to not be *too* big
- // since it makes it hard to debug as the data keeps jumping around.
- problem->Update(my_solve_number_, data);
+ // since it makes it hard to debug as y keeps jumping around.
+ problem->Update(my_solve_number_, y);
// And finally, don't let us iterate forever. If it isn't converging,
// report back.
@@ -571,7 +651,8 @@
SOLVE_VLOG(my_solve_number_, 1)
<< "Took " << iteration << " iterations to solve.";
- return std::make_tuple(std::move(data), solution_node, iteration);
+ return std::make_tuple(y.block(0, 0, problem->states(), 1), solution_node,
+ iteration);
}
Problem::Derivatives NewtonSolver::AddConstraintSlackVariable(
@@ -693,6 +774,10 @@
const Eigen::Ref<const Eigen::VectorXd> lambda =
y.block(x.rows(), 0, derivatives.f.rows(), 1);
+ CHECK_LT(0, lambda.rows())
+ << ": You are calling the unconstrained Newton solver without inequality "
+ "constraints. This is not supported.";
+
const Eigen::Ref<const Eigen::VectorXd> v =
y.block(x.rows() + lambda.rows(), 0, derivatives.A.rows(), 1);
@@ -770,25 +855,32 @@
const Eigen::Ref<const Eigen::VectorXd> v =
y.block(x.rows() + lambda.rows(), 0, derivatives.A.rows(), 1);
SOLVE_VLOG(my_solve_number_, verbosity)
- << " " << prefix << "x: " << x.transpose().format(heavy);
+ << std::setprecision(12) << " " << prefix
+ << "x: " << x.transpose().format(heavy);
SOLVE_VLOG(my_solve_number_, verbosity)
- << " " << prefix << "lambda: " << lambda.transpose().format(heavy);
+ << std::setprecision(12) << " " << prefix
+ << "lambda: " << lambda.transpose().format(heavy);
SOLVE_VLOG(my_solve_number_, verbosity)
- << " " << prefix << "v: " << v.transpose().format(heavy);
+ << std::setprecision(12) << " " << prefix
+ << "v: " << v.transpose().format(heavy);
SOLVE_VLOG(my_solve_number_, verbosity)
- << " " << prefix
+ << std::setprecision(12) << " " << prefix
<< "hessian: " << derivatives.hessian.format(heavy);
SOLVE_VLOG(my_solve_number_, verbosity)
- << " " << prefix
+ << std::setprecision(12) << " " << prefix
<< "gradient: " << derivatives.gradient.format(heavy);
SOLVE_VLOG(my_solve_number_, verbosity)
- << " " << prefix << "A: " << derivatives.A.format(heavy);
+ << std::setprecision(12) << " " << prefix
+ << "A: " << derivatives.A.format(heavy);
SOLVE_VLOG(my_solve_number_, verbosity)
- << " " << prefix << "Ax-b: " << derivatives.Axmb.format(heavy);
+ << std::setprecision(12) << " " << prefix
+ << "Ax-b: " << derivatives.Axmb.format(heavy);
SOLVE_VLOG(my_solve_number_, verbosity)
- << " " << prefix << "f: " << derivatives.f.format(heavy);
+ << std::setprecision(12) << " " << prefix
+ << "f: " << derivatives.f.format(heavy);
SOLVE_VLOG(my_solve_number_, verbosity)
- << " " << prefix << "df: " << derivatives.df.format(heavy);
+ << std::setprecision(12) << " " << prefix
+ << "df: " << derivatives.df.format(heavy);
}
}
@@ -1022,6 +1114,13 @@
PrintDerivatives(derivatives, y, "", 1);
+ if (derivatives.f.rows() == 0) {
+ LOG(ERROR) << "No inequality constraints provided in constrained solver. "
+ "This suggests an inconsistency in the solver code, please "
+ "investigate.";
+ return std::nullopt;
+ }
+
// Figure out our descent direction.
Eigen::VectorXd dy;
Eigen::VectorXd rt_orig;
@@ -1275,7 +1374,8 @@
}
SOLVE_VLOG(solve_number, 2)
- << " live " << points_[j].time << " vs solution "
+ << std::setprecision(12) << std::fixed << " live "
+ << points_[j].time << " vs solution "
<< base_clock_[j].time +
std::chrono::nanoseconds(static_cast<int64_t>(
std::round(data(NodeToFullSolutionIndex(j)))))
@@ -1720,7 +1820,6 @@
}
if (filter_fps_.size() != 0 && !destructor) {
- size_t node_a_index = 0;
for (const auto &filters : filters_per_node_) {
for (const auto &filter : filters) {
while (true) {
@@ -1732,7 +1831,6 @@
WriteFilter(filter.filter, *sample);
}
}
- ++node_a_index;
}
}
diff --git a/aos/network/multinode_timestamp_filter.h b/aos/network/multinode_timestamp_filter.h
index 959fe85..828c489 100644
--- a/aos/network/multinode_timestamp_filter.h
+++ b/aos/network/multinode_timestamp_filter.h
@@ -84,6 +84,10 @@
// Ratio to let the cost increase when line searching. A small increase is
// fine since we aren't perfectly convex.
static constexpr double kAlpha = -0.15;
+ // Ratio to require the cost to decrease when line searching.
+ static constexpr double kUnconstrainedAlpha = 0.5;
+ // Unconstrained min line search distance to guarantee forward progress.
+ static constexpr double kLineSearchStopThreshold = 0.4;
// Line search step parameter.
static constexpr double kBeta = 0.5;
static constexpr double kMu = 2.0;
@@ -138,6 +142,14 @@
Eigen::VectorXd Rt(const Problem::Derivatives &derivatives,
Eigen::Ref<const Eigen::VectorXd> y, double t);
+ // Returns the squared norm of r for the unconstrained problem.
+ // (10.3.1 in Convex Optimization,
+ // https://web.stanford.edu/~boyd/cvxbook/bv_cvxbook.pdf)
+ double RSquaredUnconstrained(const Problem::Derivatives &derivatives,
+ Eigen::Ref<const Eigen::VectorXd> y,
+ Eigen::Ref<const Eigen::VectorXd> step,
+ double t);
+
// Returns the constrained newtons step, t_inverse, and Rt.
std::tuple<Eigen::VectorXd, double, Eigen::VectorXd> ConstrainedNewton(
const Eigen::Ref<const Eigen::VectorXd> y,
@@ -152,7 +164,8 @@
// used for the equality constraint. The last term is the scalar on the
// equality constraint. This needs to be removed from the solution to get the
// actual newton step.
- Eigen::VectorXd Newton(const Problem::Derivatives &derivatives,
+ Eigen::VectorXd Newton(const Eigen::Ref<const Eigen::VectorXd> y,
+ const Problem::Derivatives &derivatives,
size_t iteration);
// The solve number for this instance of the problem.
diff --git a/aos/network/rawrtc.h b/aos/network/rawrtc.h
index f43cc5e..7908124 100644
--- a/aos/network/rawrtc.h
+++ b/aos/network/rawrtc.h
@@ -170,9 +170,7 @@
void Open();
// Returns the connection if Open has been called.
- struct rawrtc_peer_connection *connection() {
- return connection_;
- }
+ struct rawrtc_peer_connection *connection() { return connection_; }
private:
// Trampolines from C -> C++.
diff --git a/aos/network/sctp_client.h b/aos/network/sctp_client.h
index 06f6b15..9b9265e 100644
--- a/aos/network/sctp_client.h
+++ b/aos/network/sctp_client.h
@@ -44,9 +44,7 @@
void SetPriorityScheduler(sctp_assoc_t assoc_id);
// Remote to send to.
- struct sockaddr_storage sockaddr_remote() const {
- return sockaddr_remote_;
- }
+ struct sockaddr_storage sockaddr_remote() const { return sockaddr_remote_; }
void LogSctpStatus(sctp_assoc_t assoc_id);
diff --git a/aos/network/sctp_lib.cc b/aos/network/sctp_lib.cc
index c3c6e23..0922d6b 100644
--- a/aos/network/sctp_lib.cc
+++ b/aos/network/sctp_lib.cc
@@ -715,8 +715,11 @@
<< "SCTP Authentication key requested, but authentication isn't "
"enabled... Use `sysctl -w net.sctp.auth_enable=1` to enable";
// Set up the key with id `1`.
- std::unique_ptr<sctp_authkey> authkey(
- (sctp_authkey *)malloc(sizeof(sctp_authkey) + auth_key.size()));
+ // NOTE: `sctp_authkey` is a variable-sized struct which is why it needs
+ // to be heap allocated. Regardless, this object doesn't have to persist past
+ // the `setsockopt` call below.
+ std::unique_ptr<sctp_authkey> authkey(static_cast<sctp_authkey *>(
+ ::operator new(sizeof(sctp_authkey) + auth_key.size())));
authkey->sca_keynumber = 1;
authkey->sca_keylength = auth_key.size();
diff --git a/aos/network/sctp_test.cc b/aos/network/sctp_test.cc
index 8e332e4..bce5c19 100644
--- a/aos/network/sctp_test.cc
+++ b/aos/network/sctp_test.cc
@@ -11,6 +11,7 @@
#include "aos/network/sctp_client.h"
#include "aos/network/sctp_lib.h"
#include "aos/network/sctp_server.h"
+#include "sctp_lib.h"
DECLARE_bool(disable_ipv6);
@@ -28,8 +29,10 @@
namespace {
void EnableSctpAuthIfAvailable() {
#if HAS_SCTP_AUTH
- CHECK(system("/usr/sbin/sysctl net.sctp.auth_enable=1 || /sbin/sysctl "
- "net.sctp.auth_enable=1") == 0)
+ // Open an SCTP socket to bring the kernel SCTP module
+ SctpServer server(1, "localhost");
+ CHECK(system("/usr/sbin/sysctl net.sctp.auth_enable=1 || "
+ "/sbin/sysctl net.sctp.auth_enable=1") == 0)
<< "Couldn't enable sctp authentication.";
#endif
}
diff --git a/aos/network/timestamp_filter.cc b/aos/network/timestamp_filter.cc
index 4a29dfc..9736679 100644
--- a/aos/network/timestamp_filter.cc
+++ b/aos/network/timestamp_filter.cc
@@ -531,6 +531,13 @@
if (!use_other) {
return std::make_pair(pointer, std::make_pair(t0, t1));
}
+
+ // The invariant of pointer is that other_points is bounded by t0, t1. Confirm
+ // it before we return things depending on it since it is easy.
+ CHECK_GT(std::get<0>(pointer.other_points_[0].second), std::get<0>(t0));
+ CHECK_LT(std::get<0>(
+ pointer.other_points_[pointer.other_points_.size() - 1].second),
+ std::get<0>(t1));
// We have 2 timestamps bookending everything, and a list of points in the
// middle.
//
@@ -660,11 +667,14 @@
const size_t index = std::distance(timestamps_.begin(), it);
+ // Now, update the pointer cache.
pointer.index_ = index - 1;
t0 = timestamp(index - 1);
pointer.t0_ = t0;
t1 = timestamp(index);
pointer.t1_ = t1;
+ // And clear out the point cache since the points changed.
+ pointer.other_points_.clear();
if (other != nullptr && !other->timestamps_empty()) {
// Ok, we now need to find all points within our range in the matched
@@ -688,8 +698,6 @@
if (std::get<0>(*other_t0_it) + std::get<1>(*other_t0_it) <
std::get<0>(pointer.t1_)) {
- pointer.other_points_.clear();
-
// Now, we've got a range. [other_t0_it, other_t1_it).
for (auto other_it = other_t0_it; other_it != other_t1_it; ++other_it) {
const std::tuple<monotonic_clock::time_point,
diff --git a/aos/network/timestamp_filter.h b/aos/network/timestamp_filter.h
index 8b597bd..b1aff86 100644
--- a/aos/network/timestamp_filter.h
+++ b/aos/network/timestamp_filter.h
@@ -306,7 +306,12 @@
std::tuple<monotonic_clock::time_point, std::chrono::nanoseconds> t1_ =
std::make_tuple(monotonic_clock::min_time, std::chrono::nanoseconds(0));
- // List of points and their associated times going the other way.
+ // List of points and their associated times going the other way. This lets
+ // us handle when there is a large gap in timestamps, but time drifts in
+ // such a way to create an impossible situation when the points are
+ // connected by straight lines.
+ //
+ // These need to be between t0 and t1.
std::vector<std::pair<size_t, std::tuple<monotonic_clock::time_point,
std::chrono::nanoseconds>>>
other_points_;
@@ -869,6 +874,14 @@
return result;
}
+ // Interpolates between two points for time ta using the provided pointer, t0,
+ // and t1. If use_other is true, then we use other_points_ inside pointer to
+ // also interpolate with. This lets us handle cases where we have
+ // observations only going one way, but the filter lines cross because time
+ // drifted.
+ //
+ // Returns the 2 points which define the line we should interpolate along, and
+ // an updated pointer caching what points were actually used.
static std::pair<
Pointer,
std::pair<
diff --git a/aos/starter/BUILD b/aos/starter/BUILD
index 732cfe3..1873166 100644
--- a/aos/starter/BUILD
+++ b/aos/starter/BUILD
@@ -93,6 +93,24 @@
],
)
+# Similar to subprocess_test, but here are all the tests that are not flaky.
+cc_test(
+ name = "subprocess_reliable_test",
+ srcs = ["subprocess_reliable_test.cc"],
+ data = [
+ "//aos/events:pingpong_config",
+ ],
+ # The roborio compiler doesn't support <filesystem>.
+ target_compatible_with = ["@platforms//os:linux"],
+ deps = [
+ ":subprocess",
+ "//aos/events:shm_event_loop",
+ "//aos/testing:googletest",
+ "//aos/testing:path",
+ "//aos/testing:tmpdir",
+ ],
+)
+
cc_test(
name = "starter_test",
srcs = ["starter_test.cc"],
diff --git a/aos/starter/subprocess.cc b/aos/starter/subprocess.cc
index 7b5fce6..4d21c61 100644
--- a/aos/starter/subprocess.cc
+++ b/aos/starter/subprocess.cc
@@ -12,6 +12,25 @@
namespace aos::starter {
+// Blocks all signals while an instance of this class is in scope.
+class ScopedCompleteSignalBlocker {
+ public:
+ ScopedCompleteSignalBlocker() {
+ sigset_t mask;
+ sigfillset(&mask);
+ // Remember the current mask.
+ PCHECK(sigprocmask(SIG_SETMASK, &mask, &old_mask_) == 0);
+ }
+
+ ~ScopedCompleteSignalBlocker() {
+ // Restore the remembered mask.
+ PCHECK(sigprocmask(SIG_SETMASK, &old_mask_, nullptr) == 0);
+ }
+
+ private:
+ sigset_t old_mask_;
+};
+
// RAII class to become root and restore back to the original user and group
// afterwards.
class Sudo {
@@ -141,11 +160,13 @@
restart_timer_(event_loop_->AddTimer([this] { DoStart(); })),
stop_timer_(event_loop_->AddTimer([this] {
if (kill(pid_, SIGKILL) == 0) {
- LOG_IF(WARNING, quiet_flag_ == QuietLogging::kNo)
+ LOG_IF(WARNING, quiet_flag_ == QuietLogging::kNo ||
+ quiet_flag_ == QuietLogging::kNotForDebugging)
<< "Failed to stop, sending SIGKILL to '" << name_
<< "' pid: " << pid_;
} else {
- PLOG_IF(WARNING, quiet_flag_ == QuietLogging::kNo)
+ PLOG_IF(WARNING, quiet_flag_ == QuietLogging::kNo ||
+ quiet_flag_ == QuietLogging::kNotForDebugging)
<< "Failed to send SIGKILL to '" << name_ << "' pid: " << pid_;
stop_timer_->Schedule(event_loop_->monotonic_now() +
std::chrono::seconds(1));
@@ -209,34 +230,56 @@
pipe_timer_->Schedule(event_loop_->monotonic_now(),
std::chrono::milliseconds(100));
- const pid_t pid = fork();
+ {
+ // Block all signals during the fork() call. Together with the default
+ // signal handler restoration below, This prevents signal handlers from
+ // getting called in the child and accidentally affecting the parent. In
+ // particular, the exit handler for shm_event_loop could be called here if
+ // we don't exec() quickly enough.
+ ScopedCompleteSignalBlocker signal_blocker;
- if (pid != 0) {
- if (pid == -1) {
- PLOG_IF(WARNING, quiet_flag_ == QuietLogging::kNo)
- << "Failed to fork '" << name_ << "'";
- stop_reason_ = aos::starter::LastStopReason::FORK_ERR;
- status_ = aos::starter::State::STOPPED;
- } else {
- pid_ = pid;
- id_ = next_id_++;
- start_time_ = event_loop_->monotonic_now();
- status_ = aos::starter::State::STARTING;
- latest_timing_report_version_.reset();
- LOG_IF(INFO, quiet_flag_ == QuietLogging::kNo)
- << "Starting '" << name_ << "' pid " << pid_;
+ const pid_t pid = fork();
- // Set up timer which moves application to RUNNING state if it is still
- // alive in 1 second.
- start_timer_->Schedule(event_loop_->monotonic_now() +
- std::chrono::seconds(1));
- // Since we are the parent process, clear our write-side of all the pipes.
- status_pipes_.write.reset();
- stdout_pipes_.write.reset();
- stderr_pipes_.write.reset();
+ if (pid != 0) {
+ if (pid == -1) {
+ PLOG_IF(WARNING, quiet_flag_ == QuietLogging::kNo ||
+ quiet_flag_ == QuietLogging::kNotForDebugging)
+ << "Failed to fork '" << name_ << "'";
+ stop_reason_ = aos::starter::LastStopReason::FORK_ERR;
+ status_ = aos::starter::State::STOPPED;
+ } else {
+ pid_ = pid;
+ id_ = next_id_++;
+ start_time_ = event_loop_->monotonic_now();
+ status_ = aos::starter::State::STARTING;
+ latest_timing_report_version_.reset();
+ LOG_IF(INFO, quiet_flag_ == QuietLogging::kNo)
+ << "Starting '" << name_ << "' pid " << pid_;
+
+ // Set up timer which moves application to RUNNING state if it is still
+ // alive in 1 second.
+ start_timer_->Schedule(event_loop_->monotonic_now() +
+ std::chrono::seconds(1));
+ // Since we are the parent process, clear our write-side of all the
+ // pipes.
+ status_pipes_.write.reset();
+ stdout_pipes_.write.reset();
+ stderr_pipes_.write.reset();
+ }
+ OnChange();
+ return;
}
- OnChange();
- return;
+
+ // Clear any signal handlers so that they don't accidentally interfere with
+ // the parent process. Is there a better way to iterate over all the
+ // signals? Right now we're just dealing with the most common ones.
+ for (int signal : {SIGINT, SIGHUP, SIGTERM}) {
+ struct sigaction action;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ action.sa_handler = SIG_DFL;
+ PCHECK(sigaction(signal, &action, nullptr) == 0);
+ }
}
if (memory_cgroup_) {
@@ -323,7 +366,8 @@
// If we got here, something went wrong
status_pipes_.write->Write(
static_cast<uint32_t>(aos::starter::LastStopReason::EXECV_ERR));
- PLOG_IF(WARNING, quiet_flag_ == QuietLogging::kNo)
+ PLOG_IF(WARNING, quiet_flag_ == QuietLogging::kNo ||
+ quiet_flag_ == QuietLogging::kNotForDebugging)
<< "Could not execute " << name_ << " (" << path_ << ')';
_exit(EXIT_FAILURE);
@@ -371,12 +415,18 @@
switch (status_) {
case aos::starter::State::STARTING:
case aos::starter::State::RUNNING: {
- LOG_IF(INFO, quiet_flag_ == QuietLogging::kNo)
+ LOG_IF(INFO, quiet_flag_ == QuietLogging::kNo ||
+ quiet_flag_ == QuietLogging::kNotForDebugging)
<< "Stopping '" << name_ << "' pid: " << pid_ << " with signal "
<< SIGINT;
status_ = aos::starter::State::STOPPING;
- kill(pid_, SIGINT);
+ if (kill(pid_, SIGINT) != 0) {
+ PLOG_IF(INFO, quiet_flag_ == QuietLogging::kNo ||
+ quiet_flag_ == QuietLogging::kNotForDebugging)
+ << "Failed to send signal " << SIGINT << " to '" << name_
+ << "' pid: " << pid_;
+ }
// Watchdog timer to SIGKILL application if it is still running 1 second
// after SIGINT
@@ -591,7 +641,8 @@
<< "Application '" << name_ << "' pid " << pid_
<< " exited with status " << exit_code_.value();
} else {
- LOG_IF(WARNING, quiet_flag_ == QuietLogging::kNo)
+ LOG_IF(WARNING, quiet_flag_ == QuietLogging::kNo ||
+ quiet_flag_ == QuietLogging::kNotForDebugging)
<< "Failed to start '" << name_ << "' on pid " << pid_
<< " : Exited with status " << exit_code_.value();
}
@@ -609,7 +660,8 @@
<< "Application '" << name_ << "' pid " << pid_
<< " exited with status " << exit_code_.value();
} else {
- if (quiet_flag_ == QuietLogging::kNo) {
+ if (quiet_flag_ == QuietLogging::kNo ||
+ quiet_flag_ == QuietLogging::kNotForDebugging) {
std::string version_string =
latest_timing_report_version_.has_value()
? absl::StrCat("'", latest_timing_report_version_.value(),
diff --git a/aos/starter/subprocess.h b/aos/starter/subprocess.h
index 784c544..9630e00 100644
--- a/aos/starter/subprocess.h
+++ b/aos/starter/subprocess.h
@@ -68,7 +68,14 @@
// automatically.
class Application {
public:
- enum class QuietLogging { kYes, kNo };
+ enum class QuietLogging {
+ kYes,
+ kNo,
+ // For debugging child processes not behaving as expected. When a child
+ // experiences an event such as exiting with an error code or dying to due a
+ // signal, this option will cause a log statement to be printed.
+ kNotForDebugging,
+ };
Application(const aos::Application *application, aos::EventLoop *event_loop,
std::function<void()> on_change,
QuietLogging quiet_flag = QuietLogging::kNo);
@@ -127,6 +134,8 @@
bool autorestart() const { return autorestart_; }
void set_autorestart(bool autorestart) { autorestart_ = autorestart; }
+ LastStopReason stop_reason() const { return stop_reason_; }
+
const std::string &GetStdout();
const std::string &GetStderr();
std::optional<int> exit_code() const { return exit_code_; }
diff --git a/aos/starter/subprocess_reliable_test.cc b/aos/starter/subprocess_reliable_test.cc
new file mode 100644
index 0000000..0460bc3
--- /dev/null
+++ b/aos/starter/subprocess_reliable_test.cc
@@ -0,0 +1,127 @@
+#include <signal.h>
+#include <sys/types.h>
+
+#include <filesystem>
+
+#include "gtest/gtest.h"
+
+#include "aos/events/shm_event_loop.h"
+#include "aos/starter/subprocess.h"
+#include "aos/testing/path.h"
+#include "aos/testing/tmpdir.h"
+#include "aos/util/file.h"
+
+namespace aos::starter::testing {
+
+namespace {
+void Wait(pid_t pid) {
+ int status;
+ if (waitpid(pid, &status, 0) != pid) {
+ if (errno != ECHILD) {
+ PLOG(ERROR) << "Failed to wait for PID " << pid << ": " << status;
+ FAIL();
+ }
+ }
+ LOG(INFO) << "Succesfully waited for PID " << pid;
+}
+
+} // namespace
+
+// Validates that killing a child process right after startup doesn't have any
+// unexpected consequences. The child process should exit even if it hasn't
+// `exec()`d yet.
+TEST(SubprocessTest, KillDuringStartup) {
+ const std::string config_file =
+ ::aos::testing::ArtifactPath("aos/events/pingpong_config.json");
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig(config_file);
+ aos::ShmEventLoop event_loop(&config.message());
+
+ // Run an application that takes a really long time to exit. The exact details
+ // here don't matter. We just need to to survive long enough until we can call
+ // Terminate() below.
+ auto application =
+ std::make_unique<Application>("sleep", "sleep", &event_loop, []() {});
+ application->set_args({"100"});
+
+ // Track whether we exit via our own timer callback. We don't want to exit
+ // because of any strange interactions with the child process.
+ bool exited_as_expected = false;
+
+ // Here's the sequence of events that we expect to see:
+ // 1. Start child process.
+ // 2. Stop child process (via `Terminate()`).
+ // 3. Wait 1 second.
+ // 4. Set `exited_as_expected` to `true`.
+ // 5. Exit the event loop.
+ //
+ // At the end, if `exited_as_expected` is `false`, then something unexpected
+ // happened and we failed the test here.
+ aos::TimerHandler *shutdown_timer = event_loop.AddTimer([&]() {
+ exited_as_expected = true;
+ event_loop.Exit();
+ });
+ aos::TimerHandler *trigger_timer = event_loop.AddTimer([&]() {
+ application->Start();
+ application->Terminate();
+ shutdown_timer->Schedule(event_loop.monotonic_now() +
+ std::chrono::seconds(1));
+ });
+ trigger_timer->Schedule(event_loop.monotonic_now());
+ event_loop.Run();
+ application->Stop();
+ Wait(application->get_pid());
+
+ EXPECT_TRUE(exited_as_expected) << "It looks like we killed ourselves.";
+}
+
+// Validates that the code in subprocess.cc doesn't accidentally block signals
+// in the child process.
+TEST(SubprocessTest, CanKillAfterStartup) {
+ const std::string config_file =
+ ::aos::testing::ArtifactPath("aos/events/pingpong_config.json");
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig(config_file);
+ aos::ShmEventLoop event_loop(&config.message());
+
+ // We create a directory in which we create some files so this test here and
+ // the subsequently created child process can "signal" one another. We roughly
+ // expect the following sequence of events:
+ // 1. Start the child process.
+ // 2. Test waits for "startup" file to be created by child.
+ // 3. Child process creates the "startup" file.
+ // 4. Test sees "startup" file being created, sends SIGTERM to child.
+ // 5. Child sees SIGTERM, creates "shutdown" file, and exits.
+ // 6. Test waits for child to exit.
+ // 7. Test validates that the "shutdown" file was created by the child.
+ auto signal_dir = std::filesystem::path(aos::testing::TestTmpDir()) /
+ "startup_file_signals";
+ ASSERT_TRUE(std::filesystem::create_directory(signal_dir));
+ auto startup_signal_file = signal_dir / "startup";
+ auto shutdown_signal_file = signal_dir / "shutdown";
+
+ auto application = std::make_unique<Application>("/bin/bash", "/bin/bash",
+ &event_loop, []() {});
+ application->set_args(
+ {"-c", absl::StrCat("cleanup() { touch ", shutdown_signal_file.string(),
+ "; exit 0; }; trap cleanup SIGTERM; touch ",
+ startup_signal_file.string(),
+ "; while true; do sleep 0.1; done;")});
+
+ // Wait for the child process to create the "startup" file.
+ ASSERT_FALSE(std::filesystem::exists(startup_signal_file));
+ application->Start();
+ while (!std::filesystem::exists(startup_signal_file)) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ }
+ ASSERT_FALSE(std::filesystem::exists(shutdown_signal_file));
+
+ // Manually kill the application here. The Stop() and Terminate() helpers
+ // trigger some timeout behaviour that interferes with the test here. This
+ // should cause the child to exit and create the "shutdown" file.
+ PCHECK(kill(application->get_pid(), SIGTERM) == 0);
+ Wait(application->get_pid());
+ ASSERT_TRUE(std::filesystem::exists(shutdown_signal_file));
+}
+
+} // namespace aos::starter::testing
diff --git a/aos/util/config_validator_lib.cc b/aos/util/config_validator_lib.cc
index 0f90ed6..e388bb7 100644
--- a/aos/util/config_validator_lib.cc
+++ b/aos/util/config_validator_lib.cc
@@ -177,6 +177,13 @@
const std::string log_path = aos::testing::TestTmpDir() + "/logs/";
for (const bool send_data_on_channels : {false, true}) {
SCOPED_TRACE(send_data_on_channels);
+ // Single nodes (multi-nodes with node count = 1) will not produce readable
+ // logs in the absense of data.
+ if (!send_data_on_channels && (configuration::NodesCount(config) == 1u)) {
+ continue;
+ }
+ // Send timing report when we are sending data.
+ const bool do_skip_timing_report = !send_data_on_channels;
for (const LoggerNodeSetValidation *logger_set :
*validation_config->logging()->logger_sets()) {
SCOPED_TRACE(aos::FlatbufferToJson(logger_set));
@@ -187,9 +194,11 @@
for (const auto &node : *logger_set->loggers()) {
logger_nodes.push_back(node->str());
}
- loggers = MakeLoggersForNodes(&factory, logger_nodes, log_path);
+ loggers = MakeLoggersForNodes(&factory, logger_nodes, log_path,
+ do_skip_timing_report);
} else {
- loggers = MakeLoggersForAllNodes(&factory, log_path);
+ loggers =
+ MakeLoggersForAllNodes(&factory, log_path, do_skip_timing_report);
}
std::vector<std::unique_ptr<EventLoop>> test_loops;
diff --git a/aos/util/simulation_logger.cc b/aos/util/simulation_logger.cc
index 24691ef..513fa65 100644
--- a/aos/util/simulation_logger.cc
+++ b/aos/util/simulation_logger.cc
@@ -4,13 +4,16 @@
namespace aos::util {
LoggerState::LoggerState(aos::SimulatedEventLoopFactory *factory,
- const aos::Node *node, std::string_view output_folder)
+ const aos::Node *node, std::string_view output_folder,
+ bool do_skip_timing_report)
: event_loop_(factory->MakeEventLoop("logger", node)),
namer_(std::make_unique<aos::logger::MultiNodeFilesLogNamer>(
absl::StrCat(output_folder, "/", logger::MaybeNodeName(node), "/"),
event_loop_.get())),
logger_(std::make_unique<aos::logger::Logger>(event_loop_.get())) {
- event_loop_->SkipTimingReport();
+ if (do_skip_timing_report) {
+ event_loop_->SkipTimingReport();
+ }
event_loop_->SkipAosLog();
event_loop_->OnRun([this]() { logger_->StartLogging(std::move(namer_)); });
}
@@ -18,23 +21,24 @@
std::vector<std::unique_ptr<LoggerState>> MakeLoggersForNodes(
aos::SimulatedEventLoopFactory *factory,
const std::vector<std::string> &nodes_to_log,
- std::string_view output_folder) {
+ std::string_view output_folder, bool do_skip_timing_report) {
std::vector<std::unique_ptr<LoggerState>> loggers;
for (const std::string &node : nodes_to_log) {
loggers.emplace_back(std::make_unique<LoggerState>(
factory, aos::configuration::GetNode(factory->configuration(), node),
- output_folder));
+ output_folder, do_skip_timing_report));
}
return loggers;
}
std::vector<std::unique_ptr<LoggerState>> MakeLoggersForAllNodes(
- aos::SimulatedEventLoopFactory *factory, std::string_view output_folder) {
+ aos::SimulatedEventLoopFactory *factory, std::string_view output_folder,
+ bool do_skip_timing_report) {
std::vector<std::unique_ptr<LoggerState>> loggers;
for (const aos::Node *node :
configuration::GetNodes(factory->configuration())) {
- loggers.emplace_back(
- std::make_unique<LoggerState>(factory, node, output_folder));
+ loggers.emplace_back(std::make_unique<LoggerState>(
+ factory, node, output_folder, do_skip_timing_report));
}
return loggers;
}
diff --git a/aos/util/simulation_logger.h b/aos/util/simulation_logger.h
index f431b4c..af43d02 100644
--- a/aos/util/simulation_logger.h
+++ b/aos/util/simulation_logger.h
@@ -9,7 +9,8 @@
class LoggerState {
public:
LoggerState(aos::SimulatedEventLoopFactory *factory, const aos::Node *node,
- std::string_view output_folder);
+ std::string_view output_folder,
+ bool do_skip_timing_report = true);
private:
std::unique_ptr<aos::EventLoop> event_loop_;
@@ -23,11 +24,12 @@
std::vector<std::unique_ptr<LoggerState>> MakeLoggersForNodes(
aos::SimulatedEventLoopFactory *factory,
const std::vector<std::string> &nodes_to_log,
- std::string_view output_folder);
+ std::string_view output_folder, bool do_skip_timing_report = true);
// Creates loggers for all of the nodes.
std::vector<std::unique_ptr<LoggerState>> MakeLoggersForAllNodes(
- aos::SimulatedEventLoopFactory *factory, std::string_view output_folder);
+ aos::SimulatedEventLoopFactory *factory, std::string_view output_folder,
+ bool do_skip_timing_report = true);
} // namespace aos::util
#endif // AOS_UTIL_SIMULATION_LOGGER_H_
diff --git a/compilers/yocto_orin_rootfs.BUILD b/compilers/yocto_orin_rootfs.BUILD
new file mode 100644
index 0000000..425b63a
--- /dev/null
+++ b/compilers/yocto_orin_rootfs.BUILD
@@ -0,0 +1,41 @@
+filegroup(
+ name = "sysroot_files",
+ srcs = glob(
+ include = [
+ "include/**",
+ "lib/**",
+ "lib64/**",
+ "usr/include/**",
+ "usr/lib/**",
+ "usr/lib64/**",
+ ],
+ exclude = [
+ "usr/share/**",
+ ],
+ ),
+ visibility = ["//visibility:public"],
+)
+
+cc_library(
+ name = "argus",
+ srcs = [
+ "usr/lib/libnvargus_socketclient.so",
+ ],
+ hdrs = glob(
+ include = ["usr/include/Argus/**"],
+ ),
+ includes = ["usr/include/Argus/utils/"],
+ visibility = ["//visibility:public"],
+)
+
+cc_library(
+ name = "eglstream",
+ srcs = [
+ #"usr/lib/libnvargus_socketclient.so",
+ ],
+ hdrs = glob(
+ include = ["usr/include/EGLStream/**"],
+ ),
+ includes = ["usr/include/EGLStream/"],
+ visibility = ["//visibility:public"],
+)
diff --git a/debian/BUILD.zlib.bazel b/debian/BUILD.zlib.bazel
index c0f81fa..c859eda 100644
--- a/debian/BUILD.zlib.bazel
+++ b/debian/BUILD.zlib.bazel
@@ -8,6 +8,8 @@
copts = [
"-w",
"-Dverbose=-1",
+ "-Wno-unused-but-set-variable",
+ "-Wno-implicit-function-declaration",
],
includes = [
".",
diff --git a/debian/boringssl.patch b/debian/boringssl.patch
index d12a7db..b7ac2ae 100644
--- a/debian/boringssl.patch
+++ b/debian/boringssl.patch
@@ -49,7 +49,7 @@
# Modern build environments should be able to set this to use atomic
# operations for reference counting rather than locks. However, it's
-@@ -86,17 +103,26 @@ posix_copts = [
+@@ -86,17 +103,29 @@ posix_copts = [
boringssl_copts = select({
":linux_x86_64": posix_copts,
":linux_ppc64le": posix_copts,
@@ -62,7 +62,10 @@
],
"//conditions:default": ["-DOPENSSL_NO_ASM"],
+}) + compiler_select({
-+ "clang": [],
++ "clang": [
++ "-Wno-unused-but-set-variable",
++ "-Wno-array-parameter",
++ ],
+ "gcc": [
+ "-Wno-array-parameter",
+ ],
diff --git a/debian/clapack.BUILD b/debian/clapack.BUILD
index 9ed7f82..c85e2df 100644
--- a/debian/clapack.BUILD
+++ b/debian/clapack.BUILD
@@ -295,7 +295,9 @@
"-Wno-unused-but-set-variable",
] + compiler_select({
"clang": [
+ "-Wno-deprecated-non-prototype",
"-Wno-self-assign",
+ "-Wno-unused-but-set-parameter",
],
"gcc": [
"-Wno-implicit-fallthrough",
diff --git a/debian/curl.BUILD b/debian/curl.BUILD
index 95edb78..a4f6526 100644
--- a/debian/curl.BUILD
+++ b/debian/curl.BUILD
@@ -175,6 +175,8 @@
name = "curl",
srcs = [
"include/curl_config.h",
+ "lib/altsvc.c",
+ "lib/altsvc.h",
"lib/amigaos.h",
"lib/arpa_telnet.h",
"lib/asyn.h",
@@ -198,6 +200,8 @@
"lib/curl_endian.h",
"lib/curl_fnmatch.c",
"lib/curl_fnmatch.h",
+ "lib/curl_get_line.c",
+ "lib/curl_get_line.h",
"lib/curl_gethostname.c",
"lib/curl_gethostname.h",
"lib/curl_gssapi.h",
@@ -227,6 +231,8 @@
"lib/curl_threads.h",
"lib/curlx.h",
"lib/dict.h",
+ "lib/doh.c",
+ "lib/doh.h",
"lib/dotdot.c",
"lib/dotdot.h",
"lib/easy.c",
@@ -295,16 +301,18 @@
"lib/nwos.c",
"lib/parsedate.c",
"lib/parsedate.h",
- "lib/pingpong.h",
"lib/pingpong.c",
+ "lib/pingpong.h",
"lib/pop3.h",
"lib/progress.c",
"lib/progress.h",
+ "lib/psl.c",
+ "lib/psl.h",
"lib/quic.h",
"lib/rand.c",
"lib/rand.h",
- "lib/rename.h",
"lib/rename.c",
+ "lib/rename.h",
"lib/rtsp.c",
"lib/rtsp.h",
"lib/security.c",
@@ -325,8 +333,8 @@
"lib/smb.h",
"lib/smtp.h",
"lib/sockaddr.h",
- "lib/socketpair.h",
"lib/socketpair.c",
+ "lib/socketpair.h",
"lib/socks.c",
"lib/socks.h",
"lib/speedcheck.c",
@@ -352,6 +360,8 @@
"lib/transfer.h",
"lib/url.c",
"lib/url.h",
+ "lib/urlapi.c",
+ "lib/urlapi-int.h",
"lib/urldata.h",
"lib/vauth/cleartext.c",
"lib/vauth/cram.c",
@@ -367,9 +377,12 @@
"lib/vtls/gskit.h",
"lib/vtls/gtls.h",
"lib/vtls/mbedtls.h",
+ "lib/vtls/mesalink.c",
+ "lib/vtls/mesalink.h",
"lib/vtls/nssg.h",
"lib/vtls/openssl.h",
"lib/vtls/schannel.h",
+ "lib/vtls/sectransp.h",
"lib/vtls/vtls.c",
"lib/vtls/vtls.h",
"lib/vtls/wolfssl.h",
@@ -378,19 +391,6 @@
"lib/wildcard.c",
"lib/wildcard.h",
"lib/x509asn1.h",
- "lib/psl.h",
- "lib/psl.c",
- "lib/vtls/sectransp.h",
- "lib/vtls/mesalink.h",
- "lib/vtls/mesalink.c",
- "lib/curl_get_line.h",
- "lib/curl_get_line.c",
- "lib/urlapi-int.h",
- "lib/urlapi.c",
- "lib/altsvc.h",
- "lib/altsvc.c",
- "lib/doh.h",
- "lib/doh.c",
] + select({
":macos": [
"lib/vtls/sectransp.c",
@@ -426,6 +426,7 @@
"-Wno-cast-qual",
"-Wno-format-nonliteral",
"-Wno-tautological-type-limit-compare",
+ "-Wno-unused-but-set-variable",
],
}) + select({
":macos": [
@@ -463,7 +464,7 @@
visibility = ["//visibility:public"],
deps = [
# Use the same version of zlib that gRPC does.
- "@zlib//:zlib",
+ "@zlib",
":define-ca-bundle-location",
] + select({
":windows": [],
diff --git a/debian/gstreamer.BUILD b/debian/gstreamer.BUILD
index f81f206..a9a28ef 100644
--- a/debian/gstreamer.BUILD
+++ b/debian/gstreamer.BUILD
@@ -262,8 +262,8 @@
"usr/include",
"usr/include/glib-2.0",
"usr/include/gstreamer-1.0",
- "usr/include/libsoup-2.4",
"usr/include/json-glib-1.0",
+ "usr/include/libsoup-2.4",
"usr/include/opencv4",
],
linkopts = [
diff --git a/debian/opencv.BUILD b/debian/opencv.BUILD
index 141a286..d6b4378 100644
--- a/debian/opencv.BUILD
+++ b/debian/opencv.BUILD
@@ -263,10 +263,10 @@
name = "opencv",
srcs = select({
"@platforms//cpu:x86_64": [s % "x86_64-linux-gnu" if "%" in s else s for s in _common_srcs_list] + [
- "usr/lib/x86_64-linux-gnu/libmfx.so.1",
- "usr/lib/x86_64-linux-gnu/libquadmath.so.0",
- "usr/lib/x86_64-linux-gnu/libnuma.so.1",
"usr/lib/x86_64-linux-gnu/libcrypto.so.1.1",
+ "usr/lib/x86_64-linux-gnu/libmfx.so.1",
+ "usr/lib/x86_64-linux-gnu/libnuma.so.1",
+ "usr/lib/x86_64-linux-gnu/libquadmath.so.0",
"usr/lib/x86_64-linux-gnu/libssl.so.1.1",
],
"@platforms//cpu:armv7": [s % "arm-linux-gnueabihf" if "%" in s else s for s in _common_srcs_list],
diff --git a/debian/slycot.BUILD b/debian/slycot.BUILD
index 21c0df7..fb3f376 100644
--- a/debian/slycot.BUILD
+++ b/debian/slycot.BUILD
@@ -15,6 +15,7 @@
] + compiler_select({
"clang": [
"-Wno-unused-but-set-parameter",
+ "-Wno-deprecated-non-prototype",
],
"gcc": [
"-Wno-discarded-qualifiers",
diff --git a/frc971/analysis/BUILD b/frc971/analysis/BUILD
index 60528a9..442a7de 100644
--- a/frc971/analysis/BUILD
+++ b/frc971/analysis/BUILD
@@ -58,6 +58,7 @@
"//y2022/control_loops/superstructure:turret_plotter",
"//y2022/localizer:localizer_plotter",
"//y2022/vision:vision_plotter",
+ "//y2023/control_loops/superstructure:superstructure_plotter",
"//y2023/localizer:corrections_plotter",
"//y2023/localizer:localizer_plotter",
],
diff --git a/frc971/analysis/plot_index.ts b/frc971/analysis/plot_index.ts
index 57d5041..1ee85d1 100644
--- a/frc971/analysis/plot_index.ts
+++ b/frc971/analysis/plot_index.ts
@@ -44,6 +44,8 @@
'../../y2022/control_loops/superstructure/turret_plotter'
import {plotSuperstructure as plot2022Superstructure} from
'../../y2022/control_loops/superstructure/superstructure_plotter'
+import {plotSuperstructure as plot2023Superstructure} from
+ '../../y2023/control_loops/superstructure/superstructure_plotter'
import {plotCatapult as plot2022Catapult} from
'../../y2022/control_loops/superstructure/catapult_plotter'
import {plotIntakeFront as plot2022IntakeFront, plotIntakeBack as plot2022IntakeBack} from
@@ -118,6 +120,7 @@
['Robot State', new PlotState(plotDiv, plotRobotState)],
['2023 Vision', new PlotState(plotDiv, plot2023Corrections)],
['2023 Localizer', new PlotState(plotDiv, plot2023Localizer)],
+ ['2023 Superstructure', new PlotState(plotDiv, plot2023Superstructure)],
['2020 Finisher', new PlotState(plotDiv, plot2020Finisher)],
['2020 Accelerator', new PlotState(plotDiv, plot2020Accelerator)],
['2020 Hood', new PlotState(plotDiv, plot2020Hood)],
diff --git a/frc971/constants.h b/frc971/constants.h
index 4f7cb36..cf53287 100644
--- a/frc971/constants.h
+++ b/frc971/constants.h
@@ -70,6 +70,28 @@
struct RelativeEncoderZeroingConstants {};
+struct ContinuousAbsoluteEncoderZeroingConstants {
+ // The number of samples in the moving average filter.
+ size_t average_filter_size;
+ // The distance that the absolute encoder needs to complete a full rotation.
+ // It is presumed that this will always be 2 * pi for any subsystem using this
+ // class, unless you have a continuous system that for some reason doesn't
+ // have a logical period of 1 revolution in radians.
+ double one_revolution_distance;
+ // Measured absolute position of the encoder when at zero.
+ double measured_absolute_position;
+
+ // Threshold for deciding if we are moving. moving_buffer_size samples need to
+ // be within this distance of each other before we use the middle one to zero.
+ double zeroing_threshold;
+ // Buffer size for deciding if we are moving.
+ size_t moving_buffer_size;
+
+ // Value between 0 and 1 indicating what fraction of a revolution
+ // it is acceptable for the offset to move.
+ double allowable_encoder_error;
+};
+
struct AbsoluteEncoderZeroingConstants {
// The number of samples in the moving average filter.
size_t average_filter_size;
diff --git a/frc971/control_loops/BUILD b/frc971/control_loops/BUILD
index 3cdb6ab..31b245b 100644
--- a/frc971/control_loops/BUILD
+++ b/frc971/control_loops/BUILD
@@ -416,6 +416,7 @@
"//aos/util:trapezoid_profile",
"//frc971/control_loops:control_loop",
"//frc971/zeroing",
+ "//frc971/zeroing:pot_and_index",
],
)
@@ -661,6 +662,9 @@
":static_zeroing_single_dof_profiled_subsystem_test_subsystem_output_fbs",
"//aos/testing:googletest",
"//frc971/control_loops:control_loop_test",
+ "//frc971/zeroing:absolute_and_absolute_encoder",
+ "//frc971/zeroing:absolute_encoder",
+ "//frc971/zeroing:pot_and_absolute_encoder",
],
)
diff --git a/frc971/control_loops/drivetrain/line_follow_drivetrain.cc b/frc971/control_loops/drivetrain/line_follow_drivetrain.cc
index 9823f0c..355710c 100644
--- a/frc971/control_loops/drivetrain/line_follow_drivetrain.cc
+++ b/frc971/control_loops/drivetrain/line_follow_drivetrain.cc
@@ -257,7 +257,7 @@
relative_pose_.rel_pos().y(), relative_pose_.rel_theta(),
abs_state(3, 0), abs_state(4, 0))
.finished();
- if (velocity_sign_ * goal_velocity_ < 0) {
+ if (velocity_sign_ * goal_velocity_ < -0.1) {
goal_theta = rel_state(2, 0);
}
controls_goal_ << goal_theta, goal_velocity_, 0.0;
diff --git a/frc971/control_loops/drivetrain/robot_state_plotter.ts b/frc971/control_loops/drivetrain/robot_state_plotter.ts
index 8cffd76..7a9a346 100644
--- a/frc971/control_loops/drivetrain/robot_state_plotter.ts
+++ b/frc971/control_loops/drivetrain/robot_state_plotter.ts
@@ -34,6 +34,9 @@
const brownOut = robotStatePlot.addMessageLine(robotState, ['browned_out']);
brownOut.setColor(BROWN);
brownOut.setDrawLine(false);
+ robotStatePlot.addMessageLine(robotState, ['outputs_enabled'])
+ .setColor(CYAN)
+ .setDrawLine(false);
const enabled = robotStatePlot.addMessageLine(joystickState, ['enabled']);
enabled.setColor(GREEN);
enabled.setDrawLine(false);
diff --git a/frc971/control_loops/drivetrain/trajectory.h b/frc971/control_loops/drivetrain/trajectory.h
index e30ca98..b2cecc0 100644
--- a/frc971/control_loops/drivetrain/trajectory.h
+++ b/frc971/control_loops/drivetrain/trajectory.h
@@ -92,8 +92,8 @@
}
const StateFeedbackLoop<2, 2, 2, double, StateFeedbackHybridPlant<2, 2, 2>,
- HybridKalman<2, 2, 2>>
- &velocity_drivetrain() const {
+ HybridKalman<2, 2, 2>> &
+ velocity_drivetrain() const {
return *velocity_drivetrain_;
}
diff --git a/frc971/control_loops/hybrid_state_feedback_loop.h b/frc971/control_loops/hybrid_state_feedback_loop.h
index d8dbe72..79e7da7 100644
--- a/frc971/control_loops/hybrid_state_feedback_loop.h
+++ b/frc971/control_loops/hybrid_state_feedback_loop.h
@@ -120,8 +120,8 @@
return coefficients().U_max;
}
Scalar U_max(int i, int j) const { return U_max()(i, j); }
- const Eigen::Matrix<Scalar, number_of_inputs, number_of_states>
- &U_limit_coefficient() const {
+ const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &
+ U_limit_coefficient() const {
return coefficients().U_limit_coefficient;
}
Scalar U_limit_coefficient(int i, int j) const {
@@ -145,14 +145,14 @@
Scalar &mutable_Y(int i) { return mutable_Y()(i); }
const StateFeedbackHybridPlantCoefficients<number_of_states, number_of_inputs,
- number_of_outputs, Scalar>
- &coefficients(int index) const {
+ number_of_outputs, Scalar> &
+ coefficients(int index) const {
return *coefficients_[index];
}
const StateFeedbackHybridPlantCoefficients<number_of_states, number_of_inputs,
- number_of_outputs, Scalar>
- &coefficients() const {
+ number_of_outputs, Scalar> &
+ coefficients() const {
return *coefficients_[index_];
}
@@ -398,14 +398,14 @@
int index() const { return index_; }
const HybridKalmanCoefficients<number_of_states, number_of_inputs,
- number_of_outputs>
- &coefficients(int index) const {
+ number_of_outputs> &
+ coefficients(int index) const {
return *coefficients_[index];
}
const HybridKalmanCoefficients<number_of_states, number_of_inputs,
- number_of_outputs>
- &coefficients() const {
+ number_of_outputs> &
+ coefficients() const {
return *coefficients_[index_];
}
diff --git a/frc971/control_loops/profiled_subsystem.h b/frc971/control_loops/profiled_subsystem.h
index dff5aad..2a15201 100644
--- a/frc971/control_loops/profiled_subsystem.h
+++ b/frc971/control_loops/profiled_subsystem.h
@@ -15,6 +15,7 @@
#include "frc971/control_loops/profiled_subsystem_generated.h"
#include "frc971/control_loops/simple_capped_state_feedback_loop.h"
#include "frc971/control_loops/state_feedback_loop.h"
+#include "frc971/zeroing/pot_and_index.h"
#include "frc971/zeroing/zeroing.h"
namespace frc971 {
@@ -60,8 +61,9 @@
}
// Returns the controller.
- const StateFeedbackLoop<number_of_states, number_of_inputs, number_of_outputs>
- &controller() const {
+ const StateFeedbackLoop<number_of_states, number_of_inputs,
+ number_of_outputs> &
+ controller() const {
return *loop_;
}
diff --git a/frc971/control_loops/state_feedback_loop.h b/frc971/control_loops/state_feedback_loop.h
index 295beca..c5d05c1 100644
--- a/frc971/control_loops/state_feedback_loop.h
+++ b/frc971/control_loops/state_feedback_loop.h
@@ -144,8 +144,8 @@
return coefficients().U_max;
}
Scalar U_max(int i, int j = 0) const { return U_max()(i, j); }
- const Eigen::Matrix<Scalar, number_of_inputs, number_of_states>
- &U_limit_coefficient() const {
+ const Eigen::Matrix<Scalar, number_of_inputs, number_of_states> &
+ U_limit_coefficient() const {
return coefficients().U_limit_coefficient;
}
Scalar U_limit_coefficient(int i, int j) const {
@@ -173,14 +173,14 @@
size_t coefficients_size() const { return coefficients_.size(); }
const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
- number_of_outputs, Scalar>
- &coefficients(int index) const {
+ number_of_outputs, Scalar> &
+ coefficients(int index) const {
return *coefficients_[index];
}
const StateFeedbackPlantCoefficients<number_of_states, number_of_inputs,
- number_of_outputs, Scalar>
- &coefficients() const {
+ number_of_outputs, Scalar> &
+ coefficients() const {
return *coefficients_[index_];
}
@@ -326,14 +326,14 @@
int index() const { return index_; }
const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
- number_of_outputs, Scalar>
- &coefficients(int index) const {
+ number_of_outputs, Scalar> &
+ coefficients(int index) const {
return *coefficients_[index];
}
const StateFeedbackControllerCoefficients<number_of_states, number_of_inputs,
- number_of_outputs, Scalar>
- &coefficients() const {
+ number_of_outputs, Scalar> &
+ coefficients() const {
return *coefficients_[index_];
}
@@ -450,14 +450,14 @@
int index() const { return index_; }
const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
- number_of_outputs, Scalar>
- &coefficients(int index) const {
+ number_of_outputs, Scalar> &
+ coefficients(int index) const {
return *coefficients_[index];
}
const StateFeedbackObserverCoefficients<number_of_states, number_of_inputs,
- number_of_outputs, Scalar>
- &coefficients() const {
+ number_of_outputs, Scalar> &
+ coefficients() const {
return *coefficients_[index_];
}
@@ -550,8 +550,8 @@
PlantType *mutable_plant() { return &plant_; }
const StateFeedbackController<number_of_states, number_of_inputs,
- number_of_outputs, Scalar>
- &controller() const {
+ number_of_outputs, Scalar> &
+ controller() const {
return controller_;
}
diff --git a/frc971/control_loops/static_zeroing_single_dof_profiled_subsystem_test.cc b/frc971/control_loops/static_zeroing_single_dof_profiled_subsystem_test.cc
index c886775..ace528e 100644
--- a/frc971/control_loops/static_zeroing_single_dof_profiled_subsystem_test.cc
+++ b/frc971/control_loops/static_zeroing_single_dof_profiled_subsystem_test.cc
@@ -16,6 +16,8 @@
#include "frc971/control_loops/static_zeroing_single_dof_profiled_subsystem_test_pot_and_absolute_position_generated.h"
#include "frc971/control_loops/static_zeroing_single_dof_profiled_subsystem_test_subsystem_goal_generated.h"
#include "frc971/control_loops/static_zeroing_single_dof_profiled_subsystem_test_subsystem_output_generated.h"
+#include "frc971/zeroing/absolute_encoder.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "frc971/zeroing/zeroing.h"
using ::frc971::control_loops::PositionSensorSimulator;
diff --git a/frc971/orin/build_rootfs.py b/frc971/orin/build_rootfs.py
new file mode 100755
index 0000000..f82bed7
--- /dev/null
+++ b/frc971/orin/build_rootfs.py
@@ -0,0 +1,412 @@
+#!/usr/bin/python3
+
+import contextlib
+import pathlib
+import collections
+import subprocess
+import shlex
+import os
+
+IMAGE = "arm64_bookworm_debian_yocto.img"
+YOCTO = "/home/austin/local/jetpack/robot-yocto/build"
+
+REQUIRED_DEPS = ["debootstrap", "u-boot-tools"]
+
+
+@contextlib.contextmanager
+def scoped_loopback(image):
+ """Mounts an image as a loop back device."""
+ result = subprocess.run(["sudo", "losetup", "--show", "-f", image],
+ check=True,
+ stdout=subprocess.PIPE)
+ device = result.stdout.decode('utf-8').strip()
+ print("Mounted", image, "to", repr(device))
+ try:
+ yield device
+ finally:
+ subprocess.run(["sudo", "losetup", "-d", device], check=True)
+
+
+@contextlib.contextmanager
+def scoped_mount(image):
+ """Mounts an image as a partition."""
+ partition = f"{image}.partition"
+ try:
+ os.mkdir(partition)
+ except FileExistsError:
+ pass
+
+ result = subprocess.run(["sudo", "mount", "-o", "loop", image, partition],
+ check=True)
+
+ try:
+ yield partition
+ finally:
+ subprocess.run(
+ ["sudo", "rm", f"{partition}/usr/bin/qemu-aarch64-static"])
+ subprocess.run(["sudo", "umount", partition], check=True)
+
+
+def check_required_deps(deps):
+ """Checks if the provided list of dependencies is installed."""
+ missing_deps = []
+ for dep in deps:
+ result = subprocess.run(["dpkg-query", "-W", "-f='${Status}'", dep],
+ check=True,
+ stdout=subprocess.PIPE)
+
+ if "install ok installed" not in result.stdout.decode('utf-8'):
+ missing_deps.append(dep)
+
+ if len(missing_deps) > 0:
+ print("Missing dependencies, please install:")
+ print("sudo apt-get install", " ".join(missing_deps))
+
+
+def make_image(image):
+ """Makes an image and creates an xfs filesystem on it."""
+ result = subprocess.run([
+ "dd", "if=/dev/zero", f"of={image}", "bs=1", "count=0",
+ "seek=8589934592"
+ ],
+ check=True)
+
+ with scoped_loopback(image) as loopback:
+ subprocess.run([
+ "sudo", "mkfs.xfs", "-d", "su=128k", "-d", "sw=1", "-L", "rootfs",
+ loopback
+ ],
+ check=True)
+
+
+def target_unescaped(cmd):
+ """Runs a command as root with bash -c cmd, ie without escaping."""
+ subprocess.run([
+ "sudo", "chroot", "--userspec=0:0", f"{PARTITION}",
+ "qemu-aarch64-static", "/bin/bash", "-c", cmd
+ ],
+ check=True)
+
+
+def target(cmd):
+ """Runs a command as root with escaping."""
+ target_unescaped(shlex.join([shlex.quote(c) for c in cmd]))
+
+
+def pi_target_unescaped(cmd):
+ """Runs a command as pi with bash -c cmd, ie without escaping."""
+ subprocess.run([
+ "sudo", "chroot", "--userspec=pi:pi", "--groups=pi", f"{PARTITION}",
+ "qemu-aarch64-static", "/bin/bash", "-c", cmd
+ ],
+ check=True)
+
+
+def pi_target(cmd):
+ """Runs a command as pi with escaping."""
+ pi_target_unescaped(shlex.join([shlex.quote(c) for c in cmd]))
+
+
+def copyfile(owner, permissions, file):
+ """Copies a file from contents/{file} with the provided owner and permissions."""
+ print("copyfile", owner, permissions, file)
+ subprocess.run(["sudo", "cp", f"contents/{file}", f"{PARTITION}/{file}"],
+ check=True)
+ subprocess.run(["sudo", "chmod", permissions, f"{PARTITION}/{file}"],
+ check=True)
+ target(["chown", owner, f"/{file}"])
+
+
+def target_mkdir(owner_group, permissions, folder):
+ """Creates a directory recursively with the provided permissions and ownership."""
+ print("target_mkdir", owner_group, permissions, folder)
+ owner, group = owner_group.split('.')
+ target(
+ ["install", "-d", "-m", permissions, "-o", owner, "-g", group, folder])
+
+
+def list_packages():
+ """Lists all installed packages.
+
+ Returns:
+ A dictionary with keys as packages, and values as versions.
+ """
+ result = subprocess.run([
+ "sudo", "chroot", "--userspec=0:0", f"{PARTITION}",
+ "qemu-aarch64-static", "/bin/bash", "-c",
+ "dpkg-query -W -f='${Package} ${Version}\n'"
+ ],
+ check=True,
+ stdout=subprocess.PIPE)
+
+ device = result.stdout.decode('utf-8').strip()
+
+ r = {}
+ for line in result.stdout.decode('utf-8').strip().split('\n'):
+ package, version = line.split(' ')
+ r[package] = version
+
+ return r
+
+
+def list_yocto_packages():
+ """Lists all packages in the Yocto folder.
+
+ Returns:
+ list of Package classes.
+ """
+ Package = collections.namedtuple(
+ 'Package', ['path', 'name', 'version', 'architecture'])
+ result = []
+ pathlist = pathlib.Path(f"{YOCTO}/tmp/deploy/deb").glob('**/*.deb')
+ for path in pathlist:
+ # Strip off the path, .deb, and split on _ to parse the package info.
+ s = os.path.basename(str(path))[:-4].split('_')
+ result.append(Package(str(path), s[0], s[1], s[2]))
+
+ return result
+
+
+def install_packages(new_packages, existing_packages):
+ """Installs the provided yocto packages, if they are new."""
+ # To install the yocto packages, first copy them into a folder in /tmp, then install them, then clean the folder up.
+ target(["mkdir", "-p", "/tmp/yocto_packages"])
+ try:
+ to_install = []
+ for package in new_packages:
+ if package.name in existing_packages and existing_packages[
+ package.name] == package.version:
+ print('Skipping', package)
+ continue
+
+ subprocess.run([
+ "sudo", "cp", package.path,
+ f"{PARTITION}/tmp/yocto_packages/{os.path.basename(package.path)}"
+ ],
+ check=True)
+ to_install.append(package)
+
+ if len(to_install) > 0:
+ target(["dpkg", "-i"] + [
+ f"/tmp/yocto_packages/{os.path.basename(package.path)}"
+ for package in to_install
+ ])
+
+ finally:
+ target(["rm", "-rf", "/tmp/yocto_packages"])
+
+
+def install_virtual_packages(virtual_packages):
+ """Builds and installs the provided virtual packages."""
+ try:
+ target(["mkdir", "-p", "/tmp/yocto_packages"])
+ for virtual_package in virtual_packages:
+ subprocess.run(
+ ["dpkg-deb", "--build", f"virtual_packages/{virtual_package}"],
+ check=True)
+ subprocess.run([
+ "sudo", "cp", f"virtual_packages/{virtual_package}.deb",
+ f"{PARTITION}/tmp/yocto_packages/{virtual_package}.deb"
+ ],
+ check=True)
+
+ target(["dpkg", "-i"] + [
+ f"/tmp/yocto_packages/{package}.deb"
+ for package in virtual_packages
+ ])
+
+ finally:
+ target(["rm", "-rf", "/tmp/yocto_packages"])
+
+
+def main():
+ check_required_deps(REQUIRED_DEPS)
+
+ new_image = not os.path.exists(IMAGE)
+ if new_image:
+ make_image(IMAGE)
+
+ with scoped_mount(IMAGE) as partition:
+ if new_image:
+ subprocess.run([
+ "sudo", "debootstrap", "--arch=arm64", "--no-check-gpg",
+ "--foreign", "bookworm", partition,
+ "http://deb.debian.org/debian/"
+ ],
+ check=True)
+
+ subprocess.run([
+ "sudo", "cp", "/usr/bin/qemu-aarch64-static",
+ f"{partition}/usr/bin/"
+ ],
+ check=True)
+
+ global PARTITION
+ PARTITION = partition
+
+ if new_image:
+ target(["/debootstrap/debootstrap", "--second-stage"])
+
+ target([
+ "useradd", "-m", "-p",
+ '$y$j9T$85lzhdky63CTj.two7Zj20$pVY53UR0VebErMlm8peyrEjmxeiRw/rfXfx..9.xet1',
+ '-s', '/bin/bash', 'pi'
+ ])
+ target(["addgroup", "debug"])
+ target(["addgroup", "crypto"])
+ target(["addgroup", "trusty"])
+
+ if not os.path.exists(
+ f"{partition}/etc/apt/sources.list.d/bullseye-backports.list"):
+ copyfile("root.root", "644",
+ "etc/apt/sources.list.d/bullseye-backports.list")
+ target(["apt-get", "update"])
+
+ target([
+ "apt-get", "-y", "install", "gnupg", "wget", "systemd",
+ "systemd-resolved", "locales"
+ ])
+
+ target(["localedef", "-i", "en_US", "-f", "UTF-8", "en_US.UTF-8"])
+
+ target_mkdir("root.root", "755", "run/systemd")
+ target_mkdir("systemd-resolve.systemd-resolve", "755",
+ "run/systemd/resolve")
+ copyfile("systemd-resolve.systemd-resolve", "644",
+ "run/systemd/resolve/stub-resolv.conf")
+ target(["systemctl", "enable", "systemd-resolved"])
+
+ target([
+ "apt-get", "-y", "install", "bpfcc-tools", "sudo",
+ "openssh-server", "python3", "bash-completion", "git", "v4l-utils",
+ "cpufrequtils", "pmount", "rsync", "vim-nox", "chrony",
+ "libopencv-calib3d406", "libopencv-contrib406",
+ "libopencv-core406", "libopencv-features2d406",
+ "libopencv-flann406", "libopencv-highgui406",
+ "libopencv-imgcodecs406", "libopencv-imgproc406",
+ "libopencv-ml406", "libopencv-objdetect406", "libopencv-photo406",
+ "libopencv-shape406", "libopencv-stitching406",
+ "libopencv-superres406", "libopencv-video406",
+ "libopencv-videoio406", "libopencv-videostab406",
+ "libopencv-viz406", "libnice10", "pmount", "libnice-dev", "feh",
+ "libgstreamer1.0-0", "libgstreamer-plugins-base1.0-0",
+ "libgstreamer-plugins-bad1.0-0", "gstreamer1.0-plugins-base",
+ "gstreamer1.0-plugins-good", "gstreamer1.0-plugins-bad",
+ "gstreamer1.0-plugins-ugly", "gstreamer1.0-nice", "usbutils",
+ "locales", "trace-cmd", "clinfo", "jq", "strace", "sysstat",
+ "lm-sensors", "can-utils", "xfsprogs", "gstreamer1.0-tools",
+ "bridge-utils", "net-tools", "apt-file", "parted", "xxd"
+ ])
+ target(["apt-get", "clean"])
+
+ target(["usermod", "-a", "-G", "sudo", "pi"])
+ target(["usermod", "-a", "-G", "video", "pi"])
+ target(["usermod", "-a", "-G", "systemd-journal", "pi"])
+ target(["usermod", "-a", "-G", "dialout", "pi"])
+
+ virtual_packages = [
+ 'libglib-2.0-0', 'libglvnd', 'libgtk-3-0', 'libxcb-glx', 'wayland'
+ ]
+
+ install_virtual_packages(virtual_packages)
+
+ yocto_package_names = [
+ 'tegra-argus-daemon', 'tegra-firmware', 'tegra-firmware-tegra234',
+ 'tegra-firmware-vic', 'tegra-firmware-xusb',
+ 'tegra-libraries-argus-daemon-base', 'tegra-libraries-camera',
+ 'tegra-libraries-core', 'tegra-libraries-cuda',
+ 'tegra-libraries-eglcore', 'tegra-libraries-glescore',
+ 'tegra-libraries-glxcore', 'tegra-libraries-multimedia',
+ 'tegra-libraries-multimedia-utils',
+ 'tegra-libraries-multimedia-v4l', 'tegra-libraries-nvsci',
+ 'tegra-libraries-vulkan', 'tegra-nvphs', 'tegra-nvphs-base',
+ 'libnvidia-egl-wayland1'
+ ]
+ yocto_packages = list_yocto_packages()
+ packages = list_packages()
+
+ install_packages([
+ package for package in yocto_packages
+ if package.name in yocto_package_names
+ ], packages)
+
+ # Now, install the kernel and modules after all the normal packages are in.
+ yocto_packages_to_install = [
+ package for package in yocto_packages
+ if (package.name.startswith('kernel-module-') or package.name.
+ startswith('kernel-5.10') or package.name == 'kernel-modules')
+ ]
+
+ packages_to_remove = []
+
+ # Remove kernel-module-* packages + kernel- package.
+ for key in packages:
+ if key.startswith('kernel-module') or key.startswith(
+ 'kernel-5.10'):
+ already_installed = False
+ for index, yocto_package in enumerate(
+ yocto_packages_to_install):
+ if key == yocto_package.name and packages[
+ key] == yocto_package.version:
+ print('Found already installed package', key,
+ yocto_package)
+ already_installed = True
+ del yocto_packages_to_install[index]
+ break
+ if not already_installed:
+ packages_to_remove.append(key)
+
+ print("Removing", packages_to_remove)
+ if len(packages_to_remove) > 0:
+ target(['dpkg', '--purge'] + packages_to_remove)
+ print("Installing",
+ [package.name for package in yocto_packages_to_install])
+
+ install_packages(yocto_packages_to_install, packages)
+
+ target(["systemctl", "enable", "nvargus-daemon.service"])
+
+ copyfile("root.root", "644", "etc/sysctl.d/sctp.conf")
+ copyfile("root.root", "644", "etc/systemd/logind.conf")
+ copyfile("root.root", "555",
+ "etc/bash_completion.d/aos_dump_autocomplete")
+ copyfile("root.root", "644", "etc/security/limits.d/rt.conf")
+ copyfile("root.root", "644", "etc/systemd/system/usb-mount@.service")
+ copyfile("root.root", "644", "etc/chrony/chrony.conf")
+ target_mkdir("root.root", "700", "root/bin")
+ target_mkdir("pi.pi", "755", "home/pi/.ssh")
+ copyfile("pi.pi", "600", "home/pi/.ssh/authorized_keys")
+ target_mkdir("root.root", "700", "root/bin")
+ copyfile("root.root", "644", "etc/systemd/system/grow-rootfs.service")
+ copyfile("root.root", "500", "root/bin/change_hostname.sh")
+ copyfile("root.root", "700", "root/trace.sh")
+ copyfile("root.root", "440", "etc/sudoers")
+ copyfile("root.root", "644", "etc/fstab")
+ copyfile("root.root", "644",
+ "var/nvidia/nvcam/settings/camera_overrides.isp")
+
+ target_mkdir("root.root", "755", "etc/systemd/network")
+ copyfile("root.root", "644", "etc/systemd/network/eth0.network")
+ copyfile("root.root", "644", "etc/systemd/network/80-can.network")
+ target(["/root/bin/change_hostname.sh", "pi-971-1"])
+
+ target(["systemctl", "enable", "systemd-networkd"])
+ target(["systemctl", "enable", "grow-rootfs"])
+ target(["apt-file", "update"])
+
+ target(["ldconfig"])
+
+ if not os.path.exists(f"{partition}/home/pi/.dotfiles"):
+ pi_target_unescaped(
+ "cd /home/pi/ && git clone --separate-git-dir=/home/pi/.dotfiles https://github.com/AustinSchuh/.dotfiles.git tmpdotfiles && rsync --recursive --verbose --exclude .git tmpdotfiles/ /home/pi/ && rm -r tmpdotfiles && git --git-dir=/home/pi/.dotfiles/ --work-tree=/home/pi/ config --local status.showUntrackedFiles no"
+ )
+ pi_target(["vim", "-c", "\":qa!\""])
+
+ target_unescaped(
+ "cd /root/ && git clone --separate-git-dir=/root/.dotfiles https://github.com/AustinSchuh/.dotfiles.git tmpdotfiles && rsync --recursive --verbose --exclude .git tmpdotfiles/ /root/ && rm -r tmpdotfiles && git --git-dir=/root/.dotfiles/ --work-tree=/root/ config --local status.showUntrackedFiles no"
+ )
+ target(["vim", "-c", "\":qa!\""])
+
+
+if __name__ == '__main__':
+ main()
diff --git a/frc971/orin/contents/etc/apt/sources.list.d/bullseye-backports.list b/frc971/orin/contents/etc/apt/sources.list.d/bullseye-backports.list
new file mode 100644
index 0000000..6c98bcb
--- /dev/null
+++ b/frc971/orin/contents/etc/apt/sources.list.d/bullseye-backports.list
@@ -0,0 +1,2 @@
+deb http://deb.debian.org/debian bullseye-backports main
+deb http://deb.debian.org/debian bullseye main
diff --git a/frc971/orin/contents/etc/bash_completion.d/aos_dump_autocomplete b/frc971/orin/contents/etc/bash_completion.d/aos_dump_autocomplete
new file mode 100644
index 0000000..1b82c46
--- /dev/null
+++ b/frc971/orin/contents/etc/bash_completion.d/aos_dump_autocomplete
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+if [[ -e "/home/pi/bin/aos_dump_autocomplete.sh" ]]; then
+ . /home/pi/bin/aos_dump_autocomplete.sh
+fi
diff --git a/frc971/orin/contents/etc/chrony/chrony.conf b/frc971/orin/contents/etc/chrony/chrony.conf
new file mode 100644
index 0000000..6e03143
--- /dev/null
+++ b/frc971/orin/contents/etc/chrony/chrony.conf
@@ -0,0 +1,59 @@
+# Welcome to the chrony configuration file. See chrony.conf(5) for more
+# information about usable directives.
+
+# Include configuration files found in /etc/chrony/conf.d.
+confdir /etc/chrony/conf.d
+
+# Use Debian vendor zone.
+pool 2.debian.pool.ntp.org iburst
+
+# Use time sources from DHCP.
+sourcedir /run/chrony-dhcp
+
+# Use NTP sources found in /etc/chrony/sources.d.
+sourcedir /etc/chrony/sources.d
+
+# This directive specify the location of the file containing ID/key pairs for
+# NTP authentication.
+keyfile /etc/chrony/chrony.keys
+
+# This directive specify the file into which chronyd will store the rate
+# information.
+driftfile /var/lib/chrony/chrony.drift
+
+# Save NTS keys and cookies.
+ntsdumpdir /var/lib/chrony
+
+# Uncomment the following line to turn logging on.
+#log tracking measurements statistics
+
+# Log files location.
+logdir /var/log/chrony
+
+# Stop bad estimates upsetting machine clock.
+maxupdateskew 100.0
+
+# This directive enables kernel synchronisation (every 11 minutes) of the
+# real-time clock. Note that it can’t be used along with the 'rtcfile' directive.
+rtcsync
+
+# Always step the time if it's more than 4ms off.
+makestep 0.004 -1
+
+# The next 2 settings are used to control how much slewing of the clock chrony
+# is allowed to do. The total will be the sum of both and we have a hard limit
+# at 500ppm coming from AOS.
+
+# The maximum slewing allowed to correct an offset with the reference clock.
+# Note that this value doesn't include corrections due to frequency errors
+# (drift).
+maxslewrate 200
+
+# Maximum frequency error (drift) of the clock. Chrony will try to compensate
+# for drift and this setting limits how large that correction can be.
+maxdrift 100
+
+# Get TAI-UTC offset and leap seconds from the system tz database.
+# This directive must be commented out when using time sources serving
+# leap-smeared time.
+leapsectz right/UTC
diff --git a/frc971/orin/contents/etc/fstab b/frc971/orin/contents/etc/fstab
new file mode 100644
index 0000000..fd54025
--- /dev/null
+++ b/frc971/orin/contents/etc/fstab
@@ -0,0 +1,8 @@
+# /etc/fstab: static file system information.
+#
+# Use 'blkid' to print the universally unique identifier for a
+# device; this may be used with UUID= as a more robust way to name devices
+# that works even if disks are added and removed. See fstab(5).
+#
+# <file system> <mount point> <type> <options> <dump> <pass>
+/dev/nvme0n1p1 / xfs rw,noatime,discard 0 0
diff --git a/frc971/orin/contents/etc/security/limits.d/rt.conf b/frc971/orin/contents/etc/security/limits.d/rt.conf
new file mode 100644
index 0000000..ad2c08b
--- /dev/null
+++ b/frc971/orin/contents/etc/security/limits.d/rt.conf
@@ -0,0 +1,3 @@
+pi - nice -20
+pi - rtprio 95
+pi - memlock unlimited
diff --git a/frc971/orin/contents/etc/sudoers b/frc971/orin/contents/etc/sudoers
new file mode 100644
index 0000000..4ce0b30
--- /dev/null
+++ b/frc971/orin/contents/etc/sudoers
@@ -0,0 +1,27 @@
+#
+# This file MUST be edited with the 'visudo' command as root.
+#
+# Please consider adding local content in /etc/sudoers.d/ instead of
+# directly modifying this file.
+#
+# See the man page for details on how to write a sudoers file.
+#
+Defaults env_reset
+Defaults mail_badpass
+Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+
+# Host alias specification
+
+# User alias specification
+
+# Cmnd alias specification
+
+# User privilege specification
+root ALL=(ALL:ALL) ALL
+
+# Allow members of group sudo to execute any command
+%sudo ALL=NOPASSWD: ALL
+
+# See sudoers(5) for more information on "@include" directives:
+
+@includedir /etc/sudoers.d
diff --git a/frc971/orin/contents/etc/sysctl.d/sctp.conf b/frc971/orin/contents/etc/sysctl.d/sctp.conf
new file mode 100644
index 0000000..1fcf2ca
--- /dev/null
+++ b/frc971/orin/contents/etc/sysctl.d/sctp.conf
@@ -0,0 +1,4 @@
+# https://wwwx.cs.unc.edu/~sparkst/howto/network_tuning.php
+# Make the buffers big enough for an image
+net.core.wmem_max=8388608
+net.core.rmem_max=8388608
diff --git a/frc971/orin/contents/etc/systemd/logind.conf b/frc971/orin/contents/etc/systemd/logind.conf
new file mode 100644
index 0000000..17ced30
--- /dev/null
+++ b/frc971/orin/contents/etc/systemd/logind.conf
@@ -0,0 +1,36 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# See logind.conf(5) for details.
+
+[Login]
+#NAutoVTs=6
+#ReserveVT=6
+#KillUserProcesses=no
+#KillOnlyUsers=
+#KillExcludeUsers=root
+#InhibitDelayMaxSec=5
+#HandlePowerKey=poweroff
+#HandleSuspendKey=suspend
+#HandleHibernateKey=hibernate
+#HandleLidSwitch=suspend
+#HandleLidSwitchExternalPower=suspend
+#HandleLidSwitchDocked=ignore
+#PowerKeyIgnoreInhibited=no
+#SuspendKeyIgnoreInhibited=no
+#HibernateKeyIgnoreInhibited=no
+#LidSwitchIgnoreInhibited=yes
+#HoldoffTimeoutSec=30s
+#IdleAction=ignore
+#IdleActionSec=30min
+#RuntimeDirectorySize=10%
+
+# We don't want systemd removing IPC. This makes it so nothing new can talk to
+# existing channels.
+RemoveIPC=no
+#InhibitorsMax=8192
+#SessionsMax=8192
diff --git a/frc971/orin/contents/etc/systemd/network/80-can.network b/frc971/orin/contents/etc/systemd/network/80-can.network
new file mode 100644
index 0000000..e75db33
--- /dev/null
+++ b/frc971/orin/contents/etc/systemd/network/80-can.network
@@ -0,0 +1,9 @@
+[Match]
+Name=can0
+
+[CAN]
+BitRate=1M
+DataBitRate=8M
+RestartSec=1000ms
+BusErrorReporting=yes
+FDMode=yes
diff --git a/frc971/orin/contents/etc/systemd/network/eth0.network b/frc971/orin/contents/etc/systemd/network/eth0.network
new file mode 100644
index 0000000..8bfaf61
--- /dev/null
+++ b/frc971/orin/contents/etc/systemd/network/eth0.network
@@ -0,0 +1,11 @@
+[Match]
+Name=eth0
+
+[Network]
+Address=10.9.71.20/24
+Gateway=10.9.71.13
+DNS=8.8.8.8
+
+# ipv6 adds an extra 10 seconds to boot, and we don't use it...
+# Disable all the route discovery and stuff
+LinkLocalAddressing=no
diff --git a/frc971/orin/contents/etc/systemd/system/grow-rootfs.service b/frc971/orin/contents/etc/systemd/system/grow-rootfs.service
new file mode 100644
index 0000000..5ab3803
--- /dev/null
+++ b/frc971/orin/contents/etc/systemd/system/grow-rootfs.service
@@ -0,0 +1,19 @@
+[Unit]
+Description=Grow partition and filesystem to fit disk
+DefaultDependencies=no
+Before=local-fs.target
+Before=shutdown.target
+After=-.mount
+BindsTo=-.mount
+
+# Backport of <https://github.com/systemd/systemd/pull/14618>.
+After=systemd-remount-fs.service
+
+[Service]
+Type=oneshot
+ExecStart=/bin/bash -c "/sbin/xfs_growfs $(systemctl show --property What --value -- -.mount)"
+TimeoutSec=0
+RemainAfterExit=yes
+
+[Install]
+WantedBy=multi-user.target
diff --git a/frc971/orin/contents/etc/systemd/system/usb-mount@.service b/frc971/orin/contents/etc/systemd/system/usb-mount@.service
new file mode 100644
index 0000000..934d456
--- /dev/null
+++ b/frc971/orin/contents/etc/systemd/system/usb-mount@.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Mount USB Drive on %i
+[Service]
+Type=oneshot
+RemainAfterExit=true
+ExecStart=/usr/bin/pmount --umask 000 /dev/%i /media/%i
+ExecStop=/usr/bin/pumount /dev/%i
diff --git a/frc971/orin/contents/home/pi/.ssh/authorized_keys b/frc971/orin/contents/home/pi/.ssh/authorized_keys
new file mode 100644
index 0000000..58b82cc
--- /dev/null
+++ b/frc971/orin/contents/home/pi/.ssh/authorized_keys
@@ -0,0 +1,21 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDI002gCm4aRVrIcg2G4/qF4D1oNY74HFFAHjNUIgvrmqSEn+Oy+pxigpJFiZZaJMJpaw4kpd1IEpZxhooZm4DC4/bVV3wAFTw/OJI7D75WgrRrBRHd95TMBwYyNUhoDOcPAoZ69+IL9P0rhmNjgCv6Y+3PG+Rl6IqRPuf3dXX/PT3E/h8B18PRkEnas/3WTW8goov6x10kVAa5I+iQansiyAbPQF7E+Q5mpsnl26V2vpHo1UAk7y+TD7jqifEn13TmLeTkDXmaIOflQeOBMAdErftuqrClPa00VbejP18v02RI/jOIAQ250g0hN3zvKi2eNHUPdAzlMB4cSvZspRrB /home/austin/.ssh/id_rsa
+
+ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgzaqXNuB589EgR6/ljdYhp5Ca+B8eimCTmmC23oQvNyIAAAADAQABAAABAQDI002gCm4aRVrIcg2G4/qF4D1oNY74HFFAHjNUIgvrmqSEn+Oy+pxigpJFiZZaJMJpaw4kpd1IEpZxhooZm4DC4/bVV3wAFTw/OJI7D75WgrRrBRHd95TMBwYyNUhoDOcPAoZ69+IL9P0rhmNjgCv6Y+3PG+Rl6IqRPuf3dXX/PT3E/h8B18PRkEnas/3WTW8goov6x10kVAa5I+iQansiyAbPQF7E+Q5mpsnl26V2vpHo1UAk7y+TD7jqifEn13TmLeTkDXmaIOflQeOBMAdErftuqrClPa00VbejP18v02RI/jOIAQ250g0hN3zvKi2eNHUPdAzlMB4cSvZspRrBAAAAAAAAAAAAAAABAAAAHmF1c3Rpbi5zY2h1aEBibHVlcml2ZXJ0ZWNoLmNvbQAAAA8AAAADYnJ0AAAABHJvb3QAAAAAWGi3PAAAAABjhSpmAAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAKwAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQAAAIUEANvRmN8fXmKOO6xQPsllgbHxX+hvP4sU8/ayxw1K9C2MlGT3OKPgnjWEmvEPgpPR+/YQ6asQnP+jucdgCM8q7+c4ATwFnMO7yl2LCU1UkCKShzoumXflKC9rWNVT6MY4PTbpQXui5XE0gIZrjKrkcfCGjvRouUasM/C5Zro/aGQFkL6XAAAApwAAABNlY2RzYS1zaGEyLW5pc3RwNTIxAAAAjAAAAEIAswnueuP8iT7Qbzr1yBx6tLbNY9jewA6NEkLnFJtu11VzBFFaLWxeXwKPy3ajT0DCzt6EX6YKBHfYngnzdyjP9KkAAABCAWsxaA9D59ToYmbEKT//85dczH397v6As8WeQMAMzKfJYVSJBceHiwt6EbRKd6m+xUsd/Sr4Bj/Eu2VvwplqCpOq /home/austin/.ssh/id_rsa
+
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLyVTxr8s3kjz+PEjEymgwC8o64IZgBRJbtq9HZ16ufEHqxCD6WK21v8XsbAyTo3/vIfiae+SxhZTC9PMA1AQXuXCBTcvH1avHlHNPgnfxOfzNpU5LSZx/hqrx9tJ+ELV6m34XUbAhIhXJSyiPE2Mst8et6XUvXLgQ8hr0vwXZ3jitI0WzdoZE2svQhn/Cw+NnFiIyhVm4VTnw0bo5XVvvCawvZdTWsyXIvYx9P7rJ5Kvr1eJTZB+tDynzEFxJZeC+lnE6kV8NudC/7hLwwn1Uvqon17Z4P8ukxDsaD2Y4a2v0zqqN0FkEAKjhcqRWdyHM2JOeygRJa1sABNzt4gJB austin@ASchuh-T480s
+
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDDs88Uby+A7k69WSUXp6wmDrsIIFib5bsJ/0oHdjRWSZc4gHVGVF4cFCIJsjvuiQ3LlQ1vVb4ot7kXDNhPWEENRiuMVN3bovTr0fIjSi+YzhidIUZV44LhIkf2XorjpBjfdKE8YyZgYU0wway6myLijoEy6UnLaYerFjUh0k0p+R/axNtD48Glge82pvihosNt4J4592PGbfoTg7hgPizz4Yp39MtYN0OAqHDSrthU/ceA97prMo9tugozHthDasNAb1u/KiOr86dswLiGhwfM0aWAStIu+jie8fKzFtPFFvCyeEaGTYJ/nKiTq2qX2VNLk2zoqXoP6OPHTztejMtRyuRZxx3+mwhDT1lwUQx/ZsFqMTuIOjGQjpzQg3/Q2Y7rnSeQmgc5LglzaH5SRQ7i3nXJvDm1akdHRFFjarBw9Pb2p8DsDaTmJ6gpoEFqZZa1RM5ZCab8bL9z0pHBdpqhIXcPflDQE7Qi8win+LlWBwFyjhu5PvNnAKFEv6uQC1M= austin@aschuh-3950x
+
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDONITvwkh8whp/ac9mhqIk+H4JV7gHIO6OYiOeJfd8mJGAKbox6JNPsnZ2Yewse9oc+MDKZ+dyLqBsfIVG0MUh96hJZHwIYW6wObcZt7Zj6c+JzbAQNavWltsu0IIA7wVrdz2qOXLuH3MhM5URP29IsmF9EUp2H1/iRUMlwz3+1GckYWmiJl+JKNct1DofJb4RdbY2iG34QgS6FvLEKZBxGYPboPD0DLylymdAZAq2TjCcngiq+5BWmy79BLoA2xwJjiz1WPbSILIygfX6e85FGf9ZskylfgHcltAP4xrg3ci7ygJZSw7rd37pV6PfxOz4vGmA7ROT+ocbkXtzkmGk6Qb8HPqT9uRl9Y2Wm4YQMIrREHvjXtGHePCS6R8rrK6og4U4l6Fn4ghicemoRcQXTeX8RJFN+jCpBmks+P6UbYW8k2424kVhNMHz2sHT+BU5Klz9HQvcqlCqupqiPT6HF/gzMZgMHAf2Dp17CpoDbhkhLmCE1TmFOKqNqHP31fs= milindupadhyay@mdu-brt
+
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNUJEb8hoIboZ+FWUp9OX37xRs6s63pXfkF0Hirka+ovIziorNLxR6BixqD7xkVBwXgyMo+YRRy80eHLX2NoItoRLoMfT4uqhu/izdidLcUrpYicAxMIi1pCi1SS5BcKCHbyEqS5FrHzea+0dhIeemb1EP2NXxTDlFUINTni/Aw0z8bB3UI0tY0+K8zypuDKohL9tWOOln6e0VirhPhSCpfs89959jhmeI7Al1DuyZw1vfcaVgQ/7W59rHqP8RNcziMrwwt5hCMQQRxEu4Dd11jBiLklS+wLBI8exP/aEVXGwwc6D/zhg2zma4wQ7HuivZF+sMrP4T1RlLMK3ngbMX james@hp-debian
+
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCaElJXdu6YMo7n32jAYXVPW9HKdp2vbE1BcKz+hqZDiIpMtIwmyu+KQD7XHOfkDrDLlsKRRnEvAKAhE+Q5apHdVwnR70h79khBjvRZqXBt+lip3GyGBuymE6+2bAL6zMnZ6oKBvKcPRdIUEbv1jvJV4SfCERGp0/yQxlf/h+yy2pGTEV2iGZerfYBDIyggDzrhjEeiFUL7In4kR2dQId/BPlzZx9AVIdF6CIY7MnfsPBZUkrk9XQrCJOxzN2gGPLdan3DMCp1o2K93dvojl4dQguphanwOdw8wm+wlMiucY/buHgqqbS0EFOz/taQDBFfQ2v7ckht5CFvCY56YpGFaVW7ztf7OYbU6t8LS3dsoN8+rAesBe9fJhJWR/0zFIAM7WW6j95Sppikqh0ZcaQK2/eMKFqn8R7K9zJ20BOI+QYGNnLvIVXlFzRt0/Qy/GczhejpJddwK9zbYxVKJyMNpVz3ZUlr+nRR2UtlcM+lWe7Kbu3HxTPBNk6vSCXPE+Pc= ravago@rjmacAir
+
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDSB1Nji8HEfnQX6E2FIfyvolrlihiBKukyLMA5isJhtvdaOXVOrSilpd91wB+ljLOfDy+4XWK4+8p84tvggdfvJdsLRtSBhExJNqe2ViyfUqh0O61lZg4Yvw6DGFEdS+DrqIkZh1v3WQ1Py1Mpt5V18dSu42DttHCigXFnYlpZfx9n4QT6GphkWYE3hLWHQH3uSkujzgkr86WreUi4idRDmq/r21H/MBx4q3uwWuftLS6oX79y7aukpieopeoWN8WUNscwUpUpmAn6rdFe/IHl0u8Zw4wmXoYSIQErFGsOK/rA3nKuK0uvVvUQkVKBZpjMOAAuaLugu9NYsOgqIZf/ filip@Filips-MacBook-Pro.local
+
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILZrP0on5xPZHadvlMN2/+iZzEbIeGpS5MT5hXfb+kP0 uid@pop-os
+
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC+t3HrUbZb9P/zWw9+qH9i8HBcCBRO6BS0rYZMz3UuXFSxhLendcqmAJQ+cu1lI0sb2HAyIhv4d5CQrjZ2en/ZyN93DThWNRWA+iH+ybkJhpUiRVSa/e1rz06o//kL+PVoZEHRUpyy7iJgEgcRxnVZd90baMkkm51bF0NSVn+iGCIao76VS+PBGwtQFghJyAvTz+w/hLYmFtXnY2DRfPvbw8H3cehvDhUBY9V+MUwucMU38Yfucr/BguPyw/sRFzRJtpIzP+JFQZzy/Bz4DI06vIWBps6NZqGo+ETXsrlEmNRKXgp3YWMZg/VcT6IIi9NijtDt6gHNDLfxX1Q41cYErBIaUpDKWPpGJ9z+/FxtxxBHwhIQPzSvdxqgsoGKyy7rFfWOPqWHzASsAcdx8V0EPIL4VmJQOd461WRfZxAhDdo2hQe37joRjcHW2i1nJcpVSepMf7EJH/AoYcifp+b+JUpMZx79HmKtE1cua2JcfZ6b20w7rQzLIP3M2WvrDak= deepachainani@Yashs-MBP
+
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDG+8q7VDZv1bI2s/LDLZvjX4HInQobPF9QfBi8sNJdu98drWzSIlTIRMfOFuN8Vbq2E/wr6eKXOUwq/Brxu4sZ6+po6+sT6IqyE5cd+FffNJXZUc+QxXC6maD20i7k8gNJuo+BRa6VbSR25WarRoGT+pYl03jbhR304Wn8wIYIS5cAfaP2wzwNPOvCZzzwJrba2jeoeVWRUTuqLRAw4NNq5eZskdpv7w/3qw901z7RKzuTfYiAnvsRm8o6E0uRncyujzvXoXD2jyWdKC/boIv/l1Is/XwsSJahq1NIK3y95jZHoUXpDQsq49U0wOByBpKEyQYcI54nhfwYagVsYRY9 jim.o@bluerivert.com
diff --git a/frc971/orin/contents/root/bin/change_hostname.sh b/frc971/orin/contents/root/bin/change_hostname.sh
new file mode 100755
index 0000000..785903e
--- /dev/null
+++ b/frc971/orin/contents/root/bin/change_hostname.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+set -xeuo pipefail
+
+HOSTNAME="$1"
+
+# TODO<Jim>: Should probably add handling for imu hostname, too
+if [[ ! "${HOSTNAME}" =~ ^pi-[0-9]*-[0-9]$ ]]; then
+ echo "Invalid hostname ${HOSTNAME}, needs to be pi-[team#]-[pi#]"
+ exit 1
+fi
+
+TEAM_NUMBER="$(echo ${HOSTNAME} | sed 's/pi-\(.*\)-.*/\1/')"
+PI_NUMBER="$(echo ${HOSTNAME} | sed 's/pi-.*-\(.*\)/\1/')"
+IP_BASE="$(echo ${TEAM_NUMBER} | sed 's/\(.*\)\(..\)/10.\1.\2/')"
+IP="${IP_BASE}.$(( 100 + ${PI_NUMBER}))"
+
+echo "Changing to team number ${TEAM_NUMBER}, IP ${IP}"
+
+sed -i "s/^Address=.*$/Address=${IP}\/24/" /etc/systemd/network/eth0.network
+sed -i "s/^Gateway=.*$/Gateway=${IP_BASE}.13/" /etc/systemd/network/eth0.network
+
+echo "${HOSTNAME}" > /etc/hostname
+
+# Make sure a 127.0.* entry exists to make things looking up localhost happy.
+if grep '^127.0.1.1' /etc/hosts > /dev/null;
+then
+ sed -i "s/\(127\.0\.1\.1\t\).*$/\1${HOSTNAME}/" /etc/hosts
+else
+ echo -e "127.0.1.1\t${HOSTNAME}" >> /etc/hosts
+fi
+
+# Put corret team number in pi's IP addresses, or add them if needed
+if grep '^10\.[0-9]*\.[0-9]*\.[0-9]*\s*pi-[0-9]*-[0-9] pi[0-9]$' /etc/hosts >/dev/null ;
+then
+ sed -i "s/^10\.[0-9]*\.[0-9]*\(\.[0-9]*\s*pi-\)[0-9]*\(-[0-9] pi[0-9]\)\(.*\)$/${IP_BASE}\1${TEAM_NUMBER}\2\3/" /etc/hosts
+else
+ for i in {1..6}; do
+ imu=""
+ # Add imu name to pi6. Put space in this string, since extra
+ # spaces otherwise will make the above grep fail
+ if [[ ${i} == 6 ]]; then
+ imu=" imu"
+ fi
+ echo -e "${IP_BASE}.$(( i + 100 ))\tpi-${TEAM_NUMBER}-${i} pi${i}${imu}" >> /etc/hosts
+ done
+fi
+
+# Put correct team number in roborio's address, or add it if missing
+if grep '^10\.[0-9]*\.[0-9]*\.2\s*roborio$' /etc/hosts >/dev/null;
+then
+ sed -i "s/^10\.[0-9]*\.[0-9]*\(\.2\s*roborio\)$/${IP_BASE}\1/" /etc/hosts
+else
+ echo -e "${IP_BASE}.2\troborio" >> /etc/hosts
+fi
diff --git a/frc971/orin/contents/root/trace.sh b/frc971/orin/contents/root/trace.sh
new file mode 100644
index 0000000..4b69b4e
--- /dev/null
+++ b/frc971/orin/contents/root/trace.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+echo 1 > /sys/kernel/debug/tracing/tracing_on
+echo 30720 > /sys/kernel/debug/tracing/buffer_size_kb
+echo 1 > /sys/kernel/debug/tracing/events/tegra_rtcpu/enable
+echo 1 > /sys/kernel/debug/tracing/events/freertos/enable
+echo 2 > /sys/kernel/debug/camrtc/log-level
+echo 1 > /sys/kernel/debug/tracing/events/camera_common/enable
+echo > /sys/kernel/debug/tracing/trace
+
+echo file vi2_fops.c +p > /sys/kernel/debug/dynamic_debug/control
+echo file csi2_fops.c +p > /sys/kernel/debug/dynamic_debug/control
+
+echo file vi4_fops.c +p > /sys/kernel/debug/dynamic_debug/control
+echo file csi.c +p > /sys/kernel/debug/dynamic_debug/control
+echo file csi4_fops.c +p > /sys/kernel/debug/dynamic_debug/control
+echo file nvcsi.c +p > /sys/kernel/debug/dynamic_debug/control
+
+cat /sys/kernel/debug/tracing/trace /sys/kernel/debug/tracing/trace_pipe
diff --git a/frc971/orin/contents/run/systemd/resolve/stub-resolv.conf b/frc971/orin/contents/run/systemd/resolve/stub-resolv.conf
new file mode 100644
index 0000000..fa4bebb
--- /dev/null
+++ b/frc971/orin/contents/run/systemd/resolve/stub-resolv.conf
@@ -0,0 +1,3 @@
+domain lan
+search lan
+nameserver 127.0.0.53
diff --git a/frc971/orin/contents/var/nvidia/nvcam/settings/camera_overrides.isp b/frc971/orin/contents/var/nvidia/nvcam/settings/camera_overrides.isp
new file mode 100644
index 0000000..82363b2
--- /dev/null
+++ b/frc971/orin/contents/var/nvidia/nvcam/settings/camera_overrides.isp
@@ -0,0 +1,1761 @@
+# Char-lite Calibration
+# command: nv_wrapper 0 optical_black_file ..\imx477\outputs\ob.cfg lsc ..\imx477\outputs\lsc.cfg awb ..\imx477\outputs\awb.cfg ccm ..\imx477\outputs\ccm.cfg public_params public_params.cfg out_name ..\imx477\outputs\camera_overrides.isp
+# version: 1.8.0
+# created on: 16-Jul-2020 17:10
+
+#-**************************************************************
+#-* Do not modify
+#-**************************************************************
+#* =============================================================
+#* ISP Configuration Override File
+#* Copyright (c) 2012-2017, NVIDIA CORPORATION. All rights reserved.
+#* Model:model
+#* Integrator:
+#* Part#:
+#* Sensor:sensor
+#* Size:
+#* Version: version
+#* FileName & Location:/data/nvcam/settings/camera_overrides.isp
+#* Updated:Thu Jul 20 19:15:20 2017 PST
+#* =============================================================
+ap15Function.lensShading = TRUE;
+ae.MeanAlg.HigherTarget = 120;
+ae.MeanAlg.LowerTarget = 120;
+ae.MeanAlg.HigherBrightness = 10000;
+ae.MeanAlg.LowerBrightness = 600;
+ae.MeanAlg.SlopFactor = 0.3;
+ae.MeanAlg.MinTailMass = 0.001;
+ae.MeanAlg.CriticalMass = 0.015;
+ae.MeanAlg.ConvergeSpeed = 0.5;
+ae.MaxFstopDeltaPos = 0.4;
+ae.MaxFstopDeltaNeg = 0.5;
+defaults.autoFramerateRange = {7.5, 120.0};
+ae.ApertureStepToFNumberLUT = {2.4};
+ae.ExposureTuningTable.Preview[0] = {2.4, 0.03333, 1.0, 1.0};
+ae.ExposureTuningTable.Preview[1] = {2.4, 0.03333, 2.0, 1.0};
+ae.ExposureTuningTable.Preview[2] = {2.4, 0.03333, 4.0, 1.0};
+ae.ExposureTuningTable.Preview[3] = {2.4, 0.03333, 8.0, 1.0};
+ae.ExposureTuningTable.Preview[4] = {2.4, 0.03333, 8.0, 1.0};
+ae.ExposureTuningTable.Preview[5] = {2.4, 0.06666, 8.0, 1.0};
+ae.ExposureTuningTable.Preview[6] = {2.4, 0.06666, 16.0, 1.0};
+ae.ExposureTuningTable.Preview[6] = {2.4, 0.06666, 22.0, 1.0};
+flicker.ConfidenceThreshold = 32;
+flicker.SuccessFrameCount = 8;
+flicker.FailureFrameCount = 3;
+flicker.CorrectionFreqListEntries = 2;
+flicker.CorrectionFreqList = {100, 120};
+defaults.saturation = 1.0;
+ae.saturation.Preview[0] = {100, 100, 100, 100, 100, 100, 100};
+ae.saturation.Preview[1] = {100, 100, 100, 100, 100, 100, 100};
+ae.saturation.Preview[2] = {100, 100, 100, 100, 100, 100, 100};
+ae.saturation.Preview[3] = {100, 100, 100, 100, 100, 100, 100};
+ae.saturation.Still[0] = {100, 100, 100, 100, 100, 100, 100};
+ae.saturation.Still[1] = {100, 100, 100, 100, 100, 100, 100};
+ae.saturation.Still[2] = {100, 100, 100, 100, 100, 100, 100};
+ae.saturation.Still[3] = {100, 100, 100, 100, 100, 100, 100};
+ae.saturation.Video[0] = {100, 100, 100, 100, 100, 100, 100};
+ae.saturation.Video[1] = {100, 100, 100, 100, 100, 100, 100};
+ae.saturation.Video[2] = {100, 100, 100, 100, 100, 100, 100};
+ae.saturation.Video[3] = {100, 100, 100, 100, 100, 100, 100};
+sharpness.v2.Preview[0] = {3, 3, 5, 5, 5, 5, 5};
+sharpness.v2.Preview[1] = {3, 3, 5, 5, 5, 5, 5};
+sharpness.v2.Preview[2] = {3, 3, 5, 5, 5, 5, 5};
+sharpness.v2.Preview[3] = {3, 3, 5, 5, 5, 5, 5};
+sharpness.v2.Still[0] = {3, 3, 5, 5, 5, 5, 5};
+sharpness.v2.Still[1] = {3, 3, 5, 5, 5, 5, 5};
+sharpness.v2.Still[2] = {3, 3, 5, 5, 5, 5, 5};
+sharpness.v2.Still[3] = {3, 3, 5, 5, 5, 5, 5};
+sharpness.v2.Video[0] = {3, 3, 5, 5, 5, 5, 5};
+sharpness.v2.Video[1] = {3, 3, 5, 5, 5, 5, 5};
+sharpness.v2.Video[2] = {3, 3, 5, 5, 5, 5, 5};
+sharpness.v2.Video[3] = {3, 3, 5, 5, 5, 5, 5};
+tc.Enable=true;
+tc.Version=v2;
+tc.v2.user.presets[0].Gamma.Value=2.4000;
+tc.v2.user.presets[0].UserCurve.Enable=FALSE;
+tc.v2.user.presets[0].UserCurve.Points={ 0.0000, 0.0000, 0.2500, 0.2500, 0.5000, 0.5000, 0.7500, 0.7500, 1.0000, 1.0000 };
+tc.v2.user.presets[0].CurveControl.Enable=TRUE;
+tc.v2.user.presets[0].CurveControl.AdjustHighlights=0.7500;
+tc.v2.user.presets[0].CurveControl.MidtoneBrightness=0.5000;
+tc.v2.user.presets[0].CurveControl.MidtoneContrast=0.5000;
+tc.v2.user.presets[0].CurveControl.AdjustShadows=0.2500;
+tc.v2.user.presets[0].Brightness.Enable=FALSE;
+tc.v2.user.presets[0].Brightness.Value=1.0000;
+tc.v2.user.presets[1].Gamma.Value=2.4000;
+tc.v2.user.presets[1].UserCurve.Enable=FALSE;
+tc.v2.user.presets[1].UserCurve.Points={ 0.0000, 0.0000, 0.2500, 0.2500, 0.5000, 0.5000, 0.7500, 0.7500, 1.0000, 1.0000 };
+tc.v2.user.presets[1].CurveControl.Enable=TRUE;
+tc.v2.user.presets[1].CurveControl.AdjustHighlights=0.7500;
+tc.v2.user.presets[1].CurveControl.MidtoneBrightness=0.5000;
+tc.v2.user.presets[1].CurveControl.MidtoneContrast=0.5000;
+tc.v2.user.presets[1].CurveControl.AdjustShadows=0.2500;
+tc.v2.user.presets[1].Brightness.Enable=FALSE;
+tc.v2.user.presets[1].Brightness.Value=1.0000;
+tc.v2.user.presets[2].Gamma.Value=2.4000;
+tc.v2.user.presets[2].UserCurve.Enable=FALSE;
+tc.v2.user.presets[2].UserCurve.Points={ 0.0000, 0.0000, 0.2500, 0.2500, 0.5000, 0.5000, 0.7500, 0.7500, 1.0000, 1.0000 };
+tc.v2.user.presets[2].CurveControl.Enable=TRUE;
+tc.v2.user.presets[2].CurveControl.AdjustHighlights=0.7500;
+tc.v2.user.presets[2].CurveControl.MidtoneBrightness=0.5000;
+tc.v2.user.presets[2].CurveControl.MidtoneContrast=0.5000;
+tc.v2.user.presets[2].CurveControl.AdjustShadows=0.2500;
+tc.v2.user.presets[2].Brightness.Enable=FALSE;
+tc.v2.user.presets[2].Brightness.Value=1.0000;
+tc.v2.user.presets[3].Gamma.Value=2.4000;
+tc.v2.user.presets[3].UserCurve.Enable=FALSE;
+tc.v2.user.presets[3].UserCurve.Points={ 0.0000, 0.0000, 0.2500, 0.2500, 0.5000, 0.5000, 0.7500, 0.7500, 1.0000, 1.0000 };
+tc.v2.user.presets[3].CurveControl.Enable=TRUE;
+tc.v2.user.presets[3].CurveControl.AdjustHighlights=0.7500;
+tc.v2.user.presets[3].CurveControl.MidtoneBrightness=0.5000;
+tc.v2.user.presets[3].CurveControl.MidtoneContrast=0.5000;
+tc.v2.user.presets[3].CurveControl.AdjustShadows=0.2500;
+tc.v2.user.presets[3].Brightness.Enable=FALSE;
+tc.v2.user.presets[3].Brightness.Value=1.0000;
+tc.v2.user.presets[4].Gamma.Value=2.4000;
+tc.v2.user.presets[4].UserCurve.Enable=FALSE;
+tc.v2.user.presets[4].UserCurve.Points={ 0.0000, 0.0000, 0.2500, 0.2500, 0.5000, 0.5000, 0.7500, 0.7500, 1.0000, 1.0000 };
+tc.v2.user.presets[4].CurveControl.Enable=TRUE;
+tc.v2.user.presets[4].CurveControl.AdjustHighlights=0.7500;
+tc.v2.user.presets[4].CurveControl.MidtoneBrightness=0.5000;
+tc.v2.user.presets[4].CurveControl.MidtoneContrast=0.5000;
+tc.v2.user.presets[4].CurveControl.AdjustShadows=0.2500;
+tc.v2.user.presets[4].Brightness.Enable=FALSE;
+tc.v2.user.presets[4].Brightness.Value=1.0000;
+tc.v2.user.presets[5].Gamma.Value=2.4000;
+tc.v2.user.presets[5].UserCurve.Enable=FALSE;
+tc.v2.user.presets[5].UserCurve.Points={ 0.0000, 0.0000, 0.2500, 0.2500, 0.5000, 0.5000, 0.7500, 0.7500, 1.0000, 1.0000 };
+tc.v2.user.presets[5].CurveControl.Enable=TRUE;
+tc.v2.user.presets[5].CurveControl.AdjustHighlights=0.7500;
+tc.v2.user.presets[5].CurveControl.MidtoneBrightness=0.5000;
+tc.v2.user.presets[5].CurveControl.MidtoneContrast=0.5000;
+tc.v2.user.presets[5].CurveControl.AdjustShadows=0.2500;
+tc.v2.user.presets[5].Brightness.Enable=FALSE;
+tc.v2.user.presets[5].Brightness.Value=1.0000;
+tc.v2.user.presets[6].Gamma.Value=2.4000;
+tc.v2.user.presets[6].UserCurve.Enable=FALSE;
+tc.v2.user.presets[6].UserCurve.Points={ 0.0000, 0.0000, 0.2500, 0.2500, 0.5000, 0.5000, 0.7500, 0.7500, 1.0000, 1.0000 };
+tc.v2.user.presets[6].CurveControl.Enable=TRUE;
+tc.v2.user.presets[6].CurveControl.AdjustHighlights=0.7500;
+tc.v2.user.presets[6].CurveControl.MidtoneBrightness=0.5000;
+tc.v2.user.presets[6].CurveControl.MidtoneContrast=0.5000;
+tc.v2.user.presets[6].CurveControl.AdjustShadows=0.2500;
+tc.v2.user.presets[6].Brightness.Enable=FALSE;
+tc.v2.user.presets[6].Brightness.Value=1.0000;
+tc.v2.user.presets[7].Gamma.Value=2.4000;
+tc.v2.user.presets[7].UserCurve.Enable=FALSE;
+tc.v2.user.presets[7].UserCurve.Points={ 0.0000, 0.0000, 0.2500, 0.2500, 0.5000, 0.5000, 0.7500, 0.7500, 1.0000, 1.0000 };
+tc.v2.user.presets[7].CurveControl.Enable=TRUE;
+tc.v2.user.presets[7].CurveControl.AdjustHighlights=0.7500;
+tc.v2.user.presets[7].CurveControl.MidtoneBrightness=0.5000;
+tc.v2.user.presets[7].CurveControl.MidtoneContrast=0.5000;
+tc.v2.user.presets[7].CurveControl.AdjustShadows=0.2500;
+tc.v2.user.presets[7].Brightness.Enable=FALSE;
+tc.v2.user.presets[7].Brightness.Value=1.0000;
+tc.v2.user.presets[8].Gamma.Value=2.4000;
+tc.v2.user.presets[8].UserCurve.Enable=FALSE;
+tc.v2.user.presets[8].UserCurve.Points={ 0.0000, 0.0000, 0.2500, 0.2500, 0.5000, 0.5000, 0.7500, 0.7500, 1.0000, 1.0000 };
+tc.v2.user.presets[8].CurveControl.Enable=TRUE;
+tc.v2.user.presets[8].CurveControl.AdjustHighlights=0.7500;
+tc.v2.user.presets[8].CurveControl.MidtoneBrightness=0.5000;
+tc.v2.user.presets[8].CurveControl.MidtoneContrast=0.5000;
+tc.v2.user.presets[8].CurveControl.AdjustShadows=0.2500;
+tc.v2.user.presets[8].Brightness.Enable=FALSE;
+tc.v2.user.presets[8].Brightness.Value=1.0000;
+tc.v2.user.UseIndices={ 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+tc.v2.user.FlashUseIndices= { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+tc.v2.UseAxisX={ 1068.0000, 2136.0000, 9970.0000, 14242.0000 };
+tc.v2.UseAxisY={ 1.0000, 1.0000, 1.0000, 1.0000 };
+tc.v2.FlashUseAxisX={ 1068.0000, 2136.0000, 9970.0000, 14242.0000 };
+tc.v2.FlashUseAxisY={ 1.0000, 1.0000, 1.0000, 1.0000 };
+tc.v2.initStats.brightness=3811;
+tc.v2.initStats.tcdre=1.0;
+flash.IntensityCalibrateEnable = false;
+flash.Led1.FlashLevel[1] = 180;
+flash.Led1.TorchLevel[1] = 100;
+af.module_cal_enable = 0;
+af.settle_time = 30;
+af.inf = 220;
+af.macro = 510;
+af.inf_offset = 0;
+af.macro_offset = 0;
+af.macro_max = 100;
+noiseReduction.v2.MaxValue = 7;
+noiseReduction.v2.Preview[0] = { 1, 2, 3, 5, 6, 7, 7 };
+noiseReduction.v2.Preview[1] = { 1, 2, 3, 5, 6, 7, 7 };
+noiseReduction.v2.Preview[2] = { 1, 2, 3, 5, 6, 7, 7 };
+noiseReduction.v2.Preview[3] = { 1, 2, 3, 5, 6, 7, 7 };
+noiseReduction.v2.Still[0] = { 1, 2, 3, 5, 6, 7, 7 };
+noiseReduction.v2.Still[1] = { 1, 2, 3, 5, 6, 7, 7 };
+noiseReduction.v2.Still[2] = { 1, 2, 3, 5, 6, 7, 7 };
+noiseReduction.v2.Still[3] = { 1, 2, 3, 5, 6, 7, 7 };
+noiseReduction.v2.Video[0] = { 1, 2, 3, 5, 6, 7, 7 };
+noiseReduction.v2.Video[1] = { 1, 2, 3, 5, 6, 7, 7 };
+noiseReduction.v2.Video[2] = { 1, 2, 3, 5, 6, 7, 7 };
+noiseReduction.v2.Video[3] = { 1, 2, 3, 5, 6, 7, 7 };
+noiseReduction.v6.Chroma.Enable = TRUE;
+noiseReduction.v6.Luma.Enable = TRUE;
+noiseReduction.v6.Chroma.GainThreshold = 1.0;
+noiseReduction.v6.Luma.GainThreshold = 2.0;
+noiseReduction.v6.NumSignalConditioningPoints = 7;
+noiseReduction.v6.SignalConditioning[0].Gain = 2;
+noiseReduction.v6.SignalConditioning[0].NoiseBlend = 0.95;
+noiseReduction.v6.SignalConditioning[0].Shaping = 1.0;
+noiseReduction.v6.SignalConditioning[1].Gain = 4;
+noiseReduction.v6.SignalConditioning[1].NoiseBlend = 0.90;
+noiseReduction.v6.SignalConditioning[1].Shaping = 1.0;
+noiseReduction.v6.SignalConditioning[2].Gain = 6;
+noiseReduction.v6.SignalConditioning[2].NoiseBlend = 0.86;
+noiseReduction.v6.SignalConditioning[2].Shaping = 1.0;
+noiseReduction.v6.SignalConditioning[3].Gain = 8;
+noiseReduction.v6.SignalConditioning[3].NoiseBlend = 0.82;
+noiseReduction.v6.SignalConditioning[3].Shaping = 1.0;
+noiseReduction.v6.SignalConditioning[4].Gain = 10;
+noiseReduction.v6.SignalConditioning[4].NoiseBlend = 0.80;
+noiseReduction.v6.SignalConditioning[4].Shaping = 1.0;
+noiseReduction.v6.SignalConditioning[5].Gain = 12;
+noiseReduction.v6.SignalConditioning[5].NoiseBlend = 0.79;
+noiseReduction.v6.SignalConditioning[5].Shaping = 1.0;
+noiseReduction.v6.SignalConditioning[6].Gain = 16;
+noiseReduction.v6.SignalConditioning[6].NoiseBlend = 0.40;
+noiseReduction.v6.SignalConditioning[6].Shaping = 1.0;
+noiseReduction.v6.NumChromaPoints = 7;
+noiseReduction.v6.Chroma[0].Gain = 1;
+noiseReduction.v6.Chroma[0].FilterStrength = 0.03;
+noiseReduction.v6.Chroma[0].Levels = 2;
+noiseReduction.v6.Chroma[0].Scaling = 1.0;
+noiseReduction.v6.Chroma[0].SignalBoost = 1.0;
+noiseReduction.v6.Chroma[1].Gain = 1.1;
+noiseReduction.v6.Chroma[1].FilterStrength = 0.04;
+noiseReduction.v6.Chroma[1].Levels = 2;
+noiseReduction.v6.Chroma[1].Scaling = 1.0;
+noiseReduction.v6.Chroma[1].SignalBoost = 1.0;
+noiseReduction.v6.Chroma[2].Gain = 2;
+noiseReduction.v6.Chroma[2].FilterStrength = 0.06;
+noiseReduction.v6.Chroma[2].Levels = 3;
+noiseReduction.v6.Chroma[2].Scaling = 1.0;
+noiseReduction.v6.Chroma[2].SignalBoost = 1.0;
+noiseReduction.v6.Chroma[3].Gain = 4;
+noiseReduction.v6.Chroma[3].FilterStrength = 0.07;
+noiseReduction.v6.Chroma[3].Levels = 3;
+noiseReduction.v6.Chroma[3].Scaling = 1.0;
+noiseReduction.v6.Chroma[3].SignalBoost = 1.0;
+noiseReduction.v6.Chroma[4].Gain = 6;
+noiseReduction.v6.Chroma[4].FilterStrength = 0.08;
+noiseReduction.v6.Chroma[4].Levels = 3;
+noiseReduction.v6.Chroma[4].Scaling = 1.0;
+noiseReduction.v6.Chroma[4].SignalBoost = 1.0;
+noiseReduction.v6.Chroma[5].Gain = 8;
+noiseReduction.v6.Chroma[5].FilterStrength = 0.09;
+noiseReduction.v6.Chroma[5].Levels = 3;
+noiseReduction.v6.Chroma[5].Scaling = 1.0;
+noiseReduction.v6.Chroma[5].SignalBoost = 1.0;
+noiseReduction.v6.Chroma[6].Gain = 10;
+noiseReduction.v6.Chroma[6].FilterStrength = 0.10;
+noiseReduction.v6.Chroma[6].Levels = 3;
+noiseReduction.v6.Chroma[6].Scaling = 1.0;
+noiseReduction.v6.Chroma[6].SignalBoost = 1.0;
+noiseReduction.v6.NumLumaPoints = 7;
+noiseReduction.v6.Luma[0].Gain = 2;
+noiseReduction.v6.Luma[0].FilterStrength = 0.5;
+noiseReduction.v6.Luma[0].Levels = 1;
+noiseReduction.v6.Luma[0].Scaling = 1.0;
+noiseReduction.v6.Luma[0].SignalBoost = 1.0;
+noiseReduction.v6.Luma[1].Gain = 4;
+noiseReduction.v6.Luma[1].FilterStrength = 0.8;
+noiseReduction.v6.Luma[1].Levels = 1;
+noiseReduction.v6.Luma[1].Scaling = 1.0;
+noiseReduction.v6.Luma[1].SignalBoost = 1.0;
+noiseReduction.v6.Luma[2].Gain = 6;
+noiseReduction.v6.Luma[2].FilterStrength = 1.0;
+noiseReduction.v6.Luma[2].Levels = 1;
+noiseReduction.v6.Luma[2].Scaling = 1.0;
+noiseReduction.v6.Luma[2].SignalBoost = 1.0;
+noiseReduction.v6.Luma[3].Gain = 8;
+noiseReduction.v6.Luma[3].FilterStrength = 1.3;
+noiseReduction.v6.Luma[3].Levels = 1;
+noiseReduction.v6.Luma[3].Scaling = 1.0;
+noiseReduction.v6.Luma[3].SignalBoost = 1.0;
+noiseReduction.v6.Luma[4].Gain = 10;
+noiseReduction.v6.Luma[4].FilterStrength = 1.5;
+noiseReduction.v6.Luma[4].Levels = 1;
+noiseReduction.v6.Luma[4].Scaling = 1.0;
+noiseReduction.v6.Luma[4].SignalBoost = 1.0;
+noiseReduction.v6.Luma[5].Gain = 12;
+noiseReduction.v6.Luma[5].FilterStrength = 1.6;
+noiseReduction.v6.Luma[5].Levels = 1;
+noiseReduction.v6.Luma[5].Scaling = 1.0;
+noiseReduction.v6.Luma[5].SignalBoost = 1.0;
+noiseReduction.v6.Luma[6].Gain = 16;
+noiseReduction.v6.Luma[6].FilterStrength = 0.20;
+noiseReduction.v6.Luma[6].Levels = 1;
+noiseReduction.v6.Luma[6].Scaling = 1.0;
+noiseReduction.v6.Luma[6].SignalBoost = 1.0;
+colorEffects.sepia.param1 = -0.1500;
+colorEffects.sepia.param2 = 0.2000;
+colorEffects.aqua.param1 = 0.3000;
+colorEffects.aqua.param2 = -0.3500;
+colorEffects.solarize.numPoints = 4;
+colorEffects.solarize.point[0] = {0, 0};
+colorEffects.solarize.point[1] = {128, 160};
+colorEffects.solarize.point[2] = {196, 160};
+colorEffects.solarize.point[3] = {256, 0};
+colorEffects.solarize.point[4] = {0, 0};
+colorEffects.solarize.point[5] = {0, 0};
+colorEffects.solarize.point[6] = {0, 0};
+colorEffects.solarize.point[7] = {0, 0};
+colorEffects.solarize.point[8] = {0, 0};
+colorEffects.solarize.point[9] = {0, 0};
+colorEffects.posterize.numPoints = 8;
+colorEffects.posterize.point[0] = {0, 0};
+colorEffects.posterize.point[1] = {54, 0};
+colorEffects.posterize.point[2] = {69, 85};
+colorEffects.posterize.point[3] = {123, 85};
+colorEffects.posterize.point[4] = {138, 170};
+colorEffects.posterize.point[5] = {192, 170};
+colorEffects.posterize.point[6] = {207, 256};
+colorEffects.posterize.point[7] = {256, 256};
+colorEffects.posterize.point[8] = {0, 0};
+colorEffects.posterize.point[9] = {0, 0};
+mwbCCTTint.incandescent = {2950, 0.0};
+mwbCCTTint.fluorescent = {4300, 0.0};
+mwbCCTTint.warmfluorescent = {2940, 0.0};
+mwbCCTTint.daylight = {6100, 0.0};
+mwbCCTTint.cloudy = {7000, 0.0};
+mwbCCTTint.twilight = {10000, 0.0};
+mwbCCTTint.shade = {6550, 0.0};
+lensShading.module_cal_enable = 0;
+awb.module_cal_enable = 0;
+lensShading.falloff_PointsCount = 6;
+lensShading.falloff.Preview[0] = {1.0, 20.0};
+lensShading.falloff.Preview[1] = {2.0, 20.0};
+lensShading.falloff.Preview[2] = {4.0, 20.0};
+lensShading.falloff.Preview[3] = {8.0, 20.0};
+lensShading.falloff.Preview[4] = {16.0, 30.0};
+lensShading.falloff.Preview[5] = {32.0, 30.0};
+lensShading.falloff.Still[0] = {1.0, 20.0};
+lensShading.falloff.Still[1] = {2.0, 20.0};
+lensShading.falloff.Still[2] = {4.0, 20.0};
+lensShading.falloff.Still[3] = {8.0, 20.0};
+lensShading.falloff.Still[4] = {16.0, 30.0};
+lensShading.falloff.Still[5] = {32.0, 30.0};
+lensShading.falloff.Video[0] = {1.0, 20.0};
+lensShading.falloff.Video[1] = {2.0, 20.0};
+lensShading.falloff.Video[2] = {4.0, 20.0};
+lensShading.falloff.Video[3] = {8.0, 20.0};
+lensShading.falloff.Video[4] = {16.0, 30.0};
+lensShading.falloff.Video[5] = {32.0, 30.0};
+#-----------------------------------------------------
+# AWB Parameters
+#-----------------------------------------------------
+
+# AWB
+awb.NumGrayLineSoftClampPoints = 2;
+awb.GrayLineSoftClamp[0] = {0.9268, 0.9268};
+awb.GrayLineSoftClamp[1] = {1.6582, 1.6582};
+awb.GrayLineSoftClamp[2] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[3] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[4] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[5] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[6] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[7] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[8] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[9] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[10] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[11] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[12] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[13] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[14] = {0.0000, 0.0000};
+awb.GrayLineSoftClamp[15] = {0.0000, 0.0000};
+awb.GrayLineSoftClampSlopeBeforeFirstPoint = 0.0000;
+awb.GrayLineSoftClampSlopeAfterLastPoint = 0.0000;
+awb.GrayLineThickness = 0.0088;
+awb.HighU = 1.6582;
+awb.LowU = 0.9268;
+awb.v4.NumGrayLineSoftClampPoints = 3;
+awb.v4.GrayLineSoftClamp[0] = {0.9268, 0.9268};
+awb.v4.GrayLineSoftClamp[1] = {0.9268, 0.9268};
+awb.v4.GrayLineSoftClamp[2] = {1.6582, 1.6582};
+awb.v4.GrayLineSoftClamp[3] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClamp[4] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClamp[5] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClamp[6] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClamp[7] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClamp[8] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClamp[9] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClamp[10] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClamp[11] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClamp[12] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClamp[13] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClamp[14] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClamp[15] = {0.0000, 0.0000};
+awb.v4.GrayLineSoftClampSlopeBeforeFirstPoint = 0.0000;
+awb.v4.GrayLineSoftClampSlopeAfterLastPoint = 0.0000;
+awb.v4.GrayLineThickness = 0.0442;
+awb.v4.HighU = 1.6582;
+awb.v4.LowU = 0.9268;
+
+#Lens shading falloff factor
+lensShading.falloff_factor = 20;
+#-**************************************************************************
+#-* Below parameters are calculated from calibration process. Do not edit!
+#-**************************************************************************
+
+# AWB
+awb.GrayLineSlope = -0.9946;
+awb.GrayLineIntercept = 2.4544;
+awb.UtoMIRED = {-330.909004284264, 700.071557556732};
+awb.MIREDtoU = {-0.003021978813, 2.115601414567};
+awb.UtoCCT = {5351.936855019085,-2504.031973940120};
+awb.CCTtoU = {0.000186848243,0.467873975679};
+awb.NumDiscreteLights = 0;
+awb.v4.GrayLineSlope = -0.9946;
+awb.v4.GrayLineIntercept = 2.4544;
+awb.v4.UtoMIRED = {-330.909004284264, 700.071557556732};
+awb.v4.MIREDtoU = {-0.003021978813, 2.115601414567};
+awb.v4.UtoCCT = {5147.548412945803,-2189.798723064104};
+awb.v4.CCTtoU = {0.000194267236,0.425406144322};
+awb.v4.FusionNumLights = 5;
+awb.v4.FusionLights[0] = {224,384,384,135};
+awb.v4.FusionLights[1] = {224,384,384,135};
+awb.v4.FusionLights[2] = {249,594,594,281};
+awb.v4.FusionLights[3] = {227,555,555,253};
+awb.v4.FusionLights[4] = {214,662,662,442};
+awb.v4.FusionInitLight = 4;
+# CCM
+colorCorrection.srgbMatrix[0] = {1.53743000,-0.19831000, 0.05253000};
+colorCorrection.srgbMatrix[1] = {-0.20559000, 1.69073000,-0.45222000};
+colorCorrection.srgbMatrix[2] = {-0.33184000,-0.49242000, 1.39969000};
+# - sensor gain value corresponding to ISO100
+ae.PerChannelGainAdjustment = {1.0, 1.0, 1.0, 1.0};
+
+# Optical Black
+opticalBlack.manualBiasR = 64;
+opticalBlack.manualBiasGR = 64;
+opticalBlack.manualBiasGB = 64;
+opticalBlack.manualBiasB = 64;
+opticalBlack.float.manualBiasR = 0.06256109;
+opticalBlack.float.manualBiasGR = 0.06256109;
+opticalBlack.float.manualBiasGB = 0.06256109;
+opticalBlack.float.manualBiasB = 0.06256109;
+#-----------------------------------------------------
+# Lens Shading Parameters
+ap15Function.lensShading = TRUE;
+
+#-----------------------------------------------------
+
+# Lens Shading Surfaces
+falloff_srfc.controlPoint[0][0] = 0.000000000000;
+falloff_srfc.controlPoint[0][1] = 0.170708874040;
+falloff_srfc.controlPoint[0][2] = 0.340238317593;
+falloff_srfc.controlPoint[0][3] = 0.452085048909;
+falloff_srfc.controlPoint[0][4] = 0.677164760676;
+falloff_srfc.controlPoint[0][5] = 0.677330142506;
+falloff_srfc.controlPoint[0][6] = 0.452002154012;
+falloff_srfc.controlPoint[0][7] = 0.339406304229;
+falloff_srfc.controlPoint[0][8] = 0.170434181672;
+falloff_srfc.controlPoint[0][9] = 0.000000000000;
+falloff_srfc.controlPoint[1][0] = 0.072132534499;
+falloff_srfc.controlPoint[1][1] = 0.296887547258;
+falloff_srfc.controlPoint[1][2] = 0.466416990811;
+falloff_srfc.controlPoint[1][3] = 0.578263722127;
+falloff_srfc.controlPoint[1][4] = 0.803343433894;
+falloff_srfc.controlPoint[1][5] = 0.803508815724;
+falloff_srfc.controlPoint[1][6] = 0.578180827230;
+falloff_srfc.controlPoint[1][7] = 0.465584977447;
+falloff_srfc.controlPoint[1][8] = 0.296612854890;
+falloff_srfc.controlPoint[1][9] = 0.071377962941;
+falloff_srfc.controlPoint[2][0] = 0.167436650479;
+falloff_srfc.controlPoint[2][1] = 0.392191663238;
+falloff_srfc.controlPoint[2][2] = 0.561721106791;
+falloff_srfc.controlPoint[2][3] = 0.673567838107;
+falloff_srfc.controlPoint[2][4] = 0.898647549874;
+falloff_srfc.controlPoint[2][5] = 0.898812931703;
+falloff_srfc.controlPoint[2][6] = 0.673484943209;
+falloff_srfc.controlPoint[2][7] = 0.560889093426;
+falloff_srfc.controlPoint[2][8] = 0.391916970870;
+falloff_srfc.controlPoint[2][9] = 0.166682078921;
+falloff_srfc.controlPoint[3][0] = 0.230173639911;
+falloff_srfc.controlPoint[3][1] = 0.454928652670;
+falloff_srfc.controlPoint[3][2] = 0.624458096222;
+falloff_srfc.controlPoint[3][3] = 0.736304827538;
+falloff_srfc.controlPoint[3][4] = 0.961384539306;
+falloff_srfc.controlPoint[3][5] = 0.961549921135;
+falloff_srfc.controlPoint[3][6] = 0.736221932641;
+falloff_srfc.controlPoint[3][7] = 0.623626082858;
+falloff_srfc.controlPoint[3][8] = 0.454653960301;
+falloff_srfc.controlPoint[3][9] = 0.229419068352;
+falloff_srfc.controlPoint[4][0] = 0.356522103492;
+falloff_srfc.controlPoint[4][1] = 0.581277116251;
+falloff_srfc.controlPoint[4][2] = 0.750806559804;
+falloff_srfc.controlPoint[4][3] = 0.862653291120;
+falloff_srfc.controlPoint[4][4] = 1.087733002887;
+falloff_srfc.controlPoint[4][5] = 1.087898384717;
+falloff_srfc.controlPoint[4][6] = 0.862570396223;
+falloff_srfc.controlPoint[4][7] = 0.749974546440;
+falloff_srfc.controlPoint[4][8] = 0.581002423883;
+falloff_srfc.controlPoint[4][9] = 0.355767531934;
+falloff_srfc.controlPoint[5][0] = 0.356704584387;
+falloff_srfc.controlPoint[5][1] = 0.581459597146;
+falloff_srfc.controlPoint[5][2] = 0.750989040699;
+falloff_srfc.controlPoint[5][3] = 0.862835772015;
+falloff_srfc.controlPoint[5][4] = 1.087915483783;
+falloff_srfc.controlPoint[5][5] = 1.088080865612;
+falloff_srfc.controlPoint[5][6] = 0.862752877118;
+falloff_srfc.controlPoint[5][7] = 0.750157027335;
+falloff_srfc.controlPoint[5][8] = 0.581184904778;
+falloff_srfc.controlPoint[5][9] = 0.355950012829;
+falloff_srfc.controlPoint[6][0] = 0.230082637765;
+falloff_srfc.controlPoint[6][1] = 0.454837650524;
+falloff_srfc.controlPoint[6][2] = 0.624367094077;
+falloff_srfc.controlPoint[6][3] = 0.736213825393;
+falloff_srfc.controlPoint[6][4] = 0.961293537160;
+falloff_srfc.controlPoint[6][5] = 0.961458918989;
+falloff_srfc.controlPoint[6][6] = 0.736130930495;
+falloff_srfc.controlPoint[6][7] = 0.623535080712;
+falloff_srfc.controlPoint[6][8] = 0.454562958156;
+falloff_srfc.controlPoint[6][9] = 0.229328066207;
+falloff_srfc.controlPoint[7][0] = 0.166849337330;
+falloff_srfc.controlPoint[7][1] = 0.391604350089;
+falloff_srfc.controlPoint[7][2] = 0.561133793642;
+falloff_srfc.controlPoint[7][3] = 0.672980524958;
+falloff_srfc.controlPoint[7][4] = 0.898060236726;
+falloff_srfc.controlPoint[7][5] = 0.898225618555;
+falloff_srfc.controlPoint[7][6] = 0.672897630061;
+falloff_srfc.controlPoint[7][7] = 0.560301780278;
+falloff_srfc.controlPoint[7][8] = 0.391329657721;
+falloff_srfc.controlPoint[7][9] = 0.166094765772;
+falloff_srfc.controlPoint[8][0] = 0.071906715933;
+falloff_srfc.controlPoint[8][1] = 0.296661728692;
+falloff_srfc.controlPoint[8][2] = 0.466191172244;
+falloff_srfc.controlPoint[8][3] = 0.578037903561;
+falloff_srfc.controlPoint[8][4] = 0.803117615328;
+falloff_srfc.controlPoint[8][5] = 0.803282997157;
+falloff_srfc.controlPoint[8][6] = 0.577955008663;
+falloff_srfc.controlPoint[8][7] = 0.465359158880;
+falloff_srfc.controlPoint[8][8] = 0.296387036323;
+falloff_srfc.controlPoint[8][9] = 0.071152144374;
+falloff_srfc.controlPoint[9][0] = 0.000000000000;
+falloff_srfc.controlPoint[9][1] = 0.170146049063;
+falloff_srfc.controlPoint[9][2] = 0.339675492615;
+falloff_srfc.controlPoint[9][3] = 0.451522223932;
+falloff_srfc.controlPoint[9][4] = 0.676601935699;
+falloff_srfc.controlPoint[9][5] = 0.676767317528;
+falloff_srfc.controlPoint[9][6] = 0.451439329034;
+falloff_srfc.controlPoint[9][7] = 0.338843479251;
+falloff_srfc.controlPoint[9][8] = 0.169871356694;
+falloff_srfc.controlPoint[9][9] = 0.000000000000;
+lensShading.correction_type.enableWPC = FALSE;
+lensShading.correction_type.enableLSC = TRUE;
+lensShading.ctrlPointsCount = 3;
+lensShading.imageHeight = 3040;
+lensShading.imageWidth = 4056;
+lensShading.leftPatchFactor = 0.25000;
+lensShading.centerPatchFactor = 0.50000;
+lensShading.topPatchFactor = 0.25000;
+lensShading.middlePatchFactor = 0.50000;
+lensShading.ctrlPoints[0].cct = 2856;
+lensShading.ctrlPoints[0].light_family = 1;
+lensShading.ctrlPoints[0].controlPointR[0][0] = 1.134521484375;
+lensShading.ctrlPoints[0].controlPointR[0][1] = 0.960693359375;
+lensShading.ctrlPoints[0].controlPointR[0][2] = 1.151367187500;
+lensShading.ctrlPoints[0].controlPointR[0][3] = 1.100463867188;
+lensShading.ctrlPoints[0].controlPointR[0][4] = 1.139526367188;
+lensShading.ctrlPoints[0].controlPointR[0][5] = 1.077514648438;
+lensShading.ctrlPoints[0].controlPointR[0][6] = 1.081542968750;
+lensShading.ctrlPoints[0].controlPointR[0][7] = 1.109619140625;
+lensShading.ctrlPoints[0].controlPointR[0][8] = 0.838378906250;
+lensShading.ctrlPoints[0].controlPointR[0][9] = 1.468627929688;
+lensShading.ctrlPoints[0].controlPointR[1][0] = 1.025634765625;
+lensShading.ctrlPoints[0].controlPointR[1][1] = 1.146606445313;
+lensShading.ctrlPoints[0].controlPointR[1][2] = 1.111816406250;
+lensShading.ctrlPoints[0].controlPointR[1][3] = 1.135498046875;
+lensShading.ctrlPoints[0].controlPointR[1][4] = 1.042846679688;
+lensShading.ctrlPoints[0].controlPointR[1][5] = 1.204956054688;
+lensShading.ctrlPoints[0].controlPointR[1][6] = 1.078491210938;
+lensShading.ctrlPoints[0].controlPointR[1][7] = 1.197753906250;
+lensShading.ctrlPoints[0].controlPointR[1][8] = 0.818115234375;
+lensShading.ctrlPoints[0].controlPointR[1][9] = 1.154174804688;
+lensShading.ctrlPoints[0].controlPointR[2][0] = 1.112792968750;
+lensShading.ctrlPoints[0].controlPointR[2][1] = 1.075439453125;
+lensShading.ctrlPoints[0].controlPointR[2][2] = 1.148925781250;
+lensShading.ctrlPoints[0].controlPointR[2][3] = 1.136962890625;
+lensShading.ctrlPoints[0].controlPointR[2][4] = 1.143798828125;
+lensShading.ctrlPoints[0].controlPointR[2][5] = 1.107055664063;
+lensShading.ctrlPoints[0].controlPointR[2][6] = 1.113891601563;
+lensShading.ctrlPoints[0].controlPointR[2][7] = 1.111083984375;
+lensShading.ctrlPoints[0].controlPointR[2][8] = 1.073852539063;
+lensShading.ctrlPoints[0].controlPointR[2][9] = 1.022583007813;
+lensShading.ctrlPoints[0].controlPointR[3][0] = 1.095703125000;
+lensShading.ctrlPoints[0].controlPointR[3][1] = 1.097290039063;
+lensShading.ctrlPoints[0].controlPointR[3][2] = 1.140258789063;
+lensShading.ctrlPoints[0].controlPointR[3][3] = 1.126342773438;
+lensShading.ctrlPoints[0].controlPointR[3][4] = 1.130981445313;
+lensShading.ctrlPoints[0].controlPointR[3][5] = 1.116210937500;
+lensShading.ctrlPoints[0].controlPointR[3][6] = 1.117797851563;
+lensShading.ctrlPoints[0].controlPointR[3][7] = 1.092651367188;
+lensShading.ctrlPoints[0].controlPointR[3][8] = 1.078857421875;
+lensShading.ctrlPoints[0].controlPointR[3][9] = 1.041381835938;
+lensShading.ctrlPoints[0].controlPointR[4][0] = 1.107177734375;
+lensShading.ctrlPoints[0].controlPointR[4][1] = 1.159790039063;
+lensShading.ctrlPoints[0].controlPointR[4][2] = 1.095092773438;
+lensShading.ctrlPoints[0].controlPointR[4][3] = 1.141723632813;
+lensShading.ctrlPoints[0].controlPointR[4][4] = 1.090087890625;
+lensShading.ctrlPoints[0].controlPointR[4][5] = 1.096801757813;
+lensShading.ctrlPoints[0].controlPointR[4][6] = 1.114868164063;
+lensShading.ctrlPoints[0].controlPointR[4][7] = 1.161254882813;
+lensShading.ctrlPoints[0].controlPointR[4][8] = 1.033935546875;
+lensShading.ctrlPoints[0].controlPointR[4][9] = 1.079833984375;
+lensShading.ctrlPoints[0].controlPointR[5][0] = 1.095092773438;
+lensShading.ctrlPoints[0].controlPointR[5][1] = 1.094238281250;
+lensShading.ctrlPoints[0].controlPointR[5][2] = 1.160766601563;
+lensShading.ctrlPoints[0].controlPointR[5][3] = 1.147216796875;
+lensShading.ctrlPoints[0].controlPointR[5][4] = 1.112060546875;
+lensShading.ctrlPoints[0].controlPointR[5][5] = 1.165771484375;
+lensShading.ctrlPoints[0].controlPointR[5][6] = 1.118530273438;
+lensShading.ctrlPoints[0].controlPointR[5][7] = 1.082763671875;
+lensShading.ctrlPoints[0].controlPointR[5][8] = 1.109252929688;
+lensShading.ctrlPoints[0].controlPointR[5][9] = 1.014770507813;
+lensShading.ctrlPoints[0].controlPointR[6][0] = 1.158203125000;
+lensShading.ctrlPoints[0].controlPointR[6][1] = 1.112304687500;
+lensShading.ctrlPoints[0].controlPointR[6][2] = 1.166992187500;
+lensShading.ctrlPoints[0].controlPointR[6][3] = 1.148315429688;
+lensShading.ctrlPoints[0].controlPointR[6][4] = 1.166870117188;
+lensShading.ctrlPoints[0].controlPointR[6][5] = 1.145141601563;
+lensShading.ctrlPoints[0].controlPointR[6][6] = 1.122192382813;
+lensShading.ctrlPoints[0].controlPointR[6][7] = 1.142456054688;
+lensShading.ctrlPoints[0].controlPointR[6][8] = 1.010253906250;
+lensShading.ctrlPoints[0].controlPointR[6][9] = 1.154907226563;
+lensShading.ctrlPoints[0].controlPointR[7][0] = 1.243652343750;
+lensShading.ctrlPoints[0].controlPointR[7][1] = 1.133300781250;
+lensShading.ctrlPoints[0].controlPointR[7][2] = 1.146850585938;
+lensShading.ctrlPoints[0].controlPointR[7][3] = 1.158447265625;
+lensShading.ctrlPoints[0].controlPointR[7][4] = 1.169311523438;
+lensShading.ctrlPoints[0].controlPointR[7][5] = 1.160888671875;
+lensShading.ctrlPoints[0].controlPointR[7][6] = 1.123657226563;
+lensShading.ctrlPoints[0].controlPointR[7][7] = 1.081054687500;
+lensShading.ctrlPoints[0].controlPointR[7][8] = 1.047363281250;
+lensShading.ctrlPoints[0].controlPointR[7][9] = 1.225341796875;
+lensShading.ctrlPoints[0].controlPointR[8][0] = 1.191650390625;
+lensShading.ctrlPoints[0].controlPointR[8][1] = 1.046508789063;
+lensShading.ctrlPoints[0].controlPointR[8][2] = 1.124511718750;
+lensShading.ctrlPoints[0].controlPointR[8][3] = 1.161865234375;
+lensShading.ctrlPoints[0].controlPointR[8][4] = 1.163696289063;
+lensShading.ctrlPoints[0].controlPointR[8][5] = 1.153076171875;
+lensShading.ctrlPoints[0].controlPointR[8][6] = 1.125976562500;
+lensShading.ctrlPoints[0].controlPointR[8][7] = 1.067016601563;
+lensShading.ctrlPoints[0].controlPointR[8][8] = 1.066406250000;
+lensShading.ctrlPoints[0].controlPointR[8][9] = 1.251098632813;
+lensShading.ctrlPoints[0].controlPointR[9][0] = 1.592041015625;
+lensShading.ctrlPoints[0].controlPointR[9][1] = 1.106567382813;
+lensShading.ctrlPoints[0].controlPointR[9][2] = 1.173828125000;
+lensShading.ctrlPoints[0].controlPointR[9][3] = 1.132080078125;
+lensShading.ctrlPoints[0].controlPointR[9][4] = 1.157226562500;
+lensShading.ctrlPoints[0].controlPointR[9][5] = 1.137695312500;
+lensShading.ctrlPoints[0].controlPointR[9][6] = 1.100219726563;
+lensShading.ctrlPoints[0].controlPointR[9][7] = 1.160766601563;
+lensShading.ctrlPoints[0].controlPointR[9][8] = 1.062622070313;
+lensShading.ctrlPoints[0].controlPointR[9][9] = 1.739868164063;
+lensShading.ctrlPoints[0].controlPointGR[0][0] = 1.100097656250;
+lensShading.ctrlPoints[0].controlPointGR[0][1] = 1.002075195313;
+lensShading.ctrlPoints[0].controlPointGR[0][2] = 1.099365234375;
+lensShading.ctrlPoints[0].controlPointGR[0][3] = 1.088500976563;
+lensShading.ctrlPoints[0].controlPointGR[0][4] = 1.087158203125;
+lensShading.ctrlPoints[0].controlPointGR[0][5] = 1.086181640625;
+lensShading.ctrlPoints[0].controlPointGR[0][6] = 1.064208984375;
+lensShading.ctrlPoints[0].controlPointGR[0][7] = 1.101684570313;
+lensShading.ctrlPoints[0].controlPointGR[0][8] = 0.797363281250;
+lensShading.ctrlPoints[0].controlPointGR[0][9] = 1.501220703125;
+lensShading.ctrlPoints[0].controlPointGR[1][0] = 1.005615234375;
+lensShading.ctrlPoints[0].controlPointGR[1][1] = 1.123046875000;
+lensShading.ctrlPoints[0].controlPointGR[1][2] = 1.123046875000;
+lensShading.ctrlPoints[0].controlPointGR[1][3] = 1.106079101563;
+lensShading.ctrlPoints[0].controlPointGR[1][4] = 1.078369140625;
+lensShading.ctrlPoints[0].controlPointGR[1][5] = 1.133789062500;
+lensShading.ctrlPoints[0].controlPointGR[1][6] = 1.052612304688;
+lensShading.ctrlPoints[0].controlPointGR[1][7] = 1.211547851563;
+lensShading.ctrlPoints[0].controlPointGR[1][8] = 0.774658203125;
+lensShading.ctrlPoints[0].controlPointGR[1][9] = 1.173461914063;
+lensShading.ctrlPoints[0].controlPointGR[2][0] = 1.088745117188;
+lensShading.ctrlPoints[0].controlPointGR[2][1] = 1.061279296875;
+lensShading.ctrlPoints[0].controlPointGR[2][2] = 1.074218750000;
+lensShading.ctrlPoints[0].controlPointGR[2][3] = 1.102661132813;
+lensShading.ctrlPoints[0].controlPointGR[2][4] = 1.085937500000;
+lensShading.ctrlPoints[0].controlPointGR[2][5] = 1.096435546875;
+lensShading.ctrlPoints[0].controlPointGR[2][6] = 1.085571289063;
+lensShading.ctrlPoints[0].controlPointGR[2][7] = 1.080810546875;
+lensShading.ctrlPoints[0].controlPointGR[2][8] = 1.092163085938;
+lensShading.ctrlPoints[0].controlPointGR[2][9] = 0.992431640625;
+lensShading.ctrlPoints[0].controlPointGR[3][0] = 1.065063476563;
+lensShading.ctrlPoints[0].controlPointGR[3][1] = 1.099609375000;
+lensShading.ctrlPoints[0].controlPointGR[3][2] = 1.099365234375;
+lensShading.ctrlPoints[0].controlPointGR[3][3] = 1.106689453125;
+lensShading.ctrlPoints[0].controlPointGR[3][4] = 1.090698242188;
+lensShading.ctrlPoints[0].controlPointGR[3][5] = 1.088623046875;
+lensShading.ctrlPoints[0].controlPointGR[3][6] = 1.085571289063;
+lensShading.ctrlPoints[0].controlPointGR[3][7] = 1.080322265625;
+lensShading.ctrlPoints[0].controlPointGR[3][8] = 1.042724609375;
+lensShading.ctrlPoints[0].controlPointGR[3][9] = 1.036987304688;
+lensShading.ctrlPoints[0].controlPointGR[4][0] = 1.100708007813;
+lensShading.ctrlPoints[0].controlPointGR[4][1] = 1.085083007813;
+lensShading.ctrlPoints[0].controlPointGR[4][2] = 1.118652343750;
+lensShading.ctrlPoints[0].controlPointGR[4][3] = 1.099121093750;
+lensShading.ctrlPoints[0].controlPointGR[4][4] = 1.078613281250;
+lensShading.ctrlPoints[0].controlPointGR[4][5] = 1.072509765625;
+lensShading.ctrlPoints[0].controlPointGR[4][6] = 1.091186523438;
+lensShading.ctrlPoints[0].controlPointGR[4][7] = 1.120605468750;
+lensShading.ctrlPoints[0].controlPointGR[4][8] = 1.055175781250;
+lensShading.ctrlPoints[0].controlPointGR[4][9] = 1.049072265625;
+lensShading.ctrlPoints[0].controlPointGR[5][0] = 1.065551757813;
+lensShading.ctrlPoints[0].controlPointGR[5][1] = 1.103759765625;
+lensShading.ctrlPoints[0].controlPointGR[5][2] = 1.095458984375;
+lensShading.ctrlPoints[0].controlPointGR[5][3] = 1.116943359375;
+lensShading.ctrlPoints[0].controlPointGR[5][4] = 1.092529296875;
+lensShading.ctrlPoints[0].controlPointGR[5][5] = 1.109741210938;
+lensShading.ctrlPoints[0].controlPointGR[5][6] = 1.088989257813;
+lensShading.ctrlPoints[0].controlPointGR[5][7] = 1.098632812500;
+lensShading.ctrlPoints[0].controlPointGR[5][8] = 1.044067382813;
+lensShading.ctrlPoints[0].controlPointGR[5][9] = 1.027587890625;
+lensShading.ctrlPoints[0].controlPointGR[6][0] = 1.129882812500;
+lensShading.ctrlPoints[0].controlPointGR[6][1] = 1.072387695313;
+lensShading.ctrlPoints[0].controlPointGR[6][2] = 1.142822265625;
+lensShading.ctrlPoints[0].controlPointGR[6][3] = 1.111816406250;
+lensShading.ctrlPoints[0].controlPointGR[6][4] = 1.127075195313;
+lensShading.ctrlPoints[0].controlPointGR[6][5] = 1.117553710938;
+lensShading.ctrlPoints[0].controlPointGR[6][6] = 1.098876953125;
+lensShading.ctrlPoints[0].controlPointGR[6][7] = 1.090087890625;
+lensShading.ctrlPoints[0].controlPointGR[6][8] = 1.019653320313;
+lensShading.ctrlPoints[0].controlPointGR[6][9] = 1.123779296875;
+lensShading.ctrlPoints[0].controlPointGR[7][0] = 1.216796875000;
+lensShading.ctrlPoints[0].controlPointGR[7][1] = 1.040893554688;
+lensShading.ctrlPoints[0].controlPointGR[7][2] = 1.096801757813;
+lensShading.ctrlPoints[0].controlPointGR[7][3] = 1.152221679688;
+lensShading.ctrlPoints[0].controlPointGR[7][4] = 1.105346679688;
+lensShading.ctrlPoints[0].controlPointGR[7][5] = 1.128295898438;
+lensShading.ctrlPoints[0].controlPointGR[7][6] = 1.091186523438;
+lensShading.ctrlPoints[0].controlPointGR[7][7] = 1.113647460938;
+lensShading.ctrlPoints[0].controlPointGR[7][8] = 0.949462890625;
+lensShading.ctrlPoints[0].controlPointGR[7][9] = 1.240234375000;
+lensShading.ctrlPoints[0].controlPointGR[8][0] = 1.189575195313;
+lensShading.ctrlPoints[0].controlPointGR[8][1] = 1.028442382813;
+lensShading.ctrlPoints[0].controlPointGR[8][2] = 1.112915039063;
+lensShading.ctrlPoints[0].controlPointGR[8][3] = 1.089843750000;
+lensShading.ctrlPoints[0].controlPointGR[8][4] = 1.161132812500;
+lensShading.ctrlPoints[0].controlPointGR[8][5] = 1.097900390625;
+lensShading.ctrlPoints[0].controlPointGR[8][6] = 1.094238281250;
+lensShading.ctrlPoints[0].controlPointGR[8][7] = 1.018676757813;
+lensShading.ctrlPoints[0].controlPointGR[8][8] = 1.049926757813;
+lensShading.ctrlPoints[0].controlPointGR[8][9] = 1.245361328125;
+lensShading.ctrlPoints[0].controlPointGR[9][0] = 1.515502929688;
+lensShading.ctrlPoints[0].controlPointGR[9][1] = 1.076782226563;
+lensShading.ctrlPoints[0].controlPointGR[9][2] = 1.101684570313;
+lensShading.ctrlPoints[0].controlPointGR[9][3] = 1.114746093750;
+lensShading.ctrlPoints[0].controlPointGR[9][4] = 1.101440429688;
+lensShading.ctrlPoints[0].controlPointGR[9][5] = 1.131469726563;
+lensShading.ctrlPoints[0].controlPointGR[9][6] = 1.059570312500;
+lensShading.ctrlPoints[0].controlPointGR[9][7] = 1.145385742188;
+lensShading.ctrlPoints[0].controlPointGR[9][8] = 1.019897460938;
+lensShading.ctrlPoints[0].controlPointGR[9][9] = 1.733398437500;
+lensShading.ctrlPoints[0].controlPointGB[0][0] = 1.117187500000;
+lensShading.ctrlPoints[0].controlPointGB[0][1] = 1.017211914063;
+lensShading.ctrlPoints[0].controlPointGB[0][2] = 1.104248046875;
+lensShading.ctrlPoints[0].controlPointGB[0][3] = 1.093139648438;
+lensShading.ctrlPoints[0].controlPointGB[0][4] = 1.103027343750;
+lensShading.ctrlPoints[0].controlPointGB[0][5] = 1.083740234375;
+lensShading.ctrlPoints[0].controlPointGB[0][6] = 1.072387695313;
+lensShading.ctrlPoints[0].controlPointGB[0][7] = 1.144775390625;
+lensShading.ctrlPoints[0].controlPointGB[0][8] = 0.770751953125;
+lensShading.ctrlPoints[0].controlPointGB[0][9] = 1.514770507813;
+lensShading.ctrlPoints[0].controlPointGB[1][0] = 1.018310546875;
+lensShading.ctrlPoints[0].controlPointGB[1][1] = 1.127197265625;
+lensShading.ctrlPoints[0].controlPointGB[1][2] = 1.090209960938;
+lensShading.ctrlPoints[0].controlPointGB[1][3] = 1.122802734375;
+lensShading.ctrlPoints[0].controlPointGB[1][4] = 1.068603515625;
+lensShading.ctrlPoints[0].controlPointGB[1][5] = 1.144165039063;
+lensShading.ctrlPoints[0].controlPointGB[1][6] = 1.074829101563;
+lensShading.ctrlPoints[0].controlPointGB[1][7] = 1.159301757813;
+lensShading.ctrlPoints[0].controlPointGB[1][8] = 0.852539062500;
+lensShading.ctrlPoints[0].controlPointGB[1][9] = 1.158813476563;
+lensShading.ctrlPoints[0].controlPointGB[2][0] = 1.115112304688;
+lensShading.ctrlPoints[0].controlPointGB[2][1] = 1.026489257813;
+lensShading.ctrlPoints[0].controlPointGB[2][2] = 1.140136718750;
+lensShading.ctrlPoints[0].controlPointGB[2][3] = 1.093750000000;
+lensShading.ctrlPoints[0].controlPointGB[2][4] = 1.116455078125;
+lensShading.ctrlPoints[0].controlPointGB[2][5] = 1.094360351563;
+lensShading.ctrlPoints[0].controlPointGB[2][6] = 1.088623046875;
+lensShading.ctrlPoints[0].controlPointGB[2][7] = 1.106933593750;
+lensShading.ctrlPoints[0].controlPointGB[2][8] = 1.067504882813;
+lensShading.ctrlPoints[0].controlPointGB[2][9] = 1.041259765625;
+lensShading.ctrlPoints[0].controlPointGB[3][0] = 1.063110351563;
+lensShading.ctrlPoints[0].controlPointGB[3][1] = 1.118896484375;
+lensShading.ctrlPoints[0].controlPointGB[3][2] = 1.090820312500;
+lensShading.ctrlPoints[0].controlPointGB[3][3] = 1.110229492188;
+lensShading.ctrlPoints[0].controlPointGB[3][4] = 1.095947265625;
+lensShading.ctrlPoints[0].controlPointGB[3][5] = 1.096557617188;
+lensShading.ctrlPoints[0].controlPointGB[3][6] = 1.090942382813;
+lensShading.ctrlPoints[0].controlPointGB[3][7] = 1.093261718750;
+lensShading.ctrlPoints[0].controlPointGB[3][8] = 1.048706054688;
+lensShading.ctrlPoints[0].controlPointGB[3][9] = 1.037231445313;
+lensShading.ctrlPoints[0].controlPointGB[4][0] = 1.107788085938;
+lensShading.ctrlPoints[0].controlPointGB[4][1] = 1.068359375000;
+lensShading.ctrlPoints[0].controlPointGB[4][2] = 1.127197265625;
+lensShading.ctrlPoints[0].controlPointGB[4][3] = 1.099121093750;
+lensShading.ctrlPoints[0].controlPointGB[4][4] = 1.084106445313;
+lensShading.ctrlPoints[0].controlPointGB[4][5] = 1.066650390625;
+lensShading.ctrlPoints[0].controlPointGB[4][6] = 1.100585937500;
+lensShading.ctrlPoints[0].controlPointGB[4][7] = 1.133056640625;
+lensShading.ctrlPoints[0].controlPointGB[4][8] = 1.051391601563;
+lensShading.ctrlPoints[0].controlPointGB[4][9] = 1.067993164063;
+lensShading.ctrlPoints[0].controlPointGB[5][0] = 1.061889648438;
+lensShading.ctrlPoints[0].controlPointGB[5][1] = 1.123413085938;
+lensShading.ctrlPoints[0].controlPointGB[5][2] = 1.090698242188;
+lensShading.ctrlPoints[0].controlPointGB[5][3] = 1.124145507813;
+lensShading.ctrlPoints[0].controlPointGB[5][4] = 1.074584960938;
+lensShading.ctrlPoints[0].controlPointGB[5][5] = 1.134033203125;
+lensShading.ctrlPoints[0].controlPointGB[5][6] = 1.088500976563;
+lensShading.ctrlPoints[0].controlPointGB[5][7] = 1.110351562500;
+lensShading.ctrlPoints[0].controlPointGB[5][8] = 1.036376953125;
+lensShading.ctrlPoints[0].controlPointGB[5][9] = 1.032226562500;
+lensShading.ctrlPoints[0].controlPointGB[6][0] = 1.125488281250;
+lensShading.ctrlPoints[0].controlPointGB[6][1] = 1.076782226563;
+lensShading.ctrlPoints[0].controlPointGB[6][2] = 1.135009765625;
+lensShading.ctrlPoints[0].controlPointGB[6][3] = 1.111694335938;
+lensShading.ctrlPoints[0].controlPointGB[6][4] = 1.130371093750;
+lensShading.ctrlPoints[0].controlPointGB[6][5] = 1.120483398438;
+lensShading.ctrlPoints[0].controlPointGB[6][6] = 1.097290039063;
+lensShading.ctrlPoints[0].controlPointGB[6][7] = 1.094482421875;
+lensShading.ctrlPoints[0].controlPointGB[6][8] = 1.017700195313;
+lensShading.ctrlPoints[0].controlPointGB[6][9] = 1.139282226563;
+lensShading.ctrlPoints[0].controlPointGB[7][0] = 1.214599609375;
+lensShading.ctrlPoints[0].controlPointGB[7][1] = 1.060180664063;
+lensShading.ctrlPoints[0].controlPointGB[7][2] = 1.109130859375;
+lensShading.ctrlPoints[0].controlPointGB[7][3] = 1.139404296875;
+lensShading.ctrlPoints[0].controlPointGB[7][4] = 1.105468750000;
+lensShading.ctrlPoints[0].controlPointGB[7][5] = 1.122070312500;
+lensShading.ctrlPoints[0].controlPointGB[7][6] = 1.092529296875;
+lensShading.ctrlPoints[0].controlPointGB[7][7] = 1.104370117188;
+lensShading.ctrlPoints[0].controlPointGB[7][8] = 0.979003906250;
+lensShading.ctrlPoints[0].controlPointGB[7][9] = 1.221557617188;
+lensShading.ctrlPoints[0].controlPointGB[8][0] = 1.171875000000;
+lensShading.ctrlPoints[0].controlPointGB[8][1] = 1.030273437500;
+lensShading.ctrlPoints[0].controlPointGB[8][2] = 1.096435546875;
+lensShading.ctrlPoints[0].controlPointGB[8][3] = 1.103759765625;
+lensShading.ctrlPoints[0].controlPointGB[8][4] = 1.139770507813;
+lensShading.ctrlPoints[0].controlPointGB[8][5] = 1.121459960938;
+lensShading.ctrlPoints[0].controlPointGB[8][6] = 1.088989257813;
+lensShading.ctrlPoints[0].controlPointGB[8][7] = 1.006225585938;
+lensShading.ctrlPoints[0].controlPointGB[8][8] = 1.081665039063;
+lensShading.ctrlPoints[0].controlPointGB[8][9] = 1.246459960938;
+lensShading.ctrlPoints[0].controlPointGB[9][0] = 1.529052734375;
+lensShading.ctrlPoints[0].controlPointGB[9][1] = 1.055419921875;
+lensShading.ctrlPoints[0].controlPointGB[9][2] = 1.115356445313;
+lensShading.ctrlPoints[0].controlPointGB[9][3] = 1.094238281250;
+lensShading.ctrlPoints[0].controlPointGB[9][4] = 1.119750976563;
+lensShading.ctrlPoints[0].controlPointGB[9][5] = 1.108276367188;
+lensShading.ctrlPoints[0].controlPointGB[9][6] = 1.066284179688;
+lensShading.ctrlPoints[0].controlPointGB[9][7] = 1.156982421875;
+lensShading.ctrlPoints[0].controlPointGB[9][8] = 0.994873046875;
+lensShading.ctrlPoints[0].controlPointGB[9][9] = 1.735473632813;
+lensShading.ctrlPoints[0].controlPointB[0][0] = 1.137939453125;
+lensShading.ctrlPoints[0].controlPointB[0][1] = 1.042846679688;
+lensShading.ctrlPoints[0].controlPointB[0][2] = 1.180297851563;
+lensShading.ctrlPoints[0].controlPointB[0][3] = 1.141113281250;
+lensShading.ctrlPoints[0].controlPointB[0][4] = 1.173828125000;
+lensShading.ctrlPoints[0].controlPointB[0][5] = 1.112426757813;
+lensShading.ctrlPoints[0].controlPointB[0][6] = 1.125732421875;
+lensShading.ctrlPoints[0].controlPointB[0][7] = 1.078247070313;
+lensShading.ctrlPoints[0].controlPointB[0][8] = 0.961303710938;
+lensShading.ctrlPoints[0].controlPointB[0][9] = 1.374267578125;
+lensShading.ctrlPoints[0].controlPointB[1][0] = 1.055786132813;
+lensShading.ctrlPoints[0].controlPointB[1][1] = 1.235839843750;
+lensShading.ctrlPoints[0].controlPointB[1][2] = 1.083984375000;
+lensShading.ctrlPoints[0].controlPointB[1][3] = 1.199096679688;
+lensShading.ctrlPoints[0].controlPointB[1][4] = 1.049316406250;
+lensShading.ctrlPoints[0].controlPointB[1][5] = 1.266479492188;
+lensShading.ctrlPoints[0].controlPointB[1][6] = 1.101318359375;
+lensShading.ctrlPoints[0].controlPointB[1][7] = 1.285400390625;
+lensShading.ctrlPoints[0].controlPointB[1][8] = 0.756103515625;
+lensShading.ctrlPoints[0].controlPointB[1][9] = 1.257324218750;
+lensShading.ctrlPoints[0].controlPointB[2][0] = 1.153320312500;
+lensShading.ctrlPoints[0].controlPointB[2][1] = 1.080078125000;
+lensShading.ctrlPoints[0].controlPointB[2][2] = 1.217041015625;
+lensShading.ctrlPoints[0].controlPointB[2][3] = 1.160156250000;
+lensShading.ctrlPoints[0].controlPointB[2][4] = 1.203247070313;
+lensShading.ctrlPoints[0].controlPointB[2][5] = 1.126708984375;
+lensShading.ctrlPoints[0].controlPointB[2][6] = 1.142700195313;
+lensShading.ctrlPoints[0].controlPointB[2][7] = 1.089965820313;
+lensShading.ctrlPoints[0].controlPointB[2][8] = 1.209228515625;
+lensShading.ctrlPoints[0].controlPointB[2][9] = 0.934448242188;
+lensShading.ctrlPoints[0].controlPointB[3][0] = 1.117187500000;
+lensShading.ctrlPoints[0].controlPointB[3][1] = 1.179565429688;
+lensShading.ctrlPoints[0].controlPointB[3][2] = 1.145507812500;
+lensShading.ctrlPoints[0].controlPointB[3][3] = 1.174682617188;
+lensShading.ctrlPoints[0].controlPointB[3][4] = 1.156982421875;
+lensShading.ctrlPoints[0].controlPointB[3][5] = 1.140625000000;
+lensShading.ctrlPoints[0].controlPointB[3][6] = 1.150268554688;
+lensShading.ctrlPoints[0].controlPointB[3][7] = 1.119018554688;
+lensShading.ctrlPoints[0].controlPointB[3][8] = 1.095703125000;
+lensShading.ctrlPoints[0].controlPointB[3][9] = 1.050292968750;
+lensShading.ctrlPoints[0].controlPointB[4][0] = 1.148681640625;
+lensShading.ctrlPoints[0].controlPointB[4][1] = 1.168457031250;
+lensShading.ctrlPoints[0].controlPointB[4][2] = 1.172363281250;
+lensShading.ctrlPoints[0].controlPointB[4][3] = 1.175781250000;
+lensShading.ctrlPoints[0].controlPointB[4][4] = 1.140258789063;
+lensShading.ctrlPoints[0].controlPointB[4][5] = 1.153076171875;
+lensShading.ctrlPoints[0].controlPointB[4][6] = 1.117553710938;
+lensShading.ctrlPoints[0].controlPointB[4][7] = 1.195678710938;
+lensShading.ctrlPoints[0].controlPointB[4][8] = 1.082275390625;
+lensShading.ctrlPoints[0].controlPointB[4][9] = 1.064575195313;
+lensShading.ctrlPoints[0].controlPointB[5][0] = 1.143920898438;
+lensShading.ctrlPoints[0].controlPointB[5][1] = 1.122070312500;
+lensShading.ctrlPoints[0].controlPointB[5][2] = 1.201904296875;
+lensShading.ctrlPoints[0].controlPointB[5][3] = 1.177368164063;
+lensShading.ctrlPoints[0].controlPointB[5][4] = 1.154907226563;
+lensShading.ctrlPoints[0].controlPointB[5][5] = 1.172485351563;
+lensShading.ctrlPoints[0].controlPointB[5][6] = 1.172729492188;
+lensShading.ctrlPoints[0].controlPointB[5][7] = 1.101928710938;
+lensShading.ctrlPoints[0].controlPointB[5][8] = 1.129638671875;
+lensShading.ctrlPoints[0].controlPointB[5][9] = 1.034912109375;
+lensShading.ctrlPoints[0].controlPointB[6][0] = 1.174804687500;
+lensShading.ctrlPoints[0].controlPointB[6][1] = 1.164306640625;
+lensShading.ctrlPoints[0].controlPointB[6][2] = 1.193359375000;
+lensShading.ctrlPoints[0].controlPointB[6][3] = 1.195312500000;
+lensShading.ctrlPoints[0].controlPointB[6][4] = 1.186523437500;
+lensShading.ctrlPoints[0].controlPointB[6][5] = 1.188598632813;
+lensShading.ctrlPoints[0].controlPointB[6][6] = 1.139160156250;
+lensShading.ctrlPoints[0].controlPointB[6][7] = 1.148437500000;
+lensShading.ctrlPoints[0].controlPointB[6][8] = 1.061401367188;
+lensShading.ctrlPoints[0].controlPointB[6][9] = 1.144042968750;
+lensShading.ctrlPoints[0].controlPointB[7][0] = 1.367065429688;
+lensShading.ctrlPoints[0].controlPointB[7][1] = 1.026977539063;
+lensShading.ctrlPoints[0].controlPointB[7][2] = 1.276733398438;
+lensShading.ctrlPoints[0].controlPointB[7][3] = 1.187011718750;
+lensShading.ctrlPoints[0].controlPointB[7][4] = 1.210571289063;
+lensShading.ctrlPoints[0].controlPointB[7][5] = 1.171508789063;
+lensShading.ctrlPoints[0].controlPointB[7][6] = 1.181274414063;
+lensShading.ctrlPoints[0].controlPointB[7][7] = 1.132690429688;
+lensShading.ctrlPoints[0].controlPointB[7][8] = 1.095703125000;
+lensShading.ctrlPoints[0].controlPointB[7][9] = 1.181762695313;
+lensShading.ctrlPoints[0].controlPointB[8][0] = 1.191650390625;
+lensShading.ctrlPoints[0].controlPointB[8][1] = 1.103515625000;
+lensShading.ctrlPoints[0].controlPointB[8][2] = 1.111938476563;
+lensShading.ctrlPoints[0].controlPointB[8][3] = 1.196655273438;
+lensShading.ctrlPoints[0].controlPointB[8][4] = 1.145141601563;
+lensShading.ctrlPoints[0].controlPointB[8][5] = 1.185913085938;
+lensShading.ctrlPoints[0].controlPointB[8][6] = 1.109375000000;
+lensShading.ctrlPoints[0].controlPointB[8][7] = 1.027221679688;
+lensShading.ctrlPoints[0].controlPointB[8][8] = 1.090820312500;
+lensShading.ctrlPoints[0].controlPointB[8][9] = 1.261230468750;
+lensShading.ctrlPoints[0].controlPointB[9][0] = 1.585205078125;
+lensShading.ctrlPoints[0].controlPointB[9][1] = 1.170654296875;
+lensShading.ctrlPoints[0].controlPointB[9][2] = 1.156127929688;
+lensShading.ctrlPoints[0].controlPointB[9][3] = 1.155395507813;
+lensShading.ctrlPoints[0].controlPointB[9][4] = 1.184204101563;
+lensShading.ctrlPoints[0].controlPointB[9][5] = 1.171875000000;
+lensShading.ctrlPoints[0].controlPointB[9][6] = 1.123291015625;
+lensShading.ctrlPoints[0].controlPointB[9][7] = 1.159790039063;
+lensShading.ctrlPoints[0].controlPointB[9][8] = 1.119750976563;
+lensShading.ctrlPoints[0].controlPointB[9][9] = 1.673583984375;
+lensShading.ctrlPoints[1].cct = 4000;
+lensShading.ctrlPoints[1].light_family = 2;
+lensShading.ctrlPoints[1].controlPointR[0][0] = 1.083862304688;
+lensShading.ctrlPoints[1].controlPointR[0][1] = 0.958007812500;
+lensShading.ctrlPoints[1].controlPointR[0][2] = 1.130615234375;
+lensShading.ctrlPoints[1].controlPointR[0][3] = 1.063964843750;
+lensShading.ctrlPoints[1].controlPointR[0][4] = 1.088989257813;
+lensShading.ctrlPoints[1].controlPointR[0][5] = 1.084594726563;
+lensShading.ctrlPoints[1].controlPointR[0][6] = 1.072143554688;
+lensShading.ctrlPoints[1].controlPointR[0][7] = 1.107177734375;
+lensShading.ctrlPoints[1].controlPointR[0][8] = 0.815429687500;
+lensShading.ctrlPoints[1].controlPointR[0][9] = 1.580322265625;
+lensShading.ctrlPoints[1].controlPointR[1][0] = 0.999633789063;
+lensShading.ctrlPoints[1].controlPointR[1][1] = 1.102416992188;
+lensShading.ctrlPoints[1].controlPointR[1][2] = 1.067504882813;
+lensShading.ctrlPoints[1].controlPointR[1][3] = 1.113647460938;
+lensShading.ctrlPoints[1].controlPointR[1][4] = 1.112670898438;
+lensShading.ctrlPoints[1].controlPointR[1][5] = 1.102416992188;
+lensShading.ctrlPoints[1].controlPointR[1][6] = 1.081298828125;
+lensShading.ctrlPoints[1].controlPointR[1][7] = 1.187500000000;
+lensShading.ctrlPoints[1].controlPointR[1][8] = 0.771728515625;
+lensShading.ctrlPoints[1].controlPointR[1][9] = 1.229492187500;
+lensShading.ctrlPoints[1].controlPointR[2][0] = 1.086914062500;
+lensShading.ctrlPoints[1].controlPointR[2][1] = 1.023315429688;
+lensShading.ctrlPoints[1].controlPointR[2][2] = 1.174926757813;
+lensShading.ctrlPoints[1].controlPointR[2][3] = 1.089599609375;
+lensShading.ctrlPoints[1].controlPointR[2][4] = 1.111572265625;
+lensShading.ctrlPoints[1].controlPointR[2][5] = 1.117797851563;
+lensShading.ctrlPoints[1].controlPointR[2][6] = 1.111450195313;
+lensShading.ctrlPoints[1].controlPointR[2][7] = 1.166137695313;
+lensShading.ctrlPoints[1].controlPointR[2][8] = 1.044799804688;
+lensShading.ctrlPoints[1].controlPointR[2][9] = 1.093383789063;
+lensShading.ctrlPoints[1].controlPointR[3][0] = 1.056518554688;
+lensShading.ctrlPoints[1].controlPointR[3][1] = 1.092895507813;
+lensShading.ctrlPoints[1].controlPointR[3][2] = 1.084472656250;
+lensShading.ctrlPoints[1].controlPointR[3][3] = 1.109375000000;
+lensShading.ctrlPoints[1].controlPointR[3][4] = 1.092895507813;
+lensShading.ctrlPoints[1].controlPointR[3][5] = 1.099609375000;
+lensShading.ctrlPoints[1].controlPointR[3][6] = 1.109252929688;
+lensShading.ctrlPoints[1].controlPointR[3][7] = 1.090209960938;
+lensShading.ctrlPoints[1].controlPointR[3][8] = 1.074584960938;
+lensShading.ctrlPoints[1].controlPointR[3][9] = 1.081420898438;
+lensShading.ctrlPoints[1].controlPointR[4][0] = 1.095581054688;
+lensShading.ctrlPoints[1].controlPointR[4][1] = 1.059204101563;
+lensShading.ctrlPoints[1].controlPointR[4][2] = 1.116210937500;
+lensShading.ctrlPoints[1].controlPointR[4][3] = 1.092895507813;
+lensShading.ctrlPoints[1].controlPointR[4][4] = 1.082519531250;
+lensShading.ctrlPoints[1].controlPointR[4][5] = 1.094360351563;
+lensShading.ctrlPoints[1].controlPointR[4][6] = 1.110229492188;
+lensShading.ctrlPoints[1].controlPointR[4][7] = 1.224975585938;
+lensShading.ctrlPoints[1].controlPointR[4][8] = 0.971557617188;
+lensShading.ctrlPoints[1].controlPointR[4][9] = 1.152832031250;
+lensShading.ctrlPoints[1].controlPointR[5][0] = 1.061035156250;
+lensShading.ctrlPoints[1].controlPointR[5][1] = 1.090332031250;
+lensShading.ctrlPoints[1].controlPointR[5][2] = 1.116821289063;
+lensShading.ctrlPoints[1].controlPointR[5][3] = 1.118408203125;
+lensShading.ctrlPoints[1].controlPointR[5][4] = 1.095092773438;
+lensShading.ctrlPoints[1].controlPointR[5][5] = 1.105590820313;
+lensShading.ctrlPoints[1].controlPointR[5][6] = 1.118774414063;
+lensShading.ctrlPoints[1].controlPointR[5][7] = 1.063232421875;
+lensShading.ctrlPoints[1].controlPointR[5][8] = 1.124145507813;
+lensShading.ctrlPoints[1].controlPointR[5][9] = 1.058837890625;
+lensShading.ctrlPoints[1].controlPointR[6][0] = 1.113281250000;
+lensShading.ctrlPoints[1].controlPointR[6][1] = 1.043212890625;
+lensShading.ctrlPoints[1].controlPointR[6][2] = 1.131225585938;
+lensShading.ctrlPoints[1].controlPointR[6][3] = 1.104370117188;
+lensShading.ctrlPoints[1].controlPointR[6][4] = 1.133911132813;
+lensShading.ctrlPoints[1].controlPointR[6][5] = 1.117553710938;
+lensShading.ctrlPoints[1].controlPointR[6][6] = 1.117431640625;
+lensShading.ctrlPoints[1].controlPointR[6][7] = 1.149169921875;
+lensShading.ctrlPoints[1].controlPointR[6][8] = 1.019775390625;
+lensShading.ctrlPoints[1].controlPointR[6][9] = 1.210449218750;
+lensShading.ctrlPoints[1].controlPointR[7][0] = 1.201782226563;
+lensShading.ctrlPoints[1].controlPointR[7][1] = 1.068115234375;
+lensShading.ctrlPoints[1].controlPointR[7][2] = 1.099975585938;
+lensShading.ctrlPoints[1].controlPointR[7][3] = 1.140380859375;
+lensShading.ctrlPoints[1].controlPointR[7][4] = 1.080566406250;
+lensShading.ctrlPoints[1].controlPointR[7][5] = 1.162231445313;
+lensShading.ctrlPoints[1].controlPointR[7][6] = 1.121337890625;
+lensShading.ctrlPoints[1].controlPointR[7][7] = 1.080932617188;
+lensShading.ctrlPoints[1].controlPointR[7][8] = 1.054565429688;
+lensShading.ctrlPoints[1].controlPointR[7][9] = 1.302734375000;
+lensShading.ctrlPoints[1].controlPointR[8][0] = 1.157836914063;
+lensShading.ctrlPoints[1].controlPointR[8][1] = 0.961791992188;
+lensShading.ctrlPoints[1].controlPointR[8][2] = 1.110351562500;
+lensShading.ctrlPoints[1].controlPointR[8][3] = 1.092651367188;
+lensShading.ctrlPoints[1].controlPointR[8][4] = 1.166992187500;
+lensShading.ctrlPoints[1].controlPointR[8][5] = 1.119873046875;
+lensShading.ctrlPoints[1].controlPointR[8][6] = 1.091552734375;
+lensShading.ctrlPoints[1].controlPointR[8][7] = 1.112548828125;
+lensShading.ctrlPoints[1].controlPointR[8][8] = 1.015258789063;
+lensShading.ctrlPoints[1].controlPointR[8][9] = 1.356323242188;
+lensShading.ctrlPoints[1].controlPointR[9][0] = 1.489013671875;
+lensShading.ctrlPoints[1].controlPointR[9][1] = 1.096069335938;
+lensShading.ctrlPoints[1].controlPointR[9][2] = 1.102050781250;
+lensShading.ctrlPoints[1].controlPointR[9][3] = 1.106079101563;
+lensShading.ctrlPoints[1].controlPointR[9][4] = 1.133422851563;
+lensShading.ctrlPoints[1].controlPointR[9][5] = 1.097045898438;
+lensShading.ctrlPoints[1].controlPointR[9][6] = 1.115844726563;
+lensShading.ctrlPoints[1].controlPointR[9][7] = 1.141357421875;
+lensShading.ctrlPoints[1].controlPointR[9][8] = 1.062133789063;
+lensShading.ctrlPoints[1].controlPointR[9][9] = 1.936035156250;
+lensShading.ctrlPoints[1].controlPointGR[0][0] = 1.063476562500;
+lensShading.ctrlPoints[1].controlPointGR[0][1] = 1.007202148438;
+lensShading.ctrlPoints[1].controlPointGR[0][2] = 1.059814453125;
+lensShading.ctrlPoints[1].controlPointGR[0][3] = 1.056518554688;
+lensShading.ctrlPoints[1].controlPointGR[0][4] = 1.074951171875;
+lensShading.ctrlPoints[1].controlPointGR[0][5] = 1.055541992188;
+lensShading.ctrlPoints[1].controlPointGR[0][6] = 1.048339843750;
+lensShading.ctrlPoints[1].controlPointGR[0][7] = 1.097412109375;
+lensShading.ctrlPoints[1].controlPointGR[0][8] = 0.760375976563;
+lensShading.ctrlPoints[1].controlPointGR[0][9] = 1.566162109375;
+lensShading.ctrlPoints[1].controlPointGR[1][0] = 0.996337890625;
+lensShading.ctrlPoints[1].controlPointGR[1][1] = 1.042358398438;
+lensShading.ctrlPoints[1].controlPointGR[1][2] = 1.114990234375;
+lensShading.ctrlPoints[1].controlPointGR[1][3] = 1.078369140625;
+lensShading.ctrlPoints[1].controlPointGR[1][4] = 1.059204101563;
+lensShading.ctrlPoints[1].controlPointGR[1][5] = 1.084594726563;
+lensShading.ctrlPoints[1].controlPointGR[1][6] = 1.051025390625;
+lensShading.ctrlPoints[1].controlPointGR[1][7] = 1.207519531250;
+lensShading.ctrlPoints[1].controlPointGR[1][8] = 0.743041992188;
+lensShading.ctrlPoints[1].controlPointGR[1][9] = 1.232666015625;
+lensShading.ctrlPoints[1].controlPointGR[2][0] = 1.065307617188;
+lensShading.ctrlPoints[1].controlPointGR[2][1] = 1.065429687500;
+lensShading.ctrlPoints[1].controlPointGR[2][2] = 1.051269531250;
+lensShading.ctrlPoints[1].controlPointGR[2][3] = 1.074707031250;
+lensShading.ctrlPoints[1].controlPointGR[2][4] = 1.070678710938;
+lensShading.ctrlPoints[1].controlPointGR[2][5] = 1.080444335938;
+lensShading.ctrlPoints[1].controlPointGR[2][6] = 1.066772460938;
+lensShading.ctrlPoints[1].controlPointGR[2][7] = 1.076904296875;
+lensShading.ctrlPoints[1].controlPointGR[2][8] = 1.064819335938;
+lensShading.ctrlPoints[1].controlPointGR[2][9] = 1.026000976563;
+lensShading.ctrlPoints[1].controlPointGR[3][0] = 1.040161132813;
+lensShading.ctrlPoints[1].controlPointGR[3][1] = 1.072875976563;
+lensShading.ctrlPoints[1].controlPointGR[3][2] = 1.065917968750;
+lensShading.ctrlPoints[1].controlPointGR[3][3] = 1.080688476563;
+lensShading.ctrlPoints[1].controlPointGR[3][4] = 1.057250976563;
+lensShading.ctrlPoints[1].controlPointGR[3][5] = 1.068481445313;
+lensShading.ctrlPoints[1].controlPointGR[3][6] = 1.069458007813;
+lensShading.ctrlPoints[1].controlPointGR[3][7] = 1.082641601563;
+lensShading.ctrlPoints[1].controlPointGR[3][8] = 1.013916015625;
+lensShading.ctrlPoints[1].controlPointGR[3][9] = 1.064819335938;
+lensShading.ctrlPoints[1].controlPointGR[4][0] = 1.075927734375;
+lensShading.ctrlPoints[1].controlPointGR[4][1] = 1.062500000000;
+lensShading.ctrlPoints[1].controlPointGR[4][2] = 1.084594726563;
+lensShading.ctrlPoints[1].controlPointGR[4][3] = 1.075561523438;
+lensShading.ctrlPoints[1].controlPointGR[4][4] = 1.058227539063;
+lensShading.ctrlPoints[1].controlPointGR[4][5] = 1.040161132813;
+lensShading.ctrlPoints[1].controlPointGR[4][6] = 1.084228515625;
+lensShading.ctrlPoints[1].controlPointGR[4][7] = 1.129028320313;
+lensShading.ctrlPoints[1].controlPointGR[4][8] = 1.037841796875;
+lensShading.ctrlPoints[1].controlPointGR[4][9] = 1.075561523438;
+lensShading.ctrlPoints[1].controlPointGR[5][0] = 1.031005859375;
+lensShading.ctrlPoints[1].controlPointGR[5][1] = 1.084228515625;
+lensShading.ctrlPoints[1].controlPointGR[5][2] = 1.067993164063;
+lensShading.ctrlPoints[1].controlPointGR[5][3] = 1.088256835938;
+lensShading.ctrlPoints[1].controlPointGR[5][4] = 1.037109375000;
+lensShading.ctrlPoints[1].controlPointGR[5][5] = 1.110839843750;
+lensShading.ctrlPoints[1].controlPointGR[5][6] = 1.072387695313;
+lensShading.ctrlPoints[1].controlPointGR[5][7] = 1.089355468750;
+lensShading.ctrlPoints[1].controlPointGR[5][8] = 1.032592773438;
+lensShading.ctrlPoints[1].controlPointGR[5][9] = 1.048095703125;
+lensShading.ctrlPoints[1].controlPointGR[6][0] = 1.088867187500;
+lensShading.ctrlPoints[1].controlPointGR[6][1] = 1.049560546875;
+lensShading.ctrlPoints[1].controlPointGR[6][2] = 1.101440429688;
+lensShading.ctrlPoints[1].controlPointGR[6][3] = 1.084838867188;
+lensShading.ctrlPoints[1].controlPointGR[6][4] = 1.105346679688;
+lensShading.ctrlPoints[1].controlPointGR[6][5] = 1.082641601563;
+lensShading.ctrlPoints[1].controlPointGR[6][6] = 1.086303710938;
+lensShading.ctrlPoints[1].controlPointGR[6][7] = 1.095214843750;
+lensShading.ctrlPoints[1].controlPointGR[6][8] = 1.002319335938;
+lensShading.ctrlPoints[1].controlPointGR[6][9] = 1.155517578125;
+lensShading.ctrlPoints[1].controlPointGR[7][0] = 1.180175781250;
+lensShading.ctrlPoints[1].controlPointGR[7][1] = 1.003051757813;
+lensShading.ctrlPoints[1].controlPointGR[7][2] = 1.097290039063;
+lensShading.ctrlPoints[1].controlPointGR[7][3] = 1.098632812500;
+lensShading.ctrlPoints[1].controlPointGR[7][4] = 1.064941406250;
+lensShading.ctrlPoints[1].controlPointGR[7][5] = 1.135131835938;
+lensShading.ctrlPoints[1].controlPointGR[7][6] = 1.071289062500;
+lensShading.ctrlPoints[1].controlPointGR[7][7] = 1.106689453125;
+lensShading.ctrlPoints[1].controlPointGR[7][8] = 0.937988281250;
+lensShading.ctrlPoints[1].controlPointGR[7][9] = 1.290161132813;
+lensShading.ctrlPoints[1].controlPointGR[8][0] = 1.148437500000;
+lensShading.ctrlPoints[1].controlPointGR[8][1] = 0.993652343750;
+lensShading.ctrlPoints[1].controlPointGR[8][2] = 1.059570312500;
+lensShading.ctrlPoints[1].controlPointGR[8][3] = 1.084960937500;
+lensShading.ctrlPoints[1].controlPointGR[8][4] = 1.137329101563;
+lensShading.ctrlPoints[1].controlPointGR[8][5] = 1.063110351563;
+lensShading.ctrlPoints[1].controlPointGR[8][6] = 1.081542968750;
+lensShading.ctrlPoints[1].controlPointGR[8][7] = 1.033203125000;
+lensShading.ctrlPoints[1].controlPointGR[8][8] = 1.046020507813;
+lensShading.ctrlPoints[1].controlPointGR[8][9] = 1.294311523438;
+lensShading.ctrlPoints[1].controlPointGR[9][0] = 1.435180664063;
+lensShading.ctrlPoints[1].controlPointGR[9][1] = 1.056640625000;
+lensShading.ctrlPoints[1].controlPointGR[9][2] = 1.080322265625;
+lensShading.ctrlPoints[1].controlPointGR[9][3] = 1.072509765625;
+lensShading.ctrlPoints[1].controlPointGR[9][4] = 1.072143554688;
+lensShading.ctrlPoints[1].controlPointGR[9][5] = 1.103027343750;
+lensShading.ctrlPoints[1].controlPointGR[9][6] = 1.054809570313;
+lensShading.ctrlPoints[1].controlPointGR[9][7] = 1.144165039063;
+lensShading.ctrlPoints[1].controlPointGR[9][8] = 0.990600585938;
+lensShading.ctrlPoints[1].controlPointGR[9][9] = 1.867187500000;
+lensShading.ctrlPoints[1].controlPointGB[0][0] = 1.058959960938;
+lensShading.ctrlPoints[1].controlPointGB[0][1] = 1.006103515625;
+lensShading.ctrlPoints[1].controlPointGB[0][2] = 1.062500000000;
+lensShading.ctrlPoints[1].controlPointGB[0][3] = 1.068115234375;
+lensShading.ctrlPoints[1].controlPointGB[0][4] = 1.078125000000;
+lensShading.ctrlPoints[1].controlPointGB[0][5] = 1.072998046875;
+lensShading.ctrlPoints[1].controlPointGB[0][6] = 1.060913085938;
+lensShading.ctrlPoints[1].controlPointGB[0][7] = 1.130493164063;
+lensShading.ctrlPoints[1].controlPointGB[0][8] = 0.752685546875;
+lensShading.ctrlPoints[1].controlPointGB[0][9] = 1.575805664063;
+lensShading.ctrlPoints[1].controlPointGB[1][0] = 1.013305664063;
+lensShading.ctrlPoints[1].controlPointGB[1][1] = 1.072143554688;
+lensShading.ctrlPoints[1].controlPointGB[1][2] = 1.126464843750;
+lensShading.ctrlPoints[1].controlPointGB[1][3] = 1.084350585938;
+lensShading.ctrlPoints[1].controlPointGB[1][4] = 1.074462890625;
+lensShading.ctrlPoints[1].controlPointGB[1][5] = 1.066650390625;
+lensShading.ctrlPoints[1].controlPointGB[1][6] = 1.065429687500;
+lensShading.ctrlPoints[1].controlPointGB[1][7] = 1.163574218750;
+lensShading.ctrlPoints[1].controlPointGB[1][8] = 0.819091796875;
+lensShading.ctrlPoints[1].controlPointGB[1][9] = 1.206420898438;
+lensShading.ctrlPoints[1].controlPointGB[2][0] = 1.064575195313;
+lensShading.ctrlPoints[1].controlPointGB[2][1] = 1.018066406250;
+lensShading.ctrlPoints[1].controlPointGB[2][2] = 1.081787109375;
+lensShading.ctrlPoints[1].controlPointGB[2][3] = 1.066894531250;
+lensShading.ctrlPoints[1].controlPointGB[2][4] = 1.082031250000;
+lensShading.ctrlPoints[1].controlPointGB[2][5] = 1.097167968750;
+lensShading.ctrlPoints[1].controlPointGB[2][6] = 1.069946289063;
+lensShading.ctrlPoints[1].controlPointGB[2][7] = 1.097045898438;
+lensShading.ctrlPoints[1].controlPointGB[2][8] = 1.030029296875;
+lensShading.ctrlPoints[1].controlPointGB[2][9] = 1.057250976563;
+lensShading.ctrlPoints[1].controlPointGB[3][0] = 1.042358398438;
+lensShading.ctrlPoints[1].controlPointGB[3][1] = 1.088012695313;
+lensShading.ctrlPoints[1].controlPointGB[3][2] = 1.060546875000;
+lensShading.ctrlPoints[1].controlPointGB[3][3] = 1.079589843750;
+lensShading.ctrlPoints[1].controlPointGB[3][4] = 1.075683593750;
+lensShading.ctrlPoints[1].controlPointGB[3][5] = 1.061523437500;
+lensShading.ctrlPoints[1].controlPointGB[3][6] = 1.079833984375;
+lensShading.ctrlPoints[1].controlPointGB[3][7] = 1.086181640625;
+lensShading.ctrlPoints[1].controlPointGB[3][8] = 1.037353515625;
+lensShading.ctrlPoints[1].controlPointGB[3][9] = 1.059570312500;
+lensShading.ctrlPoints[1].controlPointGB[4][0] = 1.065307617188;
+lensShading.ctrlPoints[1].controlPointGB[4][1] = 1.032104492188;
+lensShading.ctrlPoints[1].controlPointGB[4][2] = 1.093261718750;
+lensShading.ctrlPoints[1].controlPointGB[4][3] = 1.076416015625;
+lensShading.ctrlPoints[1].controlPointGB[4][4] = 1.058837890625;
+lensShading.ctrlPoints[1].controlPointGB[4][5] = 1.047119140625;
+lensShading.ctrlPoints[1].controlPointGB[4][6] = 1.084350585938;
+lensShading.ctrlPoints[1].controlPointGB[4][7] = 1.123535156250;
+lensShading.ctrlPoints[1].controlPointGB[4][8] = 1.023071289063;
+lensShading.ctrlPoints[1].controlPointGB[4][9] = 1.088134765625;
+lensShading.ctrlPoints[1].controlPointGB[5][0] = 1.045410156250;
+lensShading.ctrlPoints[1].controlPointGB[5][1] = 1.088745117188;
+lensShading.ctrlPoints[1].controlPointGB[5][2] = 1.071166992188;
+lensShading.ctrlPoints[1].controlPointGB[5][3] = 1.085571289063;
+lensShading.ctrlPoints[1].controlPointGB[5][4] = 1.048706054688;
+lensShading.ctrlPoints[1].controlPointGB[5][5] = 1.100830078125;
+lensShading.ctrlPoints[1].controlPointGB[5][6] = 1.077026367188;
+lensShading.ctrlPoints[1].controlPointGB[5][7] = 1.108764648438;
+lensShading.ctrlPoints[1].controlPointGB[5][8] = 1.026245117188;
+lensShading.ctrlPoints[1].controlPointGB[5][9] = 1.050537109375;
+lensShading.ctrlPoints[1].controlPointGB[6][0] = 1.083007812500;
+lensShading.ctrlPoints[1].controlPointGB[6][1] = 1.046142578125;
+lensShading.ctrlPoints[1].controlPointGB[6][2] = 1.093139648438;
+lensShading.ctrlPoints[1].controlPointGB[6][3] = 1.083374023438;
+lensShading.ctrlPoints[1].controlPointGB[6][4] = 1.103271484375;
+lensShading.ctrlPoints[1].controlPointGB[6][5] = 1.090087890625;
+lensShading.ctrlPoints[1].controlPointGB[6][6] = 1.084350585938;
+lensShading.ctrlPoints[1].controlPointGB[6][7] = 1.096679687500;
+lensShading.ctrlPoints[1].controlPointGB[6][8] = 0.999877929688;
+lensShading.ctrlPoints[1].controlPointGB[6][9] = 1.158569335938;
+lensShading.ctrlPoints[1].controlPointGB[7][0] = 1.194213867188;
+lensShading.ctrlPoints[1].controlPointGB[7][1] = 0.993652343750;
+lensShading.ctrlPoints[1].controlPointGB[7][2] = 1.113159179688;
+lensShading.ctrlPoints[1].controlPointGB[7][3] = 1.089599609375;
+lensShading.ctrlPoints[1].controlPointGB[7][4] = 1.090087890625;
+lensShading.ctrlPoints[1].controlPointGB[7][5] = 1.096191406250;
+lensShading.ctrlPoints[1].controlPointGB[7][6] = 1.089965820313;
+lensShading.ctrlPoints[1].controlPointGB[7][7] = 1.106689453125;
+lensShading.ctrlPoints[1].controlPointGB[7][8] = 0.935791015625;
+lensShading.ctrlPoints[1].controlPointGB[7][9] = 1.284179687500;
+lensShading.ctrlPoints[1].controlPointGB[8][0] = 1.118652343750;
+lensShading.ctrlPoints[1].controlPointGB[8][1] = 0.987182617188;
+lensShading.ctrlPoints[1].controlPointGB[8][2] = 1.050781250000;
+lensShading.ctrlPoints[1].controlPointGB[8][3] = 1.075561523438;
+lensShading.ctrlPoints[1].controlPointGB[8][4] = 1.114379882813;
+lensShading.ctrlPoints[1].controlPointGB[8][5] = 1.108764648438;
+lensShading.ctrlPoints[1].controlPointGB[8][6] = 1.055419921875;
+lensShading.ctrlPoints[1].controlPointGB[8][7] = 1.031738281250;
+lensShading.ctrlPoints[1].controlPointGB[8][8] = 1.052490234375;
+lensShading.ctrlPoints[1].controlPointGB[8][9] = 1.282348632813;
+lensShading.ctrlPoints[1].controlPointGB[9][0] = 1.449096679688;
+lensShading.ctrlPoints[1].controlPointGB[9][1] = 1.060302734375;
+lensShading.ctrlPoints[1].controlPointGB[9][2] = 1.064453125000;
+lensShading.ctrlPoints[1].controlPointGB[9][3] = 1.069213867188;
+lensShading.ctrlPoints[1].controlPointGB[9][4] = 1.088012695313;
+lensShading.ctrlPoints[1].controlPointGB[9][5] = 1.073852539063;
+lensShading.ctrlPoints[1].controlPointGB[9][6] = 1.069213867188;
+lensShading.ctrlPoints[1].controlPointGB[9][7] = 1.146728515625;
+lensShading.ctrlPoints[1].controlPointGB[9][8] = 0.974243164063;
+lensShading.ctrlPoints[1].controlPointGB[9][9] = 1.875122070313;
+lensShading.ctrlPoints[1].controlPointB[0][0] = 1.054565429688;
+lensShading.ctrlPoints[1].controlPointB[0][1] = 1.022338867188;
+lensShading.ctrlPoints[1].controlPointB[0][2] = 1.072387695313;
+lensShading.ctrlPoints[1].controlPointB[0][3] = 1.086425781250;
+lensShading.ctrlPoints[1].controlPointB[0][4] = 1.060546875000;
+lensShading.ctrlPoints[1].controlPointB[0][5] = 1.094848632813;
+lensShading.ctrlPoints[1].controlPointB[0][6] = 1.073486328125;
+lensShading.ctrlPoints[1].controlPointB[0][7] = 1.129028320313;
+lensShading.ctrlPoints[1].controlPointB[0][8] = 0.770996093750;
+lensShading.ctrlPoints[1].controlPointB[0][9] = 1.599243164063;
+lensShading.ctrlPoints[1].controlPointB[1][0] = 1.010498046875;
+lensShading.ctrlPoints[1].controlPointB[1][1] = 1.098999023438;
+lensShading.ctrlPoints[1].controlPointB[1][2] = 1.100830078125;
+lensShading.ctrlPoints[1].controlPointB[1][3] = 1.086425781250;
+lensShading.ctrlPoints[1].controlPointB[1][4] = 1.076171875000;
+lensShading.ctrlPoints[1].controlPointB[1][5] = 1.110717773438;
+lensShading.ctrlPoints[1].controlPointB[1][6] = 1.059204101563;
+lensShading.ctrlPoints[1].controlPointB[1][7] = 1.228149414063;
+lensShading.ctrlPoints[1].controlPointB[1][8] = 0.770141601563;
+lensShading.ctrlPoints[1].controlPointB[1][9] = 1.236816406250;
+lensShading.ctrlPoints[1].controlPointB[2][0] = 1.067260742188;
+lensShading.ctrlPoints[1].controlPointB[2][1] = 1.054321289063;
+lensShading.ctrlPoints[1].controlPointB[2][2] = 1.088867187500;
+lensShading.ctrlPoints[1].controlPointB[2][3] = 1.076904296875;
+lensShading.ctrlPoints[1].controlPointB[2][4] = 1.115844726563;
+lensShading.ctrlPoints[1].controlPointB[2][5] = 1.054931640625;
+lensShading.ctrlPoints[1].controlPointB[2][6] = 1.097167968750;
+lensShading.ctrlPoints[1].controlPointB[2][7] = 1.081054687500;
+lensShading.ctrlPoints[1].controlPointB[2][8] = 1.086547851563;
+lensShading.ctrlPoints[1].controlPointB[2][9] = 1.056274414063;
+lensShading.ctrlPoints[1].controlPointB[3][0] = 1.047119140625;
+lensShading.ctrlPoints[1].controlPointB[3][1] = 1.085083007813;
+lensShading.ctrlPoints[1].controlPointB[3][2] = 1.082519531250;
+lensShading.ctrlPoints[1].controlPointB[3][3] = 1.091430664063;
+lensShading.ctrlPoints[1].controlPointB[3][4] = 1.065185546875;
+lensShading.ctrlPoints[1].controlPointB[3][5] = 1.085693359375;
+lensShading.ctrlPoints[1].controlPointB[3][6] = 1.086425781250;
+lensShading.ctrlPoints[1].controlPointB[3][7] = 1.124511718750;
+lensShading.ctrlPoints[1].controlPointB[3][8] = 1.034057617188;
+lensShading.ctrlPoints[1].controlPointB[3][9] = 1.084716796875;
+lensShading.ctrlPoints[1].controlPointB[4][0] = 1.101562500000;
+lensShading.ctrlPoints[1].controlPointB[4][1] = 1.040283203125;
+lensShading.ctrlPoints[1].controlPointB[4][2] = 1.105224609375;
+lensShading.ctrlPoints[1].controlPointB[4][3] = 1.083862304688;
+lensShading.ctrlPoints[1].controlPointB[4][4] = 1.076904296875;
+lensShading.ctrlPoints[1].controlPointB[4][5] = 1.046752929688;
+lensShading.ctrlPoints[1].controlPointB[4][6] = 1.095214843750;
+lensShading.ctrlPoints[1].controlPointB[4][7] = 1.146118164063;
+lensShading.ctrlPoints[1].controlPointB[4][8] = 1.032592773438;
+lensShading.ctrlPoints[1].controlPointB[4][9] = 1.117553710938;
+lensShading.ctrlPoints[1].controlPointB[5][0] = 1.028930664063;
+lensShading.ctrlPoints[1].controlPointB[5][1] = 1.111450195313;
+lensShading.ctrlPoints[1].controlPointB[5][2] = 1.084960937500;
+lensShading.ctrlPoints[1].controlPointB[5][3] = 1.096069335938;
+lensShading.ctrlPoints[1].controlPointB[5][4] = 1.064819335938;
+lensShading.ctrlPoints[1].controlPointB[5][5] = 1.103881835938;
+lensShading.ctrlPoints[1].controlPointB[5][6] = 1.091796875000;
+lensShading.ctrlPoints[1].controlPointB[5][7] = 1.100708007813;
+lensShading.ctrlPoints[1].controlPointB[5][8] = 1.072753906250;
+lensShading.ctrlPoints[1].controlPointB[5][9] = 1.058105468750;
+lensShading.ctrlPoints[1].controlPointB[6][0] = 1.100830078125;
+lensShading.ctrlPoints[1].controlPointB[6][1] = 1.057128906250;
+lensShading.ctrlPoints[1].controlPointB[6][2] = 1.108032226563;
+lensShading.ctrlPoints[1].controlPointB[6][3] = 1.095703125000;
+lensShading.ctrlPoints[1].controlPointB[6][4] = 1.102416992188;
+lensShading.ctrlPoints[1].controlPointB[6][5] = 1.102416992188;
+lensShading.ctrlPoints[1].controlPointB[6][6] = 1.101318359375;
+lensShading.ctrlPoints[1].controlPointB[6][7] = 1.127319335938;
+lensShading.ctrlPoints[1].controlPointB[6][8] = 1.002929687500;
+lensShading.ctrlPoints[1].controlPointB[6][9] = 1.188842773438;
+lensShading.ctrlPoints[1].controlPointB[7][0] = 1.173461914063;
+lensShading.ctrlPoints[1].controlPointB[7][1] = 1.100463867188;
+lensShading.ctrlPoints[1].controlPointB[7][2] = 1.071166992188;
+lensShading.ctrlPoints[1].controlPointB[7][3] = 1.115844726563;
+lensShading.ctrlPoints[1].controlPointB[7][4] = 1.096313476563;
+lensShading.ctrlPoints[1].controlPointB[7][5] = 1.147949218750;
+lensShading.ctrlPoints[1].controlPointB[7][6] = 1.094238281250;
+lensShading.ctrlPoints[1].controlPointB[7][7] = 1.166992187500;
+lensShading.ctrlPoints[1].controlPointB[7][8] = 0.900268554688;
+lensShading.ctrlPoints[1].controlPointB[7][9] = 1.378295898438;
+lensShading.ctrlPoints[1].controlPointB[8][0] = 1.127197265625;
+lensShading.ctrlPoints[1].controlPointB[8][1] = 0.955200195313;
+lensShading.ctrlPoints[1].controlPointB[8][2] = 1.065795898438;
+lensShading.ctrlPoints[1].controlPointB[8][3] = 1.076049804688;
+lensShading.ctrlPoints[1].controlPointB[8][4] = 1.104248046875;
+lensShading.ctrlPoints[1].controlPointB[8][5] = 1.072021484375;
+lensShading.ctrlPoints[1].controlPointB[8][6] = 1.081420898438;
+lensShading.ctrlPoints[1].controlPointB[8][7] = 1.028564453125;
+lensShading.ctrlPoints[1].controlPointB[8][8] = 1.075195312500;
+lensShading.ctrlPoints[1].controlPointB[8][9] = 1.251831054688;
+lensShading.ctrlPoints[1].controlPointB[9][0] = 1.462280273438;
+lensShading.ctrlPoints[1].controlPointB[9][1] = 1.096191406250;
+lensShading.ctrlPoints[1].controlPointB[9][2] = 1.081420898438;
+lensShading.ctrlPoints[1].controlPointB[9][3] = 1.086791992188;
+lensShading.ctrlPoints[1].controlPointB[9][4] = 1.099975585938;
+lensShading.ctrlPoints[1].controlPointB[9][5] = 1.113769531250;
+lensShading.ctrlPoints[1].controlPointB[9][6] = 1.082397460938;
+lensShading.ctrlPoints[1].controlPointB[9][7] = 1.170532226563;
+lensShading.ctrlPoints[1].controlPointB[9][8] = 0.970336914063;
+lensShading.ctrlPoints[1].controlPointB[9][9] = 1.959106445313;
+lensShading.ctrlPoints[2].cct = 6500;
+lensShading.ctrlPoints[2].light_family = 1;
+lensShading.ctrlPoints[2].controlPointR[0][0] = 1.082397460938;
+lensShading.ctrlPoints[2].controlPointR[0][1] = 0.986572265625;
+lensShading.ctrlPoints[2].controlPointR[0][2] = 1.100585937500;
+lensShading.ctrlPoints[2].controlPointR[0][3] = 1.100708007813;
+lensShading.ctrlPoints[2].controlPointR[0][4] = 1.096191406250;
+lensShading.ctrlPoints[2].controlPointR[0][5] = 1.100341796875;
+lensShading.ctrlPoints[2].controlPointR[0][6] = 1.104492187500;
+lensShading.ctrlPoints[2].controlPointR[0][7] = 1.140136718750;
+lensShading.ctrlPoints[2].controlPointR[0][8] = 0.767333984375;
+lensShading.ctrlPoints[2].controlPointR[0][9] = 1.623535156250;
+lensShading.ctrlPoints[2].controlPointR[1][0] = 0.982910156250;
+lensShading.ctrlPoints[2].controlPointR[1][1] = 1.103637695313;
+lensShading.ctrlPoints[2].controlPointR[1][2] = 1.125610351563;
+lensShading.ctrlPoints[2].controlPointR[1][3] = 1.096313476563;
+lensShading.ctrlPoints[2].controlPointR[1][4] = 1.091796875000;
+lensShading.ctrlPoints[2].controlPointR[1][5] = 1.183593750000;
+lensShading.ctrlPoints[2].controlPointR[1][6] = 1.061645507813;
+lensShading.ctrlPoints[2].controlPointR[1][7] = 1.266723632813;
+lensShading.ctrlPoints[2].controlPointR[1][8] = 0.764282226563;
+lensShading.ctrlPoints[2].controlPointR[1][9] = 1.251586914063;
+lensShading.ctrlPoints[2].controlPointR[2][0] = 1.108032226563;
+lensShading.ctrlPoints[2].controlPointR[2][1] = 1.014282226563;
+lensShading.ctrlPoints[2].controlPointR[2][2] = 1.171508789063;
+lensShading.ctrlPoints[2].controlPointR[2][3] = 1.122192382813;
+lensShading.ctrlPoints[2].controlPointR[2][4] = 1.146850585938;
+lensShading.ctrlPoints[2].controlPointR[2][5] = 1.096069335938;
+lensShading.ctrlPoints[2].controlPointR[2][6] = 1.154785156250;
+lensShading.ctrlPoints[2].controlPointR[2][7] = 1.110229492188;
+lensShading.ctrlPoints[2].controlPointR[2][8] = 1.091308593750;
+lensShading.ctrlPoints[2].controlPointR[2][9] = 1.099487304688;
+lensShading.ctrlPoints[2].controlPointR[3][0] = 1.066894531250;
+lensShading.ctrlPoints[2].controlPointR[3][1] = 1.099243164063;
+lensShading.ctrlPoints[2].controlPointR[3][2] = 1.107910156250;
+lensShading.ctrlPoints[2].controlPointR[3][3] = 1.119506835938;
+lensShading.ctrlPoints[2].controlPointR[3][4] = 1.123657226563;
+lensShading.ctrlPoints[2].controlPointR[3][5] = 1.114990234375;
+lensShading.ctrlPoints[2].controlPointR[3][6] = 1.124267578125;
+lensShading.ctrlPoints[2].controlPointR[3][7] = 1.120849609375;
+lensShading.ctrlPoints[2].controlPointR[3][8] = 1.092651367188;
+lensShading.ctrlPoints[2].controlPointR[3][9] = 1.100463867188;
+lensShading.ctrlPoints[2].controlPointR[4][0] = 1.096679687500;
+lensShading.ctrlPoints[2].controlPointR[4][1] = 1.090454101563;
+lensShading.ctrlPoints[2].controlPointR[4][2] = 1.130981445313;
+lensShading.ctrlPoints[2].controlPointR[4][3] = 1.119750976563;
+lensShading.ctrlPoints[2].controlPointR[4][4] = 1.127807617188;
+lensShading.ctrlPoints[2].controlPointR[4][5] = 1.086181640625;
+lensShading.ctrlPoints[2].controlPointR[4][6] = 1.149902343750;
+lensShading.ctrlPoints[2].controlPointR[4][7] = 1.204956054688;
+lensShading.ctrlPoints[2].controlPointR[4][8] = 1.016113281250;
+lensShading.ctrlPoints[2].controlPointR[4][9] = 1.176025390625;
+lensShading.ctrlPoints[2].controlPointR[5][0] = 1.069335937500;
+lensShading.ctrlPoints[2].controlPointR[5][1] = 1.100952148438;
+lensShading.ctrlPoints[2].controlPointR[5][2] = 1.120117187500;
+lensShading.ctrlPoints[2].controlPointR[5][3] = 1.127807617188;
+lensShading.ctrlPoints[2].controlPointR[5][4] = 1.097656250000;
+lensShading.ctrlPoints[2].controlPointR[5][5] = 1.150268554688;
+lensShading.ctrlPoints[2].controlPointR[5][6] = 1.127929687500;
+lensShading.ctrlPoints[2].controlPointR[5][7] = 1.130249023438;
+lensShading.ctrlPoints[2].controlPointR[5][8] = 1.116088867188;
+lensShading.ctrlPoints[2].controlPointR[5][9] = 1.090454101563;
+lensShading.ctrlPoints[2].controlPointR[6][0] = 1.109130859375;
+lensShading.ctrlPoints[2].controlPointR[6][1] = 1.076049804688;
+lensShading.ctrlPoints[2].controlPointR[6][2] = 1.141113281250;
+lensShading.ctrlPoints[2].controlPointR[6][3] = 1.131347656250;
+lensShading.ctrlPoints[2].controlPointR[6][4] = 1.144287109375;
+lensShading.ctrlPoints[2].controlPointR[6][5] = 1.161743164063;
+lensShading.ctrlPoints[2].controlPointR[6][6] = 1.140014648438;
+lensShading.ctrlPoints[2].controlPointR[6][7] = 1.165771484375;
+lensShading.ctrlPoints[2].controlPointR[6][8] = 1.043457031250;
+lensShading.ctrlPoints[2].controlPointR[6][9] = 1.234252929688;
+lensShading.ctrlPoints[2].controlPointR[7][0] = 1.234008789063;
+lensShading.ctrlPoints[2].controlPointR[7][1] = 1.033447265625;
+lensShading.ctrlPoints[2].controlPointR[7][2] = 1.155761718750;
+lensShading.ctrlPoints[2].controlPointR[7][3] = 1.151245117188;
+lensShading.ctrlPoints[2].controlPointR[7][4] = 1.151123046875;
+lensShading.ctrlPoints[2].controlPointR[7][5] = 1.177246093750;
+lensShading.ctrlPoints[2].controlPointR[7][6] = 1.147583007813;
+lensShading.ctrlPoints[2].controlPointR[7][7] = 1.153808593750;
+lensShading.ctrlPoints[2].controlPointR[7][8] = 0.965332031250;
+lensShading.ctrlPoints[2].controlPointR[7][9] = 1.398925781250;
+lensShading.ctrlPoints[2].controlPointR[8][0] = 1.171752929688;
+lensShading.ctrlPoints[2].controlPointR[8][1] = 0.985839843750;
+lensShading.ctrlPoints[2].controlPointR[8][2] = 1.111938476563;
+lensShading.ctrlPoints[2].controlPointR[8][3] = 1.116210937500;
+lensShading.ctrlPoints[2].controlPointR[8][4] = 1.182128906250;
+lensShading.ctrlPoints[2].controlPointR[8][5] = 1.095703125000;
+lensShading.ctrlPoints[2].controlPointR[8][6] = 1.146606445313;
+lensShading.ctrlPoints[2].controlPointR[8][7] = 1.030761718750;
+lensShading.ctrlPoints[2].controlPointR[8][8] = 1.168945312500;
+lensShading.ctrlPoints[2].controlPointR[8][9] = 1.306396484375;
+lensShading.ctrlPoints[2].controlPointR[9][0] = 1.507080078125;
+lensShading.ctrlPoints[2].controlPointR[9][1] = 1.070190429688;
+lensShading.ctrlPoints[2].controlPointR[9][2] = 1.147705078125;
+lensShading.ctrlPoints[2].controlPointR[9][3] = 1.104614257813;
+lensShading.ctrlPoints[2].controlPointR[9][4] = 1.175659179688;
+lensShading.ctrlPoints[2].controlPointR[9][5] = 1.151245117188;
+lensShading.ctrlPoints[2].controlPointR[9][6] = 1.116577148438;
+lensShading.ctrlPoints[2].controlPointR[9][7] = 1.212402343750;
+lensShading.ctrlPoints[2].controlPointR[9][8] = 1.031616210938;
+lensShading.ctrlPoints[2].controlPointR[9][9] = 1.976562500000;
+lensShading.ctrlPoints[2].controlPointGR[0][0] = 1.052246093750;
+lensShading.ctrlPoints[2].controlPointGR[0][1] = 0.989624023438;
+lensShading.ctrlPoints[2].controlPointGR[0][2] = 1.065917968750;
+lensShading.ctrlPoints[2].controlPointGR[0][3] = 1.062866210938;
+lensShading.ctrlPoints[2].controlPointGR[0][4] = 1.069213867188;
+lensShading.ctrlPoints[2].controlPointGR[0][5] = 1.055175781250;
+lensShading.ctrlPoints[2].controlPointGR[0][6] = 1.047119140625;
+lensShading.ctrlPoints[2].controlPointGR[0][7] = 1.119018554688;
+lensShading.ctrlPoints[2].controlPointGR[0][8] = 0.749389648438;
+lensShading.ctrlPoints[2].controlPointGR[0][9] = 1.583740234375;
+lensShading.ctrlPoints[2].controlPointGR[1][0] = 0.991088867188;
+lensShading.ctrlPoints[2].controlPointGR[1][1] = 1.075317382813;
+lensShading.ctrlPoints[2].controlPointGR[1][2] = 1.092407226563;
+lensShading.ctrlPoints[2].controlPointGR[1][3] = 1.066162109375;
+lensShading.ctrlPoints[2].controlPointGR[1][4] = 1.073974609375;
+lensShading.ctrlPoints[2].controlPointGR[1][5] = 1.107666015625;
+lensShading.ctrlPoints[2].controlPointGR[1][6] = 1.054321289063;
+lensShading.ctrlPoints[2].controlPointGR[1][7] = 1.211547851563;
+lensShading.ctrlPoints[2].controlPointGR[1][8] = 0.758422851563;
+lensShading.ctrlPoints[2].controlPointGR[1][9] = 1.214477539063;
+lensShading.ctrlPoints[2].controlPointGR[2][0] = 1.067626953125;
+lensShading.ctrlPoints[2].controlPointGR[2][1] = 1.038696289063;
+lensShading.ctrlPoints[2].controlPointGR[2][2] = 1.075683593750;
+lensShading.ctrlPoints[2].controlPointGR[2][3] = 1.082519531250;
+lensShading.ctrlPoints[2].controlPointGR[2][4] = 1.061889648438;
+lensShading.ctrlPoints[2].controlPointGR[2][5] = 1.078247070313;
+lensShading.ctrlPoints[2].controlPointGR[2][6] = 1.071777343750;
+lensShading.ctrlPoints[2].controlPointGR[2][7] = 1.100463867188;
+lensShading.ctrlPoints[2].controlPointGR[2][8] = 1.030883789063;
+lensShading.ctrlPoints[2].controlPointGR[2][9] = 1.070190429688;
+lensShading.ctrlPoints[2].controlPointGR[3][0] = 1.039184570313;
+lensShading.ctrlPoints[2].controlPointGR[3][1] = 1.067260742188;
+lensShading.ctrlPoints[2].controlPointGR[3][2] = 1.070190429688;
+lensShading.ctrlPoints[2].controlPointGR[3][3] = 1.076049804688;
+lensShading.ctrlPoints[2].controlPointGR[3][4] = 1.068115234375;
+lensShading.ctrlPoints[2].controlPointGR[3][5] = 1.064941406250;
+lensShading.ctrlPoints[2].controlPointGR[3][6] = 1.078247070313;
+lensShading.ctrlPoints[2].controlPointGR[3][7] = 1.082641601563;
+lensShading.ctrlPoints[2].controlPointGR[3][8] = 1.037719726563;
+lensShading.ctrlPoints[2].controlPointGR[3][9] = 1.064941406250;
+lensShading.ctrlPoints[2].controlPointGR[4][0] = 1.063842773438;
+lensShading.ctrlPoints[2].controlPointGR[4][1] = 1.074340820313;
+lensShading.ctrlPoints[2].controlPointGR[4][2] = 1.084960937500;
+lensShading.ctrlPoints[2].controlPointGR[4][3] = 1.075195312500;
+lensShading.ctrlPoints[2].controlPointGR[4][4] = 1.049194335938;
+lensShading.ctrlPoints[2].controlPointGR[4][5] = 1.057373046875;
+lensShading.ctrlPoints[2].controlPointGR[4][6] = 1.074951171875;
+lensShading.ctrlPoints[2].controlPointGR[4][7] = 1.162475585938;
+lensShading.ctrlPoints[2].controlPointGR[4][8] = 0.997802734375;
+lensShading.ctrlPoints[2].controlPointGR[4][9] = 1.105102539063;
+lensShading.ctrlPoints[2].controlPointGR[5][0] = 1.037841796875;
+lensShading.ctrlPoints[2].controlPointGR[5][1] = 1.067138671875;
+lensShading.ctrlPoints[2].controlPointGR[5][2] = 1.070190429688;
+lensShading.ctrlPoints[2].controlPointGR[5][3] = 1.090820312500;
+lensShading.ctrlPoints[2].controlPointGR[5][4] = 1.054687500000;
+lensShading.ctrlPoints[2].controlPointGR[5][5] = 1.092773437500;
+lensShading.ctrlPoints[2].controlPointGR[5][6] = 1.088623046875;
+lensShading.ctrlPoints[2].controlPointGR[5][7] = 1.078613281250;
+lensShading.ctrlPoints[2].controlPointGR[5][8] = 1.067016601563;
+lensShading.ctrlPoints[2].controlPointGR[5][9] = 1.041992187500;
+lensShading.ctrlPoints[2].controlPointGR[6][0] = 1.086181640625;
+lensShading.ctrlPoints[2].controlPointGR[6][1] = 1.045654296875;
+lensShading.ctrlPoints[2].controlPointGR[6][2] = 1.097900390625;
+lensShading.ctrlPoints[2].controlPointGR[6][3] = 1.087158203125;
+lensShading.ctrlPoints[2].controlPointGR[6][4] = 1.093383789063;
+lensShading.ctrlPoints[2].controlPointGR[6][5] = 1.099243164063;
+lensShading.ctrlPoints[2].controlPointGR[6][6] = 1.084838867188;
+lensShading.ctrlPoints[2].controlPointGR[6][7] = 1.109863281250;
+lensShading.ctrlPoints[2].controlPointGR[6][8] = 0.992065429688;
+lensShading.ctrlPoints[2].controlPointGR[6][9] = 1.174804687500;
+lensShading.ctrlPoints[2].controlPointGR[7][0] = 1.161254882813;
+lensShading.ctrlPoints[2].controlPointGR[7][1] = 1.059204101563;
+lensShading.ctrlPoints[2].controlPointGR[7][2] = 1.054931640625;
+lensShading.ctrlPoints[2].controlPointGR[7][3] = 1.099487304688;
+lensShading.ctrlPoints[2].controlPointGR[7][4] = 1.091918945313;
+lensShading.ctrlPoints[2].controlPointGR[7][5] = 1.106567382813;
+lensShading.ctrlPoints[2].controlPointGR[7][6] = 1.087890625000;
+lensShading.ctrlPoints[2].controlPointGR[7][7] = 1.078857421875;
+lensShading.ctrlPoints[2].controlPointGR[7][8] = 0.982543945313;
+lensShading.ctrlPoints[2].controlPointGR[7][9] = 1.277221679688;
+lensShading.ctrlPoints[2].controlPointGR[8][0] = 1.147827148438;
+lensShading.ctrlPoints[2].controlPointGR[8][1] = 0.933715820313;
+lensShading.ctrlPoints[2].controlPointGR[8][2] = 1.106079101563;
+lensShading.ctrlPoints[2].controlPointGR[8][3] = 1.079223632813;
+lensShading.ctrlPoints[2].controlPointGR[8][4] = 1.116577148438;
+lensShading.ctrlPoints[2].controlPointGR[8][5] = 1.088745117188;
+lensShading.ctrlPoints[2].controlPointGR[8][6] = 1.073852539063;
+lensShading.ctrlPoints[2].controlPointGR[8][7] = 1.063964843750;
+lensShading.ctrlPoints[2].controlPointGR[8][8] = 1.001953125000;
+lensShading.ctrlPoints[2].controlPointGR[8][9] = 1.307861328125;
+lensShading.ctrlPoints[2].controlPointGR[9][0] = 1.432128906250;
+lensShading.ctrlPoints[2].controlPointGR[9][1] = 1.074584960938;
+lensShading.ctrlPoints[2].controlPointGR[9][2] = 1.054809570313;
+lensShading.ctrlPoints[2].controlPointGR[9][3] = 1.069580078125;
+lensShading.ctrlPoints[2].controlPointGR[9][4] = 1.086669921875;
+lensShading.ctrlPoints[2].controlPointGR[9][5] = 1.098266601563;
+lensShading.ctrlPoints[2].controlPointGR[9][6] = 1.064208984375;
+lensShading.ctrlPoints[2].controlPointGR[9][7] = 1.130493164063;
+lensShading.ctrlPoints[2].controlPointGR[9][8] = 1.020874023438;
+lensShading.ctrlPoints[2].controlPointGR[9][9] = 1.854125976563;
+lensShading.ctrlPoints[2].controlPointGB[0][0] = 1.051025390625;
+lensShading.ctrlPoints[2].controlPointGB[0][1] = 1.005004882813;
+lensShading.ctrlPoints[2].controlPointGB[0][2] = 1.065551757813;
+lensShading.ctrlPoints[2].controlPointGB[0][3] = 1.067382812500;
+lensShading.ctrlPoints[2].controlPointGB[0][4] = 1.087280273438;
+lensShading.ctrlPoints[2].controlPointGB[0][5] = 1.060424804688;
+lensShading.ctrlPoints[2].controlPointGB[0][6] = 1.056884765625;
+lensShading.ctrlPoints[2].controlPointGB[0][7] = 1.148681640625;
+lensShading.ctrlPoints[2].controlPointGB[0][8] = 0.717529296875;
+lensShading.ctrlPoints[2].controlPointGB[0][9] = 1.603759765625;
+lensShading.ctrlPoints[2].controlPointGB[1][0] = 0.990478515625;
+lensShading.ctrlPoints[2].controlPointGB[1][1] = 1.097167968750;
+lensShading.ctrlPoints[2].controlPointGB[1][2] = 1.074096679688;
+lensShading.ctrlPoints[2].controlPointGB[1][3] = 1.083862304688;
+lensShading.ctrlPoints[2].controlPointGB[1][4] = 1.040039062500;
+lensShading.ctrlPoints[2].controlPointGB[1][5] = 1.114501953125;
+lensShading.ctrlPoints[2].controlPointGB[1][6] = 1.069580078125;
+lensShading.ctrlPoints[2].controlPointGB[1][7] = 1.151367187500;
+lensShading.ctrlPoints[2].controlPointGB[1][8] = 0.858032226563;
+lensShading.ctrlPoints[2].controlPointGB[1][9] = 1.179931640625;
+lensShading.ctrlPoints[2].controlPointGB[2][0] = 1.070068359375;
+lensShading.ctrlPoints[2].controlPointGB[2][1] = 0.998046875000;
+lensShading.ctrlPoints[2].controlPointGB[2][2] = 1.112426757813;
+lensShading.ctrlPoints[2].controlPointGB[2][3] = 1.072631835938;
+lensShading.ctrlPoints[2].controlPointGB[2][4] = 1.104736328125;
+lensShading.ctrlPoints[2].controlPointGB[2][5] = 1.074462890625;
+lensShading.ctrlPoints[2].controlPointGB[2][6] = 1.067749023438;
+lensShading.ctrlPoints[2].controlPointGB[2][7] = 1.120361328125;
+lensShading.ctrlPoints[2].controlPointGB[2][8] = 1.015991210938;
+lensShading.ctrlPoints[2].controlPointGB[2][9] = 1.084960937500;
+lensShading.ctrlPoints[2].controlPointGB[3][0] = 1.026855468750;
+lensShading.ctrlPoints[2].controlPointGB[3][1] = 1.093994140625;
+lensShading.ctrlPoints[2].controlPointGB[3][2] = 1.059814453125;
+lensShading.ctrlPoints[2].controlPointGB[3][3] = 1.080932617188;
+lensShading.ctrlPoints[2].controlPointGB[3][4] = 1.064941406250;
+lensShading.ctrlPoints[2].controlPointGB[3][5] = 1.072998046875;
+lensShading.ctrlPoints[2].controlPointGB[3][6] = 1.080810546875;
+lensShading.ctrlPoints[2].controlPointGB[3][7] = 1.083618164063;
+lensShading.ctrlPoints[2].controlPointGB[3][8] = 1.053588867188;
+lensShading.ctrlPoints[2].controlPointGB[3][9] = 1.062133789063;
+lensShading.ctrlPoints[2].controlPointGB[4][0] = 1.076782226563;
+lensShading.ctrlPoints[2].controlPointGB[4][1] = 1.031738281250;
+lensShading.ctrlPoints[2].controlPointGB[4][2] = 1.087158203125;
+lensShading.ctrlPoints[2].controlPointGB[4][3] = 1.073608398438;
+lensShading.ctrlPoints[2].controlPointGB[4][4] = 1.062377929688;
+lensShading.ctrlPoints[2].controlPointGB[4][5] = 1.045654296875;
+lensShading.ctrlPoints[2].controlPointGB[4][6] = 1.080932617188;
+lensShading.ctrlPoints[2].controlPointGB[4][7] = 1.153320312500;
+lensShading.ctrlPoints[2].controlPointGB[4][8] = 0.983642578125;
+lensShading.ctrlPoints[2].controlPointGB[4][9] = 1.118408203125;
+lensShading.ctrlPoints[2].controlPointGB[5][0] = 1.018066406250;
+lensShading.ctrlPoints[2].controlPointGB[5][1] = 1.095703125000;
+lensShading.ctrlPoints[2].controlPointGB[5][2] = 1.065429687500;
+lensShading.ctrlPoints[2].controlPointGB[5][3] = 1.087402343750;
+lensShading.ctrlPoints[2].controlPointGB[5][4] = 1.044067382813;
+lensShading.ctrlPoints[2].controlPointGB[5][5] = 1.110595703125;
+lensShading.ctrlPoints[2].controlPointGB[5][6] = 1.083862304688;
+lensShading.ctrlPoints[2].controlPointGB[5][7] = 1.099487304688;
+lensShading.ctrlPoints[2].controlPointGB[5][8] = 1.058837890625;
+lensShading.ctrlPoints[2].controlPointGB[5][9] = 1.044067382813;
+lensShading.ctrlPoints[2].controlPointGB[6][0] = 1.081665039063;
+lensShading.ctrlPoints[2].controlPointGB[6][1] = 1.040649414063;
+lensShading.ctrlPoints[2].controlPointGB[6][2] = 1.098754882813;
+lensShading.ctrlPoints[2].controlPointGB[6][3] = 1.081787109375;
+lensShading.ctrlPoints[2].controlPointGB[6][4] = 1.099243164063;
+lensShading.ctrlPoints[2].controlPointGB[6][5] = 1.097412109375;
+lensShading.ctrlPoints[2].controlPointGB[6][6] = 1.086425781250;
+lensShading.ctrlPoints[2].controlPointGB[6][7] = 1.107788085938;
+lensShading.ctrlPoints[2].controlPointGB[6][8] = 0.997436523438;
+lensShading.ctrlPoints[2].controlPointGB[6][9] = 1.164062500000;
+lensShading.ctrlPoints[2].controlPointGB[7][0] = 1.151733398438;
+lensShading.ctrlPoints[2].controlPointGB[7][1] = 1.036254882813;
+lensShading.ctrlPoints[2].controlPointGB[7][2] = 1.056152343750;
+lensShading.ctrlPoints[2].controlPointGB[7][3] = 1.100463867188;
+lensShading.ctrlPoints[2].controlPointGB[7][4] = 1.096679687500;
+lensShading.ctrlPoints[2].controlPointGB[7][5] = 1.093383789063;
+lensShading.ctrlPoints[2].controlPointGB[7][6] = 1.085205078125;
+lensShading.ctrlPoints[2].controlPointGB[7][7] = 1.075683593750;
+lensShading.ctrlPoints[2].controlPointGB[7][8] = 0.987182617188;
+lensShading.ctrlPoints[2].controlPointGB[7][9] = 1.268310546875;
+lensShading.ctrlPoints[2].controlPointGB[8][0] = 1.137695312500;
+lensShading.ctrlPoints[2].controlPointGB[8][1] = 0.948608398438;
+lensShading.ctrlPoints[2].controlPointGB[8][2] = 1.092163085938;
+lensShading.ctrlPoints[2].controlPointGB[8][3] = 1.074584960938;
+lensShading.ctrlPoints[2].controlPointGB[8][4] = 1.100097656250;
+lensShading.ctrlPoints[2].controlPointGB[8][5] = 1.108154296875;
+lensShading.ctrlPoints[2].controlPointGB[8][6] = 1.072998046875;
+lensShading.ctrlPoints[2].controlPointGB[8][7] = 1.067626953125;
+lensShading.ctrlPoints[2].controlPointGB[8][8] = 0.983398437500;
+lensShading.ctrlPoints[2].controlPointGB[8][9] = 1.322387695313;
+lensShading.ctrlPoints[2].controlPointGB[9][0] = 1.421752929688;
+lensShading.ctrlPoints[2].controlPointGB[9][1] = 1.078857421875;
+lensShading.ctrlPoints[2].controlPointGB[9][2] = 1.049560546875;
+lensShading.ctrlPoints[2].controlPointGB[9][3] = 1.065185546875;
+lensShading.ctrlPoints[2].controlPointGB[9][4] = 1.099609375000;
+lensShading.ctrlPoints[2].controlPointGB[9][5] = 1.079833984375;
+lensShading.ctrlPoints[2].controlPointGB[9][6] = 1.067749023438;
+lensShading.ctrlPoints[2].controlPointGB[9][7] = 1.132812500000;
+lensShading.ctrlPoints[2].controlPointGB[9][8] = 1.021606445313;
+lensShading.ctrlPoints[2].controlPointGB[9][9] = 1.829223632813;
+lensShading.ctrlPoints[2].controlPointB[0][0] = 1.067626953125;
+lensShading.ctrlPoints[2].controlPointB[0][1] = 0.951171875000;
+lensShading.ctrlPoints[2].controlPointB[0][2] = 1.110473632813;
+lensShading.ctrlPoints[2].controlPointB[0][3] = 1.056518554688;
+lensShading.ctrlPoints[2].controlPointB[0][4] = 1.093994140625;
+lensShading.ctrlPoints[2].controlPointB[0][5] = 1.054687500000;
+lensShading.ctrlPoints[2].controlPointB[0][6] = 1.069213867188;
+lensShading.ctrlPoints[2].controlPointB[0][7] = 1.134399414063;
+lensShading.ctrlPoints[2].controlPointB[0][8] = 0.739135742188;
+lensShading.ctrlPoints[2].controlPointB[0][9] = 1.590576171875;
+lensShading.ctrlPoints[2].controlPointB[1][0] = 0.969238281250;
+lensShading.ctrlPoints[2].controlPointB[1][1] = 1.175659179688;
+lensShading.ctrlPoints[2].controlPointB[1][2] = 1.016113281250;
+lensShading.ctrlPoints[2].controlPointB[1][3] = 1.098632812500;
+lensShading.ctrlPoints[2].controlPointB[1][4] = 1.035156250000;
+lensShading.ctrlPoints[2].controlPointB[1][5] = 1.125122070313;
+lensShading.ctrlPoints[2].controlPointB[1][6] = 1.055908203125;
+lensShading.ctrlPoints[2].controlPointB[1][7] = 1.160644531250;
+lensShading.ctrlPoints[2].controlPointB[1][8] = 0.858886718750;
+lensShading.ctrlPoints[2].controlPointB[1][9] = 1.210815429688;
+lensShading.ctrlPoints[2].controlPointB[2][0] = 1.090698242188;
+lensShading.ctrlPoints[2].controlPointB[2][1] = 0.956787109375;
+lensShading.ctrlPoints[2].controlPointB[2][2] = 1.132934570313;
+lensShading.ctrlPoints[2].controlPointB[2][3] = 1.060791015625;
+lensShading.ctrlPoints[2].controlPointB[2][4] = 1.104858398438;
+lensShading.ctrlPoints[2].controlPointB[2][5] = 1.052490234375;
+lensShading.ctrlPoints[2].controlPointB[2][6] = 1.083129882813;
+lensShading.ctrlPoints[2].controlPointB[2][7] = 1.119140625000;
+lensShading.ctrlPoints[2].controlPointB[2][8] = 1.034790039063;
+lensShading.ctrlPoints[2].controlPointB[2][9] = 1.066894531250;
+lensShading.ctrlPoints[2].controlPointB[3][0] = 1.028808593750;
+lensShading.ctrlPoints[2].controlPointB[3][1] = 1.086791992188;
+lensShading.ctrlPoints[2].controlPointB[3][2] = 1.064331054688;
+lensShading.ctrlPoints[2].controlPointB[3][3] = 1.079223632813;
+lensShading.ctrlPoints[2].controlPointB[3][4] = 1.063842773438;
+lensShading.ctrlPoints[2].controlPointB[3][5] = 1.071533203125;
+lensShading.ctrlPoints[2].controlPointB[3][6] = 1.080810546875;
+lensShading.ctrlPoints[2].controlPointB[3][7] = 1.100219726563;
+lensShading.ctrlPoints[2].controlPointB[3][8] = 1.048217773438;
+lensShading.ctrlPoints[2].controlPointB[3][9] = 1.080810546875;
+lensShading.ctrlPoints[2].controlPointB[4][0] = 1.089111328125;
+lensShading.ctrlPoints[2].controlPointB[4][1] = 1.040405273438;
+lensShading.ctrlPoints[2].controlPointB[4][2] = 1.078857421875;
+lensShading.ctrlPoints[2].controlPointB[4][3] = 1.073730468750;
+lensShading.ctrlPoints[2].controlPointB[4][4] = 1.048706054688;
+lensShading.ctrlPoints[2].controlPointB[4][5] = 1.068847656250;
+lensShading.ctrlPoints[2].controlPointB[4][6] = 1.084960937500;
+lensShading.ctrlPoints[2].controlPointB[4][7] = 1.156372070313;
+lensShading.ctrlPoints[2].controlPointB[4][8] = 1.000610351563;
+lensShading.ctrlPoints[2].controlPointB[4][9] = 1.117797851563;
+lensShading.ctrlPoints[2].controlPointB[5][0] = 1.024047851563;
+lensShading.ctrlPoints[2].controlPointB[5][1] = 1.084228515625;
+lensShading.ctrlPoints[2].controlPointB[5][2] = 1.072387695313;
+lensShading.ctrlPoints[2].controlPointB[5][3] = 1.081665039063;
+lensShading.ctrlPoints[2].controlPointB[5][4] = 1.074829101563;
+lensShading.ctrlPoints[2].controlPointB[5][5] = 1.076416015625;
+lensShading.ctrlPoints[2].controlPointB[5][6] = 1.093750000000;
+lensShading.ctrlPoints[2].controlPointB[5][7] = 1.072509765625;
+lensShading.ctrlPoints[2].controlPointB[5][8] = 1.104492187500;
+lensShading.ctrlPoints[2].controlPointB[5][9] = 1.054077148438;
+lensShading.ctrlPoints[2].controlPointB[6][0] = 1.086547851563;
+lensShading.ctrlPoints[2].controlPointB[6][1] = 1.045410156250;
+lensShading.ctrlPoints[2].controlPointB[6][2] = 1.100219726563;
+lensShading.ctrlPoints[2].controlPointB[6][3] = 1.083251953125;
+lensShading.ctrlPoints[2].controlPointB[6][4] = 1.095581054688;
+lensShading.ctrlPoints[2].controlPointB[6][5] = 1.097167968750;
+lensShading.ctrlPoints[2].controlPointB[6][6] = 1.093872070313;
+lensShading.ctrlPoints[2].controlPointB[6][7] = 1.130249023438;
+lensShading.ctrlPoints[2].controlPointB[6][8] = 0.980346679688;
+lensShading.ctrlPoints[2].controlPointB[6][9] = 1.195190429688;
+lensShading.ctrlPoints[2].controlPointB[7][0] = 1.171020507813;
+lensShading.ctrlPoints[2].controlPointB[7][1] = 1.062500000000;
+lensShading.ctrlPoints[2].controlPointB[7][2] = 1.063598632813;
+lensShading.ctrlPoints[2].controlPointB[7][3] = 1.118530273438;
+lensShading.ctrlPoints[2].controlPointB[7][4] = 1.072143554688;
+lensShading.ctrlPoints[2].controlPointB[7][5] = 1.124389648438;
+lensShading.ctrlPoints[2].controlPointB[7][6] = 1.093627929688;
+lensShading.ctrlPoints[2].controlPointB[7][7] = 1.110961914063;
+lensShading.ctrlPoints[2].controlPointB[7][8] = 0.973266601563;
+lensShading.ctrlPoints[2].controlPointB[7][9] = 1.320312500000;
+lensShading.ctrlPoints[2].controlPointB[8][0] = 1.119140625000;
+lensShading.ctrlPoints[2].controlPointB[8][1] = 0.935791015625;
+lensShading.ctrlPoints[2].controlPointB[8][2] = 1.070434570313;
+lensShading.ctrlPoints[2].controlPointB[8][3] = 1.055541992188;
+lensShading.ctrlPoints[2].controlPointB[8][4] = 1.120483398438;
+lensShading.ctrlPoints[2].controlPointB[8][5] = 1.078979492188;
+lensShading.ctrlPoints[2].controlPointB[8][6] = 1.070922851563;
+lensShading.ctrlPoints[2].controlPointB[8][7] = 1.046630859375;
+lensShading.ctrlPoints[2].controlPointB[8][8] = 1.051147460938;
+lensShading.ctrlPoints[2].controlPointB[8][9] = 1.285156250000;
+lensShading.ctrlPoints[2].controlPointB[9][0] = 1.434814453125;
+lensShading.ctrlPoints[2].controlPointB[9][1] = 1.068481445313;
+lensShading.ctrlPoints[2].controlPointB[9][2] = 1.075805664063;
+lensShading.ctrlPoints[2].controlPointB[9][3] = 1.076904296875;
+lensShading.ctrlPoints[2].controlPointB[9][4] = 1.084106445313;
+lensShading.ctrlPoints[2].controlPointB[9][5] = 1.102050781250;
+lensShading.ctrlPoints[2].controlPointB[9][6] = 1.076049804688;
+lensShading.ctrlPoints[2].controlPointB[9][7] = 1.137207031250;
+lensShading.ctrlPoints[2].controlPointB[9][8] = 1.001098632813;
+lensShading.ctrlPoints[2].controlPointB[9][9] = 1.901000976563;
diff --git a/frc971/orin/doflash_frc971.sh b/frc971/orin/doflash_frc971.sh
new file mode 100644
index 0000000..ecfa90c
--- /dev/null
+++ b/frc971/orin/doflash_frc971.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+set -ex
+
+TMPDIR=$(mktemp -d /tmp/yoctoflash.XXXXXXXXXX)
+
+# Cleanup on exit.
+function finish {
+ sudo rm -rf "${TMPDIR}"
+}
+trap finish EXIT
+
+# Assumes that the image has been copied into ./
+tar xf frc971-image-orin-nx-8g.tegraflash.tar.gz -C "${TMPDIR}"
+
+# Replace the rootfs with our new image.
+cp --sparse=always arm64_bookworm_debian_yocto.img "${TMPDIR}/frc971-image.ext4"
+
+cd ${TMPDIR}
+
+sudo ./initrd-flash
diff --git a/frc971/orin/virtual_packages/libglib-2.0-0/DEBIAN/control b/frc971/orin/virtual_packages/libglib-2.0-0/DEBIAN/control
new file mode 100644
index 0000000..1f9e4f0
--- /dev/null
+++ b/frc971/orin/virtual_packages/libglib-2.0-0/DEBIAN/control
@@ -0,0 +1,7 @@
+Package: libglib-2.0-0
+Version: 2.74.6-2
+Architecture: arm64
+Depends: libglib2.0-bin
+Maintainer: Austin Schuh <austin.linux@gmail.com>
+Provides: libglib-2.0-0
+Description: Adapter for libglib2.0-bin
diff --git a/frc971/orin/virtual_packages/libglvnd/DEBIAN/control b/frc971/orin/virtual_packages/libglvnd/DEBIAN/control
new file mode 100644
index 0000000..15ee630
--- /dev/null
+++ b/frc971/orin/virtual_packages/libglvnd/DEBIAN/control
@@ -0,0 +1,7 @@
+Package: libglvnd
+Version: 1.6.0-1
+Architecture: arm64
+Depends: libglvnd0
+Maintainer: Austin Schuh <austin.linux@gmail.com>
+Provides: libglvnd
+Description: Adapter for libglvnd
diff --git a/frc971/orin/virtual_packages/libgtk-3-0/DEBIAN/control b/frc971/orin/virtual_packages/libgtk-3-0/DEBIAN/control
new file mode 100644
index 0000000..8d85196
--- /dev/null
+++ b/frc971/orin/virtual_packages/libgtk-3-0/DEBIAN/control
@@ -0,0 +1,7 @@
+Package: libgtk-3.0
+Version: 3.24.38-2~deb12u1
+Architecture: arm64
+Depends: libgtk-3-0
+Maintainer: Austin Schuh <austin.linux@gmail.com>
+Provides: libgtk-3.0
+Description: Adapter for libgtk-3-0
diff --git a/frc971/orin/virtual_packages/libxcb-glx/DEBIAN/control b/frc971/orin/virtual_packages/libxcb-glx/DEBIAN/control
new file mode 100644
index 0000000..16c3060
--- /dev/null
+++ b/frc971/orin/virtual_packages/libxcb-glx/DEBIAN/control
@@ -0,0 +1,7 @@
+Package: libxcb-glx
+Version: 1.15-1
+Architecture: arm64
+Depends: libxcb-glx0
+Maintainer: Austin Schuh <austin.linux@gmail.com>
+Provides: libxcb-glx
+Description: Adapter for libxcb-glx0
diff --git a/frc971/orin/virtual_packages/wayland/DEBIAN/control b/frc971/orin/virtual_packages/wayland/DEBIAN/control
new file mode 100644
index 0000000..04ac8ca
--- /dev/null
+++ b/frc971/orin/virtual_packages/wayland/DEBIAN/control
@@ -0,0 +1,7 @@
+Package: wayland
+Version: 1.21.0-1
+Architecture: arm64
+Depends: libwayland-client0, libwayland-cursor0, libwayland-egl1, libwayland-server0
+Maintainer: Austin Schuh <austin.linux@gmail.com>
+Provides: wayland
+Description: Adapter for wayland
diff --git a/frc971/wpilib/falcon.cc b/frc971/wpilib/falcon.cc
index 6be83aa..c3ff26d 100644
--- a/frc971/wpilib/falcon.cc
+++ b/frc971/wpilib/falcon.cc
@@ -3,11 +3,12 @@
using frc971::wpilib::Falcon;
using frc971::wpilib::kMaxBringupPower;
-Falcon::Falcon(int device_id, std::string canbus,
+Falcon::Falcon(int device_id, bool inverted, std::string canbus,
std::vector<ctre::phoenix6::BaseStatusSignal *> *signals,
double stator_current_limit, double supply_current_limit)
: talon_(device_id, canbus),
device_id_(device_id),
+ inverted_(inverted),
device_temp_(talon_.GetDeviceTemp()),
supply_voltage_(talon_.GetSupplyVoltage()),
supply_current_(talon_.GetSupplyCurrent()),
@@ -37,6 +38,12 @@
signals->push_back(&duty_cycle_);
}
+Falcon::Falcon(FalconParams params, std::string canbus,
+ std::vector<ctre::phoenix6::BaseStatusSignal *> *signals,
+ double stator_current_limit, double supply_current_limit)
+ : Falcon(params.device_id, params.inverted, canbus, signals,
+ stator_current_limit, supply_current_limit) {}
+
void Falcon::PrintConfigs() {
ctre::phoenix6::configs::TalonFXConfiguration configuration;
ctre::phoenix::StatusCode status =
@@ -48,9 +55,7 @@
AOS_LOG(INFO, "configuration: %s", configuration.ToString().c_str());
}
-void Falcon::WriteConfigs(ctre::phoenix6::signals::InvertedValue invert) {
- inverted_ = invert;
-
+void Falcon::WriteConfigs() {
ctre::phoenix6::configs::CurrentLimitsConfigs current_limits;
current_limits.StatorCurrentLimit = stator_current_limit_;
current_limits.StatorCurrentLimitEnable = true;
@@ -94,7 +99,8 @@
return status;
}
-void Falcon::SerializePosition(flatbuffers::FlatBufferBuilder *fbb) {
+void Falcon::SerializePosition(flatbuffers::FlatBufferBuilder *fbb,
+ double gear_ratio) {
control_loops::CANFalcon::Builder builder(*fbb);
builder.add_id(device_id_);
builder.add_device_temp(device_temp());
@@ -102,7 +108,7 @@
builder.add_supply_current(supply_current());
builder.add_torque_current(torque_current());
builder.add_duty_cycle(duty_cycle());
- builder.add_position(position());
+ builder.add_position(position() * gear_ratio);
last_position_offset_ = builder.Finish();
}
diff --git a/frc971/wpilib/falcon.h b/frc971/wpilib/falcon.h
index 8f0f1f0..6ea8735 100644
--- a/frc971/wpilib/falcon.h
+++ b/frc971/wpilib/falcon.h
@@ -18,24 +18,35 @@
namespace frc971 {
namespace wpilib {
+struct FalconParams {
+ int device_id;
+ bool inverted;
+};
+
static constexpr units::frequency::hertz_t kCANUpdateFreqHz = 200_Hz;
static constexpr double kMaxBringupPower = 12.0;
// Gets info from and writes to falcon motors using the TalonFX controller.
class Falcon {
public:
- Falcon(int device_id, std::string canbus,
+ Falcon(int device_id, bool inverted, std::string canbus,
+ std::vector<ctre::phoenix6::BaseStatusSignal *> *signals,
+ double stator_current_limit, double supply_current_limit);
+
+ Falcon(FalconParams params, std::string canbus,
std::vector<ctre::phoenix6::BaseStatusSignal *> *signals,
double stator_current_limit, double supply_current_limit);
void PrintConfigs();
- void WriteConfigs(ctre::phoenix6::signals::InvertedValue invert);
+ void WriteConfigs();
ctre::phoenix::StatusCode WriteCurrent(double current, double max_voltage);
ctre::phoenix6::hardware::TalonFX *talon() { return &talon_; }
- void SerializePosition(flatbuffers::FlatBufferBuilder *fbb);
+ // The position of the Falcon output shaft is multiplied by gear_ratio
+ void SerializePosition(flatbuffers::FlatBufferBuilder *fbb,
+ double gear_ratio);
std::optional<flatbuffers::Offset<control_loops::CANFalcon>> TakeOffset();
diff --git a/frc971/wpilib/swerve/swerve_drivetrain_writer.cc b/frc971/wpilib/swerve/swerve_drivetrain_writer.cc
index 2b6ef9e..bfc5d73 100644
--- a/frc971/wpilib/swerve/swerve_drivetrain_writer.cc
+++ b/frc971/wpilib/swerve/swerve_drivetrain_writer.cc
@@ -37,8 +37,8 @@
void DrivetrainWriter::WriteConfigs() {
for (auto module : {front_left_, front_right_, back_left_, back_right_}) {
- module->rotation->WriteConfigs(false);
- module->translation->WriteConfigs(false);
+ module->rotation->WriteConfigs();
+ module->translation->WriteConfigs();
}
}
diff --git a/frc971/wpilib/swerve/swerve_module.h b/frc971/wpilib/swerve/swerve_module.h
index 534f0ce..f449afa 100644
--- a/frc971/wpilib/swerve/swerve_module.h
+++ b/frc971/wpilib/swerve/swerve_module.h
@@ -8,14 +8,15 @@
namespace swerve {
struct SwerveModule {
- SwerveModule(int rotation_id, int translation_id, std::string canbus,
+ SwerveModule(FalconParams rotation_params, FalconParams translation_params,
+ std::string canbus,
std::vector<ctre::phoenix6::BaseStatusSignal *> *signals,
double stator_current_limit, double supply_current_limit)
- : rotation(std::make_shared<Falcon>(rotation_id, canbus, signals,
+ : rotation(std::make_shared<Falcon>(rotation_params, canbus, signals,
stator_current_limit,
supply_current_limit)),
- translation(std::make_shared<Falcon>(translation_id, canbus, signals,
- stator_current_limit,
+ translation(std::make_shared<Falcon>(translation_params, canbus,
+ signals, stator_current_limit,
supply_current_limit)) {}
void WriteModule(
diff --git a/frc971/zeroing/BUILD b/frc971/zeroing/BUILD
index d50f181..8ca7f67 100644
--- a/frc971/zeroing/BUILD
+++ b/frc971/zeroing/BUILD
@@ -61,20 +61,8 @@
cc_library(
name = "zeroing",
srcs = [
- "absolute_and_absolute_encoder.cc",
- "absolute_encoder.cc",
- "hall_effect_and_position.cc",
- "pot_and_absolute_encoder.cc",
- "pot_and_index.cc",
- "pulse_index.cc",
],
hdrs = [
- "absolute_and_absolute_encoder.h",
- "absolute_encoder.h",
- "hall_effect_and_position.h",
- "pot_and_absolute_encoder.h",
- "pot_and_index.h",
- "pulse_index.h",
"zeroing.h",
],
target_compatible_with = ["@platforms//os:linux"],
@@ -88,19 +76,10 @@
],
)
-cc_test(
- name = "zeroing_test",
- srcs = [
- "absolute_and_absolute_encoder_test.cc",
- "absolute_encoder_test.cc",
- "hall_effect_and_position_test.cc",
- "pot_and_absolute_encoder_test.cc",
- "pot_and_index_test.cc",
- "pulse_index_test.cc",
- "relative_encoder_test.cc",
- "zeroing_test.h",
- ],
- target_compatible_with = ["@platforms//os:linux"],
+cc_library(
+ name = "zeroing_test_lib",
+ testonly = True,
+ hdrs = ["zeroing_test.h"],
deps = [
":zeroing",
"//aos/testing:googletest",
@@ -109,6 +88,46 @@
],
)
+[
+ (
+ cc_library(
+ name = lib,
+ srcs = [lib + ".cc"],
+ hdrs = [lib + ".h"],
+ deps = [
+ ":wrap",
+ ":zeroing",
+ "//aos/containers:error_list",
+ "//aos/logging",
+ "//frc971:constants",
+ "//frc971/control_loops:control_loops_fbs",
+ "@com_github_google_glog//:glog",
+ ],
+ ),
+ cc_test(
+ name = lib + "_test",
+ srcs = [lib + "_test.cc"],
+ deps = [
+ lib,
+ ":zeroing",
+ ":zeroing_test_lib",
+ "//aos/testing:googletest",
+ "//frc971/control_loops:control_loops_fbs",
+ "//frc971/control_loops:position_sensor_sim",
+ ],
+ ),
+ )
+ for lib in [
+ "absolute_and_absolute_encoder",
+ "absolute_encoder",
+ "continuous_absolute_encoder",
+ "hall_effect_and_position",
+ "pot_and_absolute_encoder",
+ "pot_and_index",
+ "pulse_index",
+ ]
+]
+
cc_library(
name = "wrap",
srcs = [
diff --git a/frc971/zeroing/absolute_encoder.h b/frc971/zeroing/absolute_encoder.h
index df40ec3..9d730f2 100644
--- a/frc971/zeroing/absolute_encoder.h
+++ b/frc971/zeroing/absolute_encoder.h
@@ -5,6 +5,7 @@
#include "flatbuffers/flatbuffers.h"
+#include "aos/containers/error_list.h"
#include "frc971/zeroing/zeroing.h"
namespace frc971 {
diff --git a/frc971/zeroing/continuous_absolute_encoder.cc b/frc971/zeroing/continuous_absolute_encoder.cc
new file mode 100644
index 0000000..a47a491
--- /dev/null
+++ b/frc971/zeroing/continuous_absolute_encoder.cc
@@ -0,0 +1,169 @@
+#include "frc971/zeroing/continuous_absolute_encoder.h"
+
+#include <cmath>
+#include <numeric>
+
+#include "glog/logging.h"
+
+#include "aos/containers/error_list.h"
+#include "frc971/zeroing/wrap.h"
+
+namespace frc971 {
+namespace zeroing {
+
+ContinuousAbsoluteEncoderZeroingEstimator::
+ ContinuousAbsoluteEncoderZeroingEstimator(
+ const constants::ContinuousAbsoluteEncoderZeroingConstants &constants)
+ : constants_(constants), move_detector_(constants_.moving_buffer_size) {
+ relative_to_absolute_offset_samples_.reserve(constants_.average_filter_size);
+ Reset();
+}
+
+void ContinuousAbsoluteEncoderZeroingEstimator::Reset() {
+ zeroed_ = false;
+ error_ = false;
+ first_offset_ = 0.0;
+ offset_ = 0.0;
+ samples_idx_ = 0;
+ position_ = 0.0;
+ nan_samples_ = 0;
+ relative_to_absolute_offset_samples_.clear();
+ move_detector_.Reset();
+}
+
+// The math here is a bit backwards, but I think it'll be less error prone that
+// way and more similar to the version with a pot as well.
+//
+// We start by unwrapping the absolute encoder using the relative encoder. This
+// puts us in a non-wrapping space and lets us average a bit easier. From
+// there, we can compute an offset and wrap ourselves back such that we stay
+// close to the middle value.
+//
+// To guard against the robot moving while updating estimates, buffer a number
+// of samples and check that the buffered samples are not different than the
+// zeroing threshold. At any point that the samples differ too much, do not
+// update estimates based on those samples.
+void ContinuousAbsoluteEncoderZeroingEstimator::UpdateEstimate(
+ const AbsolutePosition &info) {
+ // Check for Abs Encoder NaN value that would mess up the rest of the zeroing
+ // code below. NaN values are given when the Absolute Encoder is disconnected.
+ if (::std::isnan(info.absolute_encoder())) {
+ if (zeroed_) {
+ VLOG(1) << "NAN on absolute encoder.";
+ errors_.Set(ZeroingError::LOST_ABSOLUTE_ENCODER);
+ error_ = true;
+ } else {
+ ++nan_samples_;
+ VLOG(1) << "NAN on absolute encoder while zeroing " << nan_samples_;
+ if (nan_samples_ >= constants_.average_filter_size) {
+ errors_.Set(ZeroingError::LOST_ABSOLUTE_ENCODER);
+ error_ = true;
+ zeroed_ = true;
+ }
+ }
+ // Throw some dummy values in for now.
+ filtered_absolute_encoder_ = info.absolute_encoder();
+ position_ = offset_ + info.encoder();
+ return;
+ }
+
+ const bool moving = move_detector_.Update(info, constants_.moving_buffer_size,
+ constants_.zeroing_threshold);
+
+ if (!moving) {
+ const PositionStruct &sample = move_detector_.GetSample();
+
+ // adjusted_* numbers are nominally in the desired output frame.
+ const double adjusted_absolute_encoder =
+ sample.absolute_encoder - constants_.measured_absolute_position;
+
+ // Note: If are are near the breakpoint of the absolute encoder, this number
+ // will be jitter between numbers that are ~one_revolution_distance apart.
+ // For that reason, we rewrap it so that we are not near that boundary.
+ const double relative_to_absolute_offset =
+ adjusted_absolute_encoder - sample.encoder;
+
+ // To avoid the aforementioned jitter, choose a base value to use for
+ // wrapping. When we have no prior samples, just use the current offset.
+ // Otherwise, we use an arbitrary prior offset (the stored offsets will all
+ // already be wrapped).
+ const double relative_to_absolute_offset_wrap_base =
+ relative_to_absolute_offset_samples_.size() == 0
+ ? relative_to_absolute_offset
+ : relative_to_absolute_offset_samples_[0];
+
+ const double relative_to_absolute_offset_wrapped =
+ UnWrap(relative_to_absolute_offset_wrap_base,
+ relative_to_absolute_offset, constants_.one_revolution_distance);
+
+ const size_t relative_to_absolute_offset_samples_size =
+ relative_to_absolute_offset_samples_.size();
+ if (relative_to_absolute_offset_samples_size <
+ constants_.average_filter_size) {
+ relative_to_absolute_offset_samples_.push_back(
+ relative_to_absolute_offset_wrapped);
+ } else {
+ relative_to_absolute_offset_samples_[samples_idx_] =
+ relative_to_absolute_offset_wrapped;
+ }
+ samples_idx_ = (samples_idx_ + 1) % constants_.average_filter_size;
+
+ // Compute the average offset between the absolute encoder and relative
+ // encoder. Because we just pushed a value, the size() will never be zero.
+ offset_ =
+ ::std::accumulate(relative_to_absolute_offset_samples_.begin(),
+ relative_to_absolute_offset_samples_.end(), 0.0) /
+ relative_to_absolute_offset_samples_.size();
+
+ // To provide a value that can be used to estimate the
+ // measured_absolute_position when zeroing, we just need to output the
+ // current absolute encoder value. We could make use of the averaging
+ // implicit in offset_ to reduce the noise on this slightly.
+ filtered_absolute_encoder_ = sample.absolute_encoder;
+
+ if (offset_ready()) {
+ if (!zeroed_) {
+ first_offset_ = offset_;
+ }
+
+ if (::std::abs(first_offset_ - offset_) >
+ constants_.allowable_encoder_error *
+ constants_.one_revolution_distance) {
+ VLOG(1) << "Offset moved too far. Initial: " << first_offset_
+ << ", current " << offset_ << ", allowable change: "
+ << constants_.allowable_encoder_error *
+ constants_.one_revolution_distance;
+ errors_.Set(ZeroingError::OFFSET_MOVED_TOO_FAR);
+ error_ = true;
+ }
+
+ zeroed_ = true;
+ }
+ }
+
+ // Update the position. Wrap it to reflect the fact that we do not have
+ // sufficient information to disambiguate which revolution we are on (also,
+ // since this value is primarily meant for debugging, this makes it easier to
+ // see that the device is actually at zero without having to divide by 2 *
+ // pi).
+ position_ =
+ Wrap(0.0, offset_ + info.encoder(), constants_.one_revolution_distance);
+}
+
+flatbuffers::Offset<ContinuousAbsoluteEncoderZeroingEstimator::State>
+ContinuousAbsoluteEncoderZeroingEstimator::GetEstimatorState(
+ flatbuffers::FlatBufferBuilder *fbb) const {
+ flatbuffers::Offset<flatbuffers::Vector<ZeroingError>> errors_offset =
+ errors_.ToFlatbuffer(fbb);
+
+ State::Builder builder(*fbb);
+ builder.add_error(error_);
+ builder.add_zeroed(zeroed_);
+ builder.add_position(position_);
+ builder.add_absolute_position(filtered_absolute_encoder_);
+ builder.add_errors(errors_offset);
+ return builder.Finish();
+}
+
+} // namespace zeroing
+} // namespace frc971
diff --git a/frc971/zeroing/continuous_absolute_encoder.h b/frc971/zeroing/continuous_absolute_encoder.h
new file mode 100644
index 0000000..e11d866
--- /dev/null
+++ b/frc971/zeroing/continuous_absolute_encoder.h
@@ -0,0 +1,99 @@
+#ifndef FRC971_ZEROING_CONTINUOUS_ABSOLUTE_ENCODER_H_
+#define FRC971_ZEROING_CONTINUOUS_ABSOLUTE_ENCODER_H_
+
+#include <vector>
+
+#include "flatbuffers/flatbuffers.h"
+
+#include "aos/containers/error_list.h"
+#include "frc971/zeroing/zeroing.h"
+
+namespace frc971 {
+namespace zeroing {
+
+// Estimates the position with an absolute encoder which spins continuously. The
+// absolute encoder must have a 1:1 ratio to the output.
+// The provided offset(), when added to incremental encoder, may return a value
+// outside of +/- pi. The user is responsible for handling wrapping.
+class ContinuousAbsoluteEncoderZeroingEstimator
+ : public ZeroingEstimator<
+ AbsolutePosition,
+ constants::ContinuousAbsoluteEncoderZeroingConstants,
+ AbsoluteEncoderEstimatorState> {
+ public:
+ explicit ContinuousAbsoluteEncoderZeroingEstimator(
+ const constants::ContinuousAbsoluteEncoderZeroingConstants &constants);
+
+ // Resets the internal logic so it needs to be re-zeroed.
+ void Reset() override;
+
+ // Updates the sensor values for the zeroing logic.
+ void UpdateEstimate(const AbsolutePosition &info) override;
+
+ void TriggerError() override { error_ = true; }
+
+ bool zeroed() const override { return zeroed_; }
+
+ double offset() const override { return offset_; }
+
+ bool error() const override { return error_; }
+
+ // Returns true if the sample buffer is full.
+ bool offset_ready() const override {
+ return relative_to_absolute_offset_samples_.size() ==
+ constants_.average_filter_size;
+ }
+
+ // Returns information about our current state.
+ virtual flatbuffers::Offset<State> GetEstimatorState(
+ flatbuffers::FlatBufferBuilder *fbb) const override;
+
+ private:
+ struct PositionStruct {
+ PositionStruct(const AbsolutePosition &position_buffer)
+ : absolute_encoder(position_buffer.absolute_encoder()),
+ encoder(position_buffer.encoder()) {}
+ double absolute_encoder;
+ double encoder;
+ };
+
+ // The zeroing constants used to describe the configuration of the system.
+ const constants::ContinuousAbsoluteEncoderZeroingConstants constants_;
+
+ // True if the mechanism is zeroed.
+ bool zeroed_;
+ // Marker to track whether an error has occurred.
+ bool error_;
+ // The first valid offset we recorded. This is only set after zeroed_ first
+ // changes to true.
+ double first_offset_;
+
+ // The filtered absolute encoder. This is used in the status for calibration.
+ double filtered_absolute_encoder_ = 0.0;
+
+ // Samples of the offset needed to line the relative encoder up with the
+ // absolute encoder.
+ ::std::vector<double> relative_to_absolute_offset_samples_;
+
+ MoveDetector<PositionStruct, AbsolutePosition> move_detector_;
+
+ // Estimated start position of the mechanism
+ double offset_ = 0;
+ // The next position in 'relative_to_absolute_offset_samples_' and
+ // 'encoder_samples_' to be used to store the next sample.
+ int samples_idx_ = 0;
+
+ // Number of NANs we've seen in a row.
+ size_t nan_samples_ = 0;
+
+ // The filtered position.
+ double position_ = 0.0;
+
+ // Marker to track what kind of error has occured.
+ aos::ErrorList<ZeroingError> errors_;
+};
+
+} // namespace zeroing
+} // namespace frc971
+
+#endif // FRC971_ZEROING_CONTINUOUS_ABSOLUTE_ENCODER_H_
diff --git a/frc971/zeroing/continuous_absolute_encoder_test.cc b/frc971/zeroing/continuous_absolute_encoder_test.cc
new file mode 100644
index 0000000..3869393
--- /dev/null
+++ b/frc971/zeroing/continuous_absolute_encoder_test.cc
@@ -0,0 +1,198 @@
+#include "frc971/zeroing/continuous_absolute_encoder.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "frc971/zeroing/wrap.h"
+#include "frc971/zeroing/zeroing_test.h"
+
+namespace frc971 {
+namespace zeroing {
+namespace testing {
+
+using constants::ContinuousAbsoluteEncoderZeroingConstants;
+
+class ContinuousAbsoluteEncoderZeroingTest : public ZeroingTest {
+ protected:
+ void MoveTo(PositionSensorSimulator *simulator,
+ ContinuousAbsoluteEncoderZeroingEstimator *estimator,
+ double new_position) {
+ simulator->MoveTo(new_position);
+ flatbuffers::FlatBufferBuilder fbb;
+ estimator->UpdateEstimate(
+ *simulator->FillSensorValues<AbsolutePosition>(&fbb));
+ }
+};
+
+// Makes sure that using an absolute encoder lets us zero without moving.
+TEST_F(ContinuousAbsoluteEncoderZeroingTest,
+ TestContinuousAbsoluteEncoderZeroingWithoutMovement) {
+ const double index_diff = 1.0;
+ PositionSensorSimulator sim(index_diff);
+
+ const double start_pos = 2.1;
+ double measured_absolute_position = 0.3 * index_diff;
+
+ ContinuousAbsoluteEncoderZeroingConstants constants{
+ kSampleSize, index_diff, measured_absolute_position,
+ 0.1, kMovingBufferSize, kIndexErrorFraction};
+
+ sim.Initialize(start_pos, index_diff / 3.0, 0.0,
+ constants.measured_absolute_position);
+
+ ContinuousAbsoluteEncoderZeroingEstimator estimator(constants);
+
+ for (size_t i = 0; i < kSampleSize + kMovingBufferSize - 1; ++i) {
+ MoveTo(&sim, &estimator, start_pos);
+ ASSERT_FALSE(estimator.zeroed());
+ }
+
+ MoveTo(&sim, &estimator, start_pos);
+ ASSERT_TRUE(estimator.zeroed());
+ // Because the continuous estimator doesn't care about extra revolutions, it
+ // will have brought the offset down to less than index_diff.
+ EXPECT_NEAR(Wrap(0.0, start_pos, index_diff), estimator.offset(), 1e-12);
+}
+
+// Makes sure that if the underlying mechanism moves by >1 revolution that the
+// continuous zeroing estimator handles it correctly.
+TEST_F(ContinuousAbsoluteEncoderZeroingTest,
+ ContinuousEstimatorZeroesAcrossRevolution) {
+ const double index_diff = 1.0;
+ PositionSensorSimulator sim(index_diff);
+
+ const double start_pos = 2.1;
+ double measured_absolute_position = 0.3 * index_diff;
+
+ ContinuousAbsoluteEncoderZeroingConstants constants{
+ kSampleSize, index_diff, measured_absolute_position,
+ 0.1, kMovingBufferSize, kIndexErrorFraction};
+
+ sim.Initialize(start_pos, index_diff / 3.0, 0.0,
+ constants.measured_absolute_position);
+
+ ContinuousAbsoluteEncoderZeroingEstimator estimator(constants);
+
+ for (size_t i = 0; i < kSampleSize + kMovingBufferSize - 1; ++i) {
+ MoveTo(&sim, &estimator, start_pos);
+ ASSERT_FALSE(estimator.zeroed());
+ }
+
+ MoveTo(&sim, &estimator, start_pos);
+ ASSERT_TRUE(estimator.zeroed());
+ // Because the continuous estimator doesn't care about extra revolutions, it
+ // will have brought the offset down to less than index_diff.
+ EXPECT_NEAR(Wrap(0.0, start_pos, index_diff), estimator.offset(), 1e-12);
+
+ // Now, rotate by a full revolution, then stay still. We should stay zeroed.
+ for (size_t i = 0; i < kSampleSize + kMovingBufferSize; ++i) {
+ MoveTo(&sim, &estimator, start_pos + 10 * index_diff);
+ }
+ ASSERT_TRUE(estimator.zeroed());
+ ASSERT_FALSE(estimator.error());
+}
+
+// Makes sure that we ignore a NAN if we get it, but will correctly zero
+// afterwards.
+TEST_F(ContinuousAbsoluteEncoderZeroingTest,
+ TestContinuousAbsoluteEncoderZeroingIgnoresNAN) {
+ const double index_diff = 1.0;
+ PositionSensorSimulator sim(index_diff);
+
+ const double start_pos = 2.1;
+ double measured_absolute_position = 0.3 * index_diff;
+
+ ContinuousAbsoluteEncoderZeroingConstants constants{
+ kSampleSize, index_diff, measured_absolute_position,
+ 0.1, kMovingBufferSize, kIndexErrorFraction};
+
+ sim.Initialize(start_pos, index_diff / 3.0, 0.0,
+ constants.measured_absolute_position);
+
+ ContinuousAbsoluteEncoderZeroingEstimator estimator(constants);
+
+ // We tolerate a couple NANs before we start.
+ flatbuffers::FlatBufferBuilder fbb;
+ fbb.Finish(CreateAbsolutePosition(
+ fbb, 0.0, ::std::numeric_limits<double>::quiet_NaN()));
+ const auto sensor_values =
+ flatbuffers::GetRoot<AbsolutePosition>(fbb.GetBufferPointer());
+ for (size_t i = 0; i < kSampleSize - 1; ++i) {
+ estimator.UpdateEstimate(*sensor_values);
+ }
+
+ for (size_t i = 0; i < kSampleSize + kMovingBufferSize - 1; ++i) {
+ MoveTo(&sim, &estimator, start_pos);
+ ASSERT_FALSE(estimator.zeroed());
+ }
+
+ MoveTo(&sim, &estimator, start_pos);
+ ASSERT_TRUE(estimator.zeroed());
+ // Because the continuous estimator doesn't care about extra revolutions, it
+ // will have brought the offset down to less than index_diff.
+ EXPECT_NEAR(Wrap(0.0, start_pos, index_diff), estimator.offset(), 1e-12);
+}
+
+// Makes sure that using an absolute encoder doesn't let us zero while moving.
+TEST_F(ContinuousAbsoluteEncoderZeroingTest,
+ TestContinuousAbsoluteEncoderZeroingWithMovement) {
+ const double index_diff = 1.0;
+ PositionSensorSimulator sim(index_diff);
+
+ const double start_pos = 10 * index_diff;
+ double measured_absolute_position = 0.3 * index_diff;
+
+ ContinuousAbsoluteEncoderZeroingConstants constants{
+ kSampleSize, index_diff, measured_absolute_position,
+ 0.1, kMovingBufferSize, kIndexErrorFraction};
+
+ sim.Initialize(start_pos, index_diff / 3.0, 0.0,
+ constants.measured_absolute_position);
+
+ ContinuousAbsoluteEncoderZeroingEstimator estimator(constants);
+
+ for (size_t i = 0; i < kSampleSize + kMovingBufferSize - 1; ++i) {
+ MoveTo(&sim, &estimator, start_pos + i * index_diff);
+ ASSERT_FALSE(estimator.zeroed());
+ }
+ MoveTo(&sim, &estimator, start_pos + 10 * index_diff);
+
+ MoveTo(&sim, &estimator, start_pos);
+ ASSERT_FALSE(estimator.zeroed());
+}
+
+// Makes sure we detect an error if the ZeroingEstimator gets sent a NaN.
+TEST_F(ContinuousAbsoluteEncoderZeroingTest,
+ TestContinuousAbsoluteEncoderZeroingWithNaN) {
+ ContinuousAbsoluteEncoderZeroingConstants constants{
+ kSampleSize, 1, 0.3, 0.1, kMovingBufferSize, kIndexErrorFraction};
+
+ ContinuousAbsoluteEncoderZeroingEstimator estimator(constants);
+
+ flatbuffers::FlatBufferBuilder fbb;
+ fbb.Finish(CreateAbsolutePosition(
+ fbb, 0.0, ::std::numeric_limits<double>::quiet_NaN()));
+ const auto sensor_values =
+ flatbuffers::GetRoot<AbsolutePosition>(fbb.GetBufferPointer());
+ for (size_t i = 0; i < kSampleSize - 1; ++i) {
+ estimator.UpdateEstimate(*sensor_values);
+ }
+ ASSERT_FALSE(estimator.error());
+
+ estimator.UpdateEstimate(*sensor_values);
+ ASSERT_TRUE(estimator.error());
+
+ flatbuffers::FlatBufferBuilder fbb2;
+ fbb2.Finish(estimator.GetEstimatorState(&fbb2));
+
+ const AbsoluteEncoderEstimatorState *state =
+ flatbuffers::GetRoot<AbsoluteEncoderEstimatorState>(
+ fbb2.GetBufferPointer());
+
+ EXPECT_THAT(*state->errors(),
+ ::testing::ElementsAre(ZeroingError::LOST_ABSOLUTE_ENCODER));
+}
+
+} // namespace testing
+} // namespace zeroing
+} // namespace frc971
diff --git a/frc971/zeroing/zeroing.h b/frc971/zeroing/zeroing.h
index f7b52a6..5d5b6eb 100644
--- a/frc971/zeroing/zeroing.h
+++ b/frc971/zeroing/zeroing.h
@@ -172,13 +172,4 @@
} // namespace zeroing
} // namespace frc971
-// TODO(Brian): Actually split these targets apart. Need to convert all the
-// reverse dependencies to #include what they actually need...
-#include "frc971/zeroing/absolute_and_absolute_encoder.h"
-#include "frc971/zeroing/absolute_encoder.h"
-#include "frc971/zeroing/hall_effect_and_position.h"
-#include "frc971/zeroing/pot_and_absolute_encoder.h"
-#include "frc971/zeroing/pot_and_index.h"
-#include "frc971/zeroing/pulse_index.h"
-
#endif // FRC971_ZEROING_ZEROING_H_
diff --git a/scouting/www/view/view.ng.html b/scouting/www/view/view.ng.html
index 2273217..ee2c62f 100644
--- a/scouting/www/view/view.ng.html
+++ b/scouting/www/view/view.ng.html
@@ -98,8 +98,8 @@
</div>
</th>
<th scope="col">Team</th>
- <th scope="col">Set</th>
<th scope="col">Comp Level</th>
+ <th scope="col">Scout</th>
<th scope="col"></th>
</tr>
</thead>
@@ -107,8 +107,8 @@
<tr *ngFor="let stat2023 of statList; index as i;">
<th scope="row">{{stat2023.matchNumber()}}</th>
<td>{{stat2023.teamNumber()}}</td>
- <td>{{stat2023.setNumber()}}</td>
<td>{{COMP_LEVEL_LABELS[stat2023.compLevel()]}}</td>
+ <td>{{stat2023.collectedBy()}}</td>
<!-- Delete Icon. -->
<td>
<button
diff --git a/third_party/apriltag/common/workerpool.c b/third_party/apriltag/common/workerpool.c
index 29eccfc..a23832e 100644
--- a/third_party/apriltag/common/workerpool.c
+++ b/third_party/apriltag/common/workerpool.c
@@ -52,7 +52,7 @@
{
workerpool_t *wp = (workerpool_t*) p;
- int cnt = 0;
+ //int cnt = 0;
while (1) {
struct task *task;
@@ -63,13 +63,13 @@
// printf("%"PRId64" thread %d did %d\n", utime_now(), pthread_self(), cnt);
pthread_cond_broadcast(&wp->endcond);
pthread_cond_wait(&wp->startcond, &wp->mutex);
- cnt = 0;
+ //cnt = 0;
// printf("%"PRId64" thread %d awake\n", utime_now(), pthread_self());
}
zarray_get_volatile(wp->tasks, wp->taskspos, &task);
wp->taskspos++;
- cnt++;
+ //cnt++;
pthread_mutex_unlock(&wp->mutex);
// pthread_yield();
sched_yield();
diff --git a/third_party/apriltag/common/zarray.c b/third_party/apriltag/common/zarray.c
index 43e6a7e..fa1f8a2 100644
--- a/third_party/apriltag/common/zarray.c
+++ b/third_party/apriltag/common/zarray.c
@@ -41,7 +41,7 @@
return strcmp(a,b);
}
-void zarray_vmap(zarray_t *za, void (*f)())
+void zarray_vmap(zarray_t *za, void (*f)(void*))
{
assert(za != NULL);
assert(f != NULL);
diff --git a/third_party/apriltag/common/zhash.c b/third_party/apriltag/common/zhash.c
index 914f530..9414513 100644
--- a/third_party/apriltag/common/zhash.c
+++ b/third_party/apriltag/common/zhash.c
@@ -353,7 +353,7 @@
zit->last_entry--;
}
-void zhash_map_keys(zhash_t *zh, void (*f)())
+void zhash_map_keys(zhash_t *zh, void (*f)(void*))
{
assert(zh != NULL);
if (f == NULL)
@@ -369,7 +369,7 @@
}
}
-void zhash_vmap_keys(zhash_t * zh, void (*f)())
+void zhash_vmap_keys(zhash_t * zh, void (*f)(void*))
{
assert(zh != NULL);
if (f == NULL)
@@ -386,7 +386,7 @@
}
}
-void zhash_map_values(zhash_t * zh, void (*f)())
+void zhash_map_values(zhash_t * zh, void (*f)(void*))
{
assert(zh != NULL);
if (f == NULL)
@@ -401,7 +401,7 @@
}
}
-void zhash_vmap_values(zhash_t * zh, void (*f)())
+void zhash_vmap_values(zhash_t * zh, void (*f)(void*))
{
assert(zh != NULL);
if (f == NULL)
diff --git a/third_party/apriltag/common/zmaxheap.c b/third_party/apriltag/common/zmaxheap.c
index e04d03e..5cf5292 100644
--- a/third_party/apriltag/common/zmaxheap.c
+++ b/third_party/apriltag/common/zmaxheap.c
@@ -167,7 +167,7 @@
}
}
-void zmaxheap_vmap(zmaxheap_t *heap, void (*f)())
+void zmaxheap_vmap(zmaxheap_t *heap, void (*f)(void*))
{
assert(heap != NULL);
assert(f != NULL);
diff --git a/third_party/bazel-toolchain/toolchain/cc_toolchain_config.bzl b/third_party/bazel-toolchain/toolchain/cc_toolchain_config.bzl
index 59b542c..b167f6e 100644
--- a/third_party/bazel-toolchain/toolchain/cc_toolchain_config.bzl
+++ b/third_party/bazel-toolchain/toolchain/cc_toolchain_config.bzl
@@ -53,6 +53,12 @@
target_os_arch_key = _os_arch_pair(target_os, target_arch)
_check_os_arch_keys([host_os_arch_key, target_os_arch_key])
+ ## doesn't seem to have a feature for this.
+ llvm_version_split = llvm_version.split(".")
+ llvm_major_ver = int(llvm_version_split[0]) if len(llvm_version_split) else 0
+
+ llvm_subfolder = llvm_version_split[0] if llvm_major_ver > 14 else llvm_version
+
# A bunch of variables that get passed straight through to
# `create_cc_toolchain_config_info`.
# TODO: What do these values mean, and are they actually all correct?
@@ -129,7 +135,7 @@
resource_dir = [
"-resource-dir",
- "{}lib/clang/{}".format(target_toolchain_path_prefix, llvm_version),
+ "{}lib/clang/{}".format(target_toolchain_path_prefix, llvm_subfolder),
]
# Default compiler flags:
@@ -278,7 +284,7 @@
common_include_flags = [
"-nostdinc",
"-isystem",
- target_toolchain_path_prefix + "lib/clang/{}/include".format(llvm_version),
+ target_toolchain_path_prefix + "lib/clang/{}/include".format(llvm_subfolder),
"-isystem",
sysroot_path + "/usr/local/include",
"-isystem",
@@ -293,6 +299,7 @@
sysroot_path + "/usr/include",
]
compile_not_cxx_flags.extend(common_include_flags)
+
cxx_flags.extend([
"-nostdinc++",
"-isystem",
@@ -321,13 +328,12 @@
coverage_link_flags = ["-fprofile-instr-generate"]
## NOTE: framework paths is missing here; unix_cc_toolchain_config
- ## doesn't seem to have a feature for this.
# C++ built-in include directories:
cxx_builtin_include_directories = [
target_toolchain_path_prefix + "include/c++/v1",
- target_toolchain_path_prefix + "lib/clang/{}/include".format(llvm_version),
- target_toolchain_path_prefix + "lib64/clang/{}/include".format(llvm_version),
+ target_toolchain_path_prefix + "lib/clang/{}/include".format(llvm_subfolder),
+ target_toolchain_path_prefix + "lib64/clang/{}/include".format(llvm_subfolder),
]
sysroot_prefix = ""
@@ -354,8 +360,6 @@
# Tool paths:
# `llvm-strip` was introduced in V7 (https://reviews.llvm.org/D46407):
- llvm_version = llvm_version.split(".")
- llvm_major_ver = int(llvm_version[0]) if len(llvm_version) else 0
strip_binary = (tools_path_prefix + "bin/llvm-strip") if llvm_major_ver >= 7 else _host_tools.get_and_assert(host_tools_info, "strip")
# TODO: The command line formed on darwin does not work with llvm-ar.
diff --git a/third_party/bazel-toolchain/toolchain/internal/llvm_distributions.bzl b/third_party/bazel-toolchain/toolchain/internal/llvm_distributions.bzl
index 4cdbf75..031f4cf 100644
--- a/third_party/bazel-toolchain/toolchain/internal/llvm_distributions.bzl
+++ b/third_party/bazel-toolchain/toolchain/internal/llvm_distributions.bzl
@@ -181,6 +181,102 @@
"clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz": "76d0bf002ede7a893f69d9ad2c4e101d15a8f4186fbfe24e74856c8449acd7c1",
"clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz": "2c2fb857af97f41a5032e9ecadf7f78d3eff389a5cd3c9ec620d24f134ceb3c8",
"clang+llvm-13.0.0-aarch64-linux-gnu.tar.xz": "968d65d2593850ee9b37fcda074fb7641529bd45d2f976af6c8197de3c22612f",
+
+ # 13.0.1
+ "clang+llvm-13.0.1-aarch64-linux-gnu.tar.xz": "15ff2db12683e69e552b6668f7ca49edaa01ce32cb1cbc8f8ed2e887ab291069",
+ "clang+llvm-13.0.1-amd64-unknown-freebsd12.tar.xz": "8101c8d3a920bf930b33987ada5373f43537c5de8c194be0ea10530fd0ad5617",
+ "clang+llvm-13.0.1-amd64-unknown-freebsd13.tar.xz": "f1ba8ec77b5e82399af738ad9897a8aafc11c5692ceb331c8373eae77018d428",
+ "clang+llvm-13.0.1-armv7a-linux-gnueabihf.tar.xz": "1215720114538f57acbe2f3b0614c23f4fc551ba2976afa3779a3c01aaaf1221",
+ "clang+llvm-13.0.1-i386-unknown-freebsd12.tar.xz": "e3c921e0f130afa6a6ebac23c31b66b32563a5ec53a2f4ed4676f31a81379f70",
+ "clang+llvm-13.0.1-i386-unknown-freebsd13.tar.xz": "e85c46bd64a0217f3df1f42421a502648d6741ef29fd5d44674b87af119ce25d",
+ "clang+llvm-13.0.1-powerpc64le-linux-rhel-7.9.tar.xz": "ab659c290536182a99c064d4537d2fb1273bb2b1bf8c6a43866f033bf1ece4a8",
+ "clang+llvm-13.0.1-powerpc64le-linux-ubuntu-18.04.5.tar.xz": "7a4be2508aa0b4ee3f72c312af4b62ea14581a5db61aa703ea0822f46e5598cb",
+ "clang+llvm-13.0.1-x86_64-apple-darwin.tar.xz": "dec02d17698514d0fc7ace8869c38937851c542b02adf102c4e898f027145a4d",
+ "clang+llvm-13.0.1-x86_64-linux-gnu-ubuntu-18.04.tar.xz": "84a54c69781ad90615d1b0276a83ff87daaeded99fbc64457c350679df7b4ff0",
+
+ # 14.0.0
+ "clang+llvm-14.0.0-aarch64-linux-gnu.tar.xz": "1792badcd44066c79148ffeb1746058422cc9d838462be07e3cb19a4b724a1ee",
+ "clang+llvm-14.0.0-amd64-pc-solaris2.11.tar.xz": "a708470fdbaadf530d6cfd56f92fde1328cb47ef8439ecf1a2126523e7c94a50",
+ "clang+llvm-14.0.0-amd64-unknown-freebsd12.tar.xz": "7eaff7ee2a32babd795599f41f4a5ffe7f161721ebf5630f48418e626650105e",
+ "clang+llvm-14.0.0-amd64-unknown-freebsd13.tar.xz": "b68d73fd57be385e7f06046a87381f7520c8861f492c294e6301d2843d9a1f57",
+ "clang+llvm-14.0.0-armv7a-linux-gnueabihf.tar.xz": "17d5f60c3d5f9494be7f67b2dc9e6017cd5e8457e53465968a54ec7069923bfe",
+ "clang+llvm-14.0.0-i386-unknown-freebsd12.tar.xz": "5ed9d93a8425132e8117d7061d09c2989ce6b2326f25c46633e2b2dee955bb00",
+ "clang+llvm-14.0.0-i386-unknown-freebsd13.tar.xz": "81f49eb466ce9149335ac8918a5f02fa724d562a94464ed13745db0165b4a220",
+ "clang+llvm-14.0.0-powerpc64-ibm-aix-7.2.tar.xz": "4ad5866de6c69d989cbbc989201b46dfdcd7d2b23a712fcad7baa09c204f10de",
+ "clang+llvm-14.0.0-powerpc64le-linux-rhel-7.9.tar.xz": "7a31de37959fdf3be897b01f284a91c28cd38a2e2fa038ff58121d1b6f6eb087",
+ "clang+llvm-14.0.0-powerpc64le-linux-ubuntu-18.04.tar.xz": "2d504c4920885c86b306358846178bc2232dfac83b47c3b1d05861a8162980e6",
+ "clang+llvm-14.0.0-sparcv9-sun-solaris2.11.tar.xz": "b342cdaaea3b44de5b0f45052e2df49bcdf69dcc8ad0c23ec5afc04668929681",
+ "clang+llvm-14.0.0-x86_64-apple-darwin.tar.xz": "cf5af0f32d78dcf4413ef6966abbfd5b1445fe80bba57f2ff8a08f77e672b9b3",
+ "clang+llvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz": "61582215dafafb7b576ea30cc136be92c877ba1f1c31ddbbd372d6d65622fef5",
+ "clang+llvm-14.0.0-x86_64-linux-sles12.4.tar.xz": "78f70cc94c3b6f562455b15cebb63e75571d50c3d488d53d9aa4cd9dded30627",
+
+ # 15.0.0
+ "clang+llvm-15.0.0-aarch64-linux-gnu.tar.xz": "527ed550784681f95ec7a1be8fbf5a24bd03d7da9bf31afb6523996f45670be3",
+ "clang+llvm-15.0.0-amd64-pc-solaris2.11.tar.xz": "5b9fd6a30ce6941adf74667d2076a49aa047fa040e3690f7af26c264d4ce58e7",
+ "clang+llvm-15.0.0-arm64-apple-darwin21.0.tar.xz": "cfd5c3fa07d7fccea0687f5b4498329a6172b7a15bbc45b547d0ac86bd3452a5",
+ "clang+llvm-15.0.0-armv7a-linux-gnueabihf.tar.xz": "58ce8877642fc1399736ffc81bc8ef6244440fc78d72e097a07475b8b25e2bf1",
+ "clang+llvm-15.0.0-powerpc64-ibm-aix-7.2.tar.xz": "c5f63401fa88ea96ca7110bd81ead1bf1a2575962e9cc84a6713ec29c02b1c10",
+ "clang+llvm-15.0.0-powerpc64le-linux-rhel-8.4.tar.xz": "c94448766b6b92cfc8f35e611308c9680a9ad2177f88d358c2b06e9b108d61bd",
+ "clang+llvm-15.0.0-powerpc64le-linux-ubuntu-18.04.6.tar.xz": "6bcedc3d18552732f219c1d0f8c4b0c917ff5f800400a31dabfe8d040cbf1f02",
+ "clang+llvm-15.0.0-sparc64-unknown-linux-gnu.tar.xz": "b5a8108040d5d5d69d6106fa89a6cffc71a16a3583b74c1f15c42f392a47a3d9",
+ "clang+llvm-15.0.0-sparcv9-sun-solaris2.11.tar.xz": "4354854976355ca6f4ac90231a97121844c4fc9f998c9850527390120c62f01f",
+ "clang+llvm-15.0.0-x86_64-apple-darwin.tar.xz": "8fb11e6ada98b901398b2e7b0378a3a59e88c88c754e95d8f6b54613254d7d65",
+
+ # 15.0.6
+ "clang+llvm-15.0.6-aarch64-linux-gnu.tar.xz": "8ca4d68cf103da8331ca3f35fe23d940c1b78fb7f0d4763c1c059e352f5d1bec",
+ "clang+llvm-15.0.6-arm64-apple-darwin21.0.tar.xz": "32bc7b8eee3d98f72dd4e5651e6da990274ee2d28c5c19a7d8237eb817ce8d91",
+ "clang+llvm-15.0.6-armv7a-linux-gnueabihf.tar.xz": "c12e9298f9a9ed3a96342e9ffb2c02146a0cd7535231fef57c7217bd3a36f53b",
+ "clang+llvm-15.0.6-powerpc64-ibm-aix-7.2.tar.xz": "6bc1c2fcc8069e28773f6a0d16624160cd6de01b8f15aab27652eedad665d462",
+ "clang+llvm-15.0.6-powerpc64le-linux-rhel-8.4.tar.xz": "c26e5563e6ff46a03bc45fe27547c69283b64cba2359ccd3a42f735c995c0511",
+ "clang+llvm-15.0.6-powerpc64le-linux-ubuntu-18.04.tar.xz": "7fc9f07ff0fcf191df93fe4adc1da555e43f62fe1d3ddafb15c943f72b1bda17",
+ "clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04.tar.xz": "38bc7f5563642e73e69ac5626724e206d6d539fbef653541b34cae0ba9c3f036",
+
+ # 15.0.7
+ "clang+llvm-15.0.7-arm64-apple-darwin22.0.tar.xz": "867c6afd41158c132ef05a8f1ddaecf476a26b91c85def8e124414f9a9ba188d",
+ "clang+llvm-15.0.7-powerpc64-ibm-aix-7.2.tar.xz": "6cbc7c7f4395abb9c1a5bdcab3811bd6b1a6c4d08756ba674bfbbd732e2b23ac",
+ "clang+llvm-15.0.7-powerpc64le-linux-rhel-8.4.tar.xz": "2163cc934437146dc30810a21a46327ba3983f123c3bea19be316a64135b6414",
+ "clang+llvm-15.0.7-powerpc64le-linux-ubuntu-18.04.tar.xz": "19a16d768e15966923b0cbf8fc7dc148c89e316857acd89ad3aff72dcfcd61f4",
+ "clang+llvm-15.0.7-x86_64-apple-darwin21.0.tar.xz": "d16b6d536364c5bec6583d12dd7e6cf841b9f508c4430d9ee886726bd9983f1c",
+
+ # 16.0.0
+ "clang+llvm-16.0.0-aarch64-linux-gnu.tar.xz": "b750ba3120e6153fc5b316092f19b52cf3eb64e19e5f44bd1b962cb54a20cf0a",
+ "clang+llvm-16.0.0-amd64-pc-solaris2.11.tar.xz": "b637b7da383d3417ac4862342911cb467fba2ec00f48f163eb8308f2bbb9b7ad",
+ "clang+llvm-16.0.0-amd64-unknown-freebsd13.tar.xz": "c4fe6293349b3ab7d802793103d1d44f58831884e63ff1b40ce29c3e7408257b",
+ "clang+llvm-16.0.0-arm64-apple-darwin22.0.tar.xz": "2041587b90626a4a87f0de14a5842c14c6c3374f42c8ed12726ef017416409d9",
+ "clang+llvm-16.0.0-powerpc64-ibm-aix-7.2.tar.xz": "e51209eeea3c3db41084d8625ab3357991980831e0b641d633ec23e9d858333f",
+ "clang+llvm-16.0.0-powerpc64le-linux-rhel-8.4.tar.xz": "eb56949af9a83a12754f7cf254886d30c4be8a1da4dd0f27db790a7fcd35a3bf",
+ "clang+llvm-16.0.0-powerpc64le-linux-ubuntu-18.04.tar.xz": "ae34b037cde14f19c3c431de5fc04e06fa43d2cce3f8d44a63659b48afdf1f7a",
+ "clang+llvm-16.0.0-sparc64-unknown-linux-gnu.tar.xz": "a2627fcb6d97405b38c9e4c17ccfdc5d61fdd1bee742dcce0726ed39e2dcd92c",
+ "clang+llvm-16.0.0-sparcv9-sun-solaris2.11.tar.xz": "45c2ac0c10c3876332407a1ea893dccbde77a490f4a9b54a00e4881681a3c5ea",
+ "clang+llvm-16.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz": "2b8a69798e8dddeb57a186ecac217a35ea45607cb2b3cf30014431cff4340ad1",
+
+ # 16.0.1
+ "clang+llvm-16.0.1-aarch64-linux-gnu.tar.xz": "83e38451772120b016432687c0a3aab391808442b86f54966ef44c73a26280ac",
+ "clang+llvm-16.0.1-amd64-unknown-freebsd13.tar.xz": "970359de2a1a09a93a9e1cf3405e5758dfe463567b20a168f9156bd72b7f8ac6",
+ "clang+llvm-16.0.1-arm64-apple-darwin22.0.tar.xz": "cb487fa991f047dc79ae36430cbb9ef14621c1262075373955b1d97215c75879",
+ "clang+llvm-16.0.1-powerpc64-ibm-aix-7.2.tar.xz": "c56d9cf643b7f39e40436e55b59b3bd88057ec0fa084bd8e06ac17fb20ea2a21",
+ "clang+llvm-16.0.1-powerpc64le-linux-rhel-8.4.tar.xz": "c89a9af64a35ee58ef4eac7b52c173707140dc7eac6839ff254b656de8eb6c3c",
+ "clang+llvm-16.0.1-powerpc64le-linux-ubuntu-20.04.tar.xz": "08b39f9e6c19086aaf029d155c42a4db96ce662f84d6e89d8c9037d3baeee036",
+
+ # 16.0.2
+ "clang+llvm-16.0.2-aarch64-linux-gnu.tar.xz": "de89d138cfb17e2d81fdaca2f9c5e0c042014beea6bcacde7f27db40b69c0bdc",
+ "clang+llvm-16.0.2-amd64-unknown-freebsd13.tar.xz": "0cd92b6a84e7477aa8070465f01eec8198e0b1e38d1b6da8c61859a633ec9a71",
+ "clang+llvm-16.0.2-arm64-apple-darwin22.0.tar.xz": "539861297b8aa6be8e89bf68268b07d79d7a1fde87f4b98f123709f13933f326",
+ "clang+llvm-16.0.2-powerpc64-ibm-aix-7.2.tar.xz": "8c9cbf29b261f1af905f41032b446fd78bd560b549ab31d05a16d0cc972df23d",
+ "clang+llvm-16.0.2-powerpc64le-linux-rhel-8.4.tar.xz": "fe21023b64d2298d65fea0f4832a27a9948121662b54a8c8ce8a9331c4039c36",
+ "clang+llvm-16.0.2-x86_64-linux-gnu-ubuntu-22.04.tar.xz": "9530eccdffedb9761f23cbd915cf95d861b1d95f340ea36ded68bd6312af912e",
+
+ # 16.0.3
+ "clang+llvm-16.0.3-aarch64-linux-gnu.tar.xz": "315fd821ddb3e4b10c4dfabe7f200d1d17902b6a5ccd5dd665a0cd454bca379f",
+ "clang+llvm-16.0.3-arm64-apple-darwin22.0.tar.xz": "b9068eee1cf1e17848241ea581a2abe6cb4a15d470ec515c100f8b52e4c6a7cb",
+ "clang+llvm-16.0.3-powerpc64-ibm-aix-7.2.tar.xz": "f0372ea5b665ca1b8524b933b84ccbe59e9441537388815b24323aa4aab7db2f",
+ "clang+llvm-16.0.3-powerpc64le-linux-rhel-8.4.tar.xz": "9804721c746d74a85ce935d938509277af728fad1548835f539660ff1380e04d",
+ "clang+llvm-16.0.3-x86_64-linux-gnu-ubuntu-22.04.tar.xz": "638d32fd0032f99bafaab3bae63a406adb771825a02b6b7da119ee7e71af26c6",
+
+ # 16.0.4
+ "clang+llvm-16.0.4-amd64-unknown-freebsd13.tar.xz": "cf9d73bcf05b8749c7f3efbe86654b8fe0209f28993eafe26c27eb85885593f7",
+ "clang+llvm-16.0.4-arm64-apple-darwin22.0.tar.xz": "429b8061d620108fee636313df55a0602ea0d14458c6d3873989e6b130a074bd",
+ "clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04.tar.xz": "fd464333bd55b482eb7385f2f4e18248eb43129a3cda4c0920ad9ac3c12bdacf",
}
# Note: Unlike the user-specified llvm_mirror attribute, the URL prefixes in
@@ -201,6 +297,16 @@
"12.0.0": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
"12.0.1": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
"13.0.0": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
+ "13.0.1": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
+ "14.0.0": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
+ "15.0.0": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
+ "15.0.6": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
+ "15.0.7": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
+ "16.0.0": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
+ "16.0.1": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
+ "16.0.2": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
+ "16.0.3": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
+ "16.0.4": "https://github.com/llvm/llvm-project/releases/download/llvmorg-",
}
def _get_auth(ctx, urls):
diff --git a/third_party/eigen/Eigen/src/SparseCore/TriangularSolver.h b/third_party/eigen/Eigen/src/SparseCore/TriangularSolver.h
index f9c56ba..07c0d88 100644
--- a/third_party/eigen/Eigen/src/SparseCore/TriangularSolver.h
+++ b/third_party/eigen/Eigen/src/SparseCore/TriangularSolver.h
@@ -270,17 +270,12 @@
}
- Index count = 0;
// FIXME compute a reference value to filter zeros
for (typename AmbiVector<Scalar,StorageIndex>::Iterator it(tempVector/*,1e-12*/); it; ++it)
{
- ++ count;
-// std::cerr << "fill " << it.index() << ", " << col << "\n";
-// std::cout << it.value() << " ";
// FIXME use insertBack
res.insert(it.index(), col) = it.value();
}
-// std::cout << "tempVector.nonZeros() == " << int(count) << " / " << (other.rows()) << "\n";
}
res.finalize();
other = res.markAsRValue();
diff --git a/third_party/eigen/Eigen/src/SparseLU/SparseLU_heap_relax_snode.h b/third_party/eigen/Eigen/src/SparseLU/SparseLU_heap_relax_snode.h
index 6f75d50..7aecbca 100644
--- a/third_party/eigen/Eigen/src/SparseLU/SparseLU_heap_relax_snode.h
+++ b/third_party/eigen/Eigen/src/SparseLU/SparseLU_heap_relax_snode.h
@@ -75,8 +75,6 @@
// Identify the relaxed supernodes by postorder traversal of the etree
Index snode_start; // beginning of a snode
StorageIndex k;
- Index nsuper_et_post = 0; // Number of relaxed snodes in postordered etree
- Index nsuper_et = 0; // Number of relaxed snodes in the original etree
StorageIndex l;
for (j = 0; j < n; )
{
@@ -88,7 +86,6 @@
parent = et(j);
}
// Found a supernode in postordered etree, j is the last column
- ++nsuper_et_post;
k = StorageIndex(n);
for (Index i = snode_start; i <= j; ++i)
k = (std::min)(k, inv_post(i));
@@ -97,7 +94,6 @@
{
// This is also a supernode in the original etree
relax_end(k) = l; // Record last column
- ++nsuper_et;
}
else
{
@@ -107,7 +103,6 @@
if (descendants(i) == 0)
{
relax_end(l) = l;
- ++nsuper_et;
}
}
}
diff --git a/third_party/flatbuffers/src/util.cpp b/third_party/flatbuffers/src/util.cpp
index aabc23a..d3cf0d8 100644
--- a/third_party/flatbuffers/src/util.cpp
+++ b/third_party/flatbuffers/src/util.cpp
@@ -212,9 +212,16 @@
return g_file_exists_function(name);
}
-bool DirExists(const char *name) {
- // clang-format off
+#ifdef __clang__
+#define NO_MSAN_ATTRIBUTE __attribute__((no_sanitize("memory")))
+#else
+#define NO_MSAN_ATTRIBUTE
+#endif
+// For no obvious reason, clang's sanitizer thinks that the mode bits from
+// stat() are uninitialized in some circumstances.
+bool DirExists(const char *name) NO_MSAN_ATTRIBUTE {
+ // clang-format off
#ifdef _WIN32
#define flatbuffers_stat _stat
#define FLATBUFFERS_S_IFDIR _S_IFDIR
diff --git a/third_party/google-glog/bazel/glog.bzl b/third_party/google-glog/bazel/glog.bzl
index b4825d3..63f40d3 100644
--- a/third_party/google-glog/bazel/glog.bzl
+++ b/third_party/google-glog/bazel/glog.bzl
@@ -90,6 +90,7 @@
]
linux_or_darwin_copts = wasm_copts + [
+ "-Wno-unused-but-set-variable",
"-DGLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))",
# For src/utilities.cc.
"-DHAVE_SYS_SYSCALL_H",
diff --git a/third_party/googletest/googletest.patch b/third_party/googletest/googletest.patch
index ad57dc5..25d8cf4 100644
--- a/third_party/googletest/googletest.patch
+++ b/third_party/googletest/googletest.patch
@@ -30,3 +30,17 @@
linkopts = select({
"//:qnx": [],
"//:windows": [],
+diff --git a/googletest/test/BUILD.bazel b/googletest/test/BUILD.bazel
+index 1890b6ff..9bd00bd2 100644
+--- a/googletest/test/BUILD.bazel
++++ b/googletest/test/BUILD.bazel
+@@ -151,6 +151,9 @@ cc_test(
+ name = "gtest_unittest",
+ size = "small",
+ srcs = ["gtest_unittest.cc"],
++ copts = [
++ "-Wno-unused-but-set-variable",
++ ],
+ shard_count = 2,
+ deps = ["//:gtest_main"],
+ )
diff --git a/third_party/pico-sdk/tools/pioasm/BUILD b/third_party/pico-sdk/tools/pioasm/BUILD
index 355834f..1a276c3 100644
--- a/third_party/pico-sdk/tools/pioasm/BUILD
+++ b/third_party/pico-sdk/tools/pioasm/BUILD
@@ -21,6 +21,7 @@
"-Wno-unused-parameter",
"-Wno-sign-compare",
"-fexceptions",
+ "-Wno-unused-but-set-variable",
],
includes = [
".",
diff --git a/third_party/rawrtc/usrsctp/BUILD b/third_party/rawrtc/usrsctp/BUILD
index 6d1fa69..2a4118f 100644
--- a/third_party/rawrtc/usrsctp/BUILD
+++ b/third_party/rawrtc/usrsctp/BUILD
@@ -50,6 +50,7 @@
] + compiler_select({
"clang": [
"-Wno-unused-but-set-variable",
+ "-Wno-deprecated-non-prototype",
],
"gcc": [
"-Wno-discarded-qualifiers",
diff --git a/tools/build_rules/autocxx.bzl b/tools/build_rules/autocxx.bzl
index d4b6be6..01a9197 100644
--- a/tools/build_rules/autocxx.bzl
+++ b/tools/build_rules/autocxx.bzl
@@ -138,6 +138,7 @@
gen_rs.add_all(["--outdir", out_rs_json.dirname])
gen_rs.add("--gen-rs-archive")
gen_rs.add("--gen-cpp")
+ #gen_rs.add("--auto-allowlist")
gen_rs.add_all(["--generate-exact", ctx.attr.sections_to_generate])
diff --git a/y2014/control_loops/drivetrain/drivetrain_base.h b/y2014/control_loops/drivetrain/drivetrain_base.h
index a47ff5c..48143c3 100644
--- a/y2014/control_loops/drivetrain/drivetrain_base.h
+++ b/y2014/control_loops/drivetrain/drivetrain_base.h
@@ -6,8 +6,8 @@
namespace y2014 {
namespace control_loops {
-const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
- &GetDrivetrainConfig();
+const ::frc971::control_loops::drivetrain::DrivetrainConfig<double> &
+GetDrivetrainConfig();
} // namespace control_loops
} // namespace y2014
diff --git a/y2014_bot3/control_loops/drivetrain/drivetrain_base.h b/y2014_bot3/control_loops/drivetrain/drivetrain_base.h
index d41ff99..98cb31d 100644
--- a/y2014_bot3/control_loops/drivetrain/drivetrain_base.h
+++ b/y2014_bot3/control_loops/drivetrain/drivetrain_base.h
@@ -10,8 +10,8 @@
const double kDrivetrainEncoderRatio =
(17.0 / 50.0) /*output reduction*/ * (64.0 / 24.0) /*encoder gears*/;
-const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
- &GetDrivetrainConfig();
+const ::frc971::control_loops::drivetrain::DrivetrainConfig<double> &
+GetDrivetrainConfig();
} // namespace drivetrain
} // namespace control_loops
diff --git a/y2016/control_loops/drivetrain/drivetrain_base.h b/y2016/control_loops/drivetrain/drivetrain_base.h
index 4d5525a..0186a6c 100644
--- a/y2016/control_loops/drivetrain/drivetrain_base.h
+++ b/y2016/control_loops/drivetrain/drivetrain_base.h
@@ -7,8 +7,8 @@
namespace control_loops {
namespace drivetrain {
-const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
- &GetDrivetrainConfig();
+const ::frc971::control_loops::drivetrain::DrivetrainConfig<double> &
+GetDrivetrainConfig();
} // namespace drivetrain
} // namespace control_loops
diff --git a/y2016/dashboard/dashboard.cc b/y2016/dashboard/dashboard.cc
index 56b10d7..0b12b14 100644
--- a/y2016/dashboard/dashboard.cc
+++ b/y2016/dashboard/dashboard.cc
@@ -42,11 +42,11 @@
// Define the following if we want to use a local www directory and feed in
// dummy data.
-//#define DASHBOARD_TESTING
+// #define DASHBOARD_TESTING
// Define the following if we want to read from the vision queue, which has
// caused problems in the past when auto aiming that still need to be addressed.
-//#define DASHBOARD_READ_VISION_QUEUE
+// #define DASHBOARD_READ_VISION_QUEUE
DataCollector::DataCollector(::aos::EventLoop *event_loop)
: event_loop_(event_loop),
diff --git a/y2017/control_loops/drivetrain/drivetrain_base.h b/y2017/control_loops/drivetrain/drivetrain_base.h
index 59ca4a9..c84934f 100644
--- a/y2017/control_loops/drivetrain/drivetrain_base.h
+++ b/y2017/control_loops/drivetrain/drivetrain_base.h
@@ -7,8 +7,8 @@
namespace control_loops {
namespace drivetrain {
-const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
- &GetDrivetrainConfig();
+const ::frc971::control_loops::drivetrain::DrivetrainConfig<double> &
+GetDrivetrainConfig();
} // namespace drivetrain
} // namespace control_loops
diff --git a/y2017/control_loops/superstructure/column/BUILD b/y2017/control_loops/superstructure/column/BUILD
index 2d83482..6e1cc7f 100644
--- a/y2017/control_loops/superstructure/column/BUILD
+++ b/y2017/control_loops/superstructure/column/BUILD
@@ -71,6 +71,8 @@
"//frc971:constants",
"//frc971/control_loops:profiled_subsystem_fbs",
"//frc971/zeroing",
+ "//frc971/zeroing:hall_effect_and_position",
+ "//frc971/zeroing:pulse_index",
"//frc971/zeroing:wrap",
"//y2017:constants",
"//y2017/control_loops/superstructure:superstructure_position_fbs",
diff --git a/y2017/control_loops/superstructure/column/column.cc b/y2017/control_loops/superstructure/column/column.cc
index 9acd190..b8a12f7 100644
--- a/y2017/control_loops/superstructure/column/column.cc
+++ b/y2017/control_loops/superstructure/column/column.cc
@@ -11,6 +11,7 @@
#include "frc971/constants.h"
#include "frc971/control_loops/profiled_subsystem.h"
#include "frc971/control_loops/state_feedback_loop.h"
+#include "frc971/zeroing/pulse_index.h"
#include "y2017/control_loops/superstructure/column/column_integral_plant.h"
#include "y2017/control_loops/superstructure/column/stuck_column_integral_plant.h"
diff --git a/y2017/control_loops/superstructure/column/column_zeroing.h b/y2017/control_loops/superstructure/column/column_zeroing.h
index a7fe47b..c07a504 100644
--- a/y2017/control_loops/superstructure/column/column_zeroing.h
+++ b/y2017/control_loops/superstructure/column/column_zeroing.h
@@ -2,6 +2,7 @@
#define Y2017_CONTROL_LOOPS_SUPERSTRUCTURE_COLUMN_H_
#include "frc971/constants.h"
+#include "frc971/zeroing/hall_effect_and_position.h"
#include "frc971/zeroing/zeroing.h"
#include "y2017/constants.h"
#include "y2017/control_loops/superstructure/superstructure_position_generated.h"
diff --git a/y2017/control_loops/superstructure/hood/BUILD b/y2017/control_loops/superstructure/hood/BUILD
index 8f162a7..9edcc8e 100644
--- a/y2017/control_loops/superstructure/hood/BUILD
+++ b/y2017/control_loops/superstructure/hood/BUILD
@@ -43,6 +43,7 @@
deps = [
":hood_plants",
"//frc971/control_loops:profiled_subsystem",
+ "//frc971/zeroing:pulse_index",
"//y2017:constants",
"//y2017/control_loops/superstructure:superstructure_goal_fbs",
"//y2017/control_loops/superstructure:superstructure_position_fbs",
diff --git a/y2017/control_loops/superstructure/hood/hood.h b/y2017/control_loops/superstructure/hood/hood.h
index 8284e6e..47ace6e 100644
--- a/y2017/control_loops/superstructure/hood/hood.h
+++ b/y2017/control_loops/superstructure/hood/hood.h
@@ -2,6 +2,7 @@
#define Y2017_CONTROL_LOOPS_SUPERSTRUCTURE_HOOD_HOOD_H_
#include "frc971/control_loops/profiled_subsystem.h"
+#include "frc971/zeroing/pulse_index.h"
#include "y2017/constants.h"
#include "y2017/control_loops/superstructure/superstructure_goal_generated.h"
diff --git a/y2017/control_loops/superstructure/intake/BUILD b/y2017/control_loops/superstructure/intake/BUILD
index 550c241..00642b0 100644
--- a/y2017/control_loops/superstructure/intake/BUILD
+++ b/y2017/control_loops/superstructure/intake/BUILD
@@ -43,6 +43,7 @@
deps = [
":intake_plants",
"//frc971/control_loops:profiled_subsystem",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2017:constants",
"//y2017/control_loops/superstructure:superstructure_goal_fbs",
],
diff --git a/y2017/control_loops/superstructure/intake/intake.h b/y2017/control_loops/superstructure/intake/intake.h
index a91d2f0..29899fb 100644
--- a/y2017/control_loops/superstructure/intake/intake.h
+++ b/y2017/control_loops/superstructure/intake/intake.h
@@ -2,6 +2,7 @@
#define Y2017_CONTROL_LOOPS_SUPERSTRUCTURE_INTAKE_INTAKE_H_
#include "frc971/control_loops/profiled_subsystem.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2017/constants.h"
#include "y2017/control_loops/superstructure/superstructure_goal_generated.h"
diff --git a/y2017/vision/target_finder.cc b/y2017/vision/target_finder.cc
index f7a958c..e917b2e 100644
--- a/y2017/vision/target_finder.cc
+++ b/y2017/vision/target_finder.cc
@@ -68,14 +68,12 @@
RangeImage t_img = Transpose(img);
int total = 0;
int split = 0;
- int count = t_img.mini();
for (const auto &row : t_img) {
if (row.size() == 1) {
total++;
} else if (row.size() == 2) {
split++;
}
- count++;
}
return (double)split / total;
}
diff --git a/y2018/control_loops/drivetrain/drivetrain_base.h b/y2018/control_loops/drivetrain/drivetrain_base.h
index a7ce43f..0592a25 100644
--- a/y2018/control_loops/drivetrain/drivetrain_base.h
+++ b/y2018/control_loops/drivetrain/drivetrain_base.h
@@ -7,8 +7,8 @@
namespace control_loops {
namespace drivetrain {
-const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
- &GetDrivetrainConfig();
+const ::frc971::control_loops::drivetrain::DrivetrainConfig<double> &
+GetDrivetrainConfig();
} // namespace drivetrain
} // namespace control_loops
diff --git a/y2018/control_loops/superstructure/arm/BUILD b/y2018/control_loops/superstructure/arm/BUILD
index 9f969ff..ec18f9d 100644
--- a/y2018/control_loops/superstructure/arm/BUILD
+++ b/y2018/control_loops/superstructure/arm/BUILD
@@ -15,6 +15,7 @@
"//frc971/control_loops/double_jointed_arm:graph",
"//frc971/control_loops/double_jointed_arm:trajectory",
"//frc971/zeroing",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2018:constants",
"//y2018/control_loops/superstructure:superstructure_position_fbs",
"//y2018/control_loops/superstructure:superstructure_status_fbs",
diff --git a/y2018/control_loops/superstructure/arm/arm.h b/y2018/control_loops/superstructure/arm/arm.h
index 0b0a6a4..a9cf614 100644
--- a/y2018/control_loops/superstructure/arm/arm.h
+++ b/y2018/control_loops/superstructure/arm/arm.h
@@ -6,6 +6,7 @@
#include "frc971/control_loops/double_jointed_arm/ekf.h"
#include "frc971/control_loops/double_jointed_arm/graph.h"
#include "frc971/control_loops/double_jointed_arm/trajectory.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "frc971/zeroing/zeroing.h"
#include "y2018/constants.h"
#include "y2018/control_loops/superstructure/arm/generated_graph.h"
diff --git a/y2018/control_loops/superstructure/intake/BUILD b/y2018/control_loops/superstructure/intake/BUILD
index fa4eb7e..50d9989 100644
--- a/y2018/control_loops/superstructure/intake/BUILD
+++ b/y2018/control_loops/superstructure/intake/BUILD
@@ -46,6 +46,7 @@
"//frc971/control_loops:control_loop",
"//frc971/control_loops:control_loops_fbs",
"//frc971/zeroing",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2018:constants",
"//y2018/control_loops/superstructure:superstructure_output_fbs",
"//y2018/control_loops/superstructure:superstructure_position_fbs",
diff --git a/y2018/control_loops/superstructure/intake/intake.h b/y2018/control_loops/superstructure/intake/intake.h
index 09a7e4d..bec5ff6 100644
--- a/y2018/control_loops/superstructure/intake/intake.h
+++ b/y2018/control_loops/superstructure/intake/intake.h
@@ -5,6 +5,7 @@
#include "aos/commonmath.h"
#include "frc971/control_loops/control_loop.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "frc971/zeroing/wrap.h"
#include "frc971/zeroing/zeroing.h"
#include "y2018/constants.h"
diff --git a/y2019/BUILD b/y2019/BUILD
index 2fba6d6..d388819 100644
--- a/y2019/BUILD
+++ b/y2019/BUILD
@@ -41,6 +41,8 @@
"//frc971/control_loops:pose",
"//frc971/control_loops:static_zeroing_single_dof_profiled_subsystem",
"//frc971/control_loops/drivetrain:camera",
+ "//frc971/zeroing:absolute_encoder",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2019/control_loops/drivetrain:polydrivetrain_plants",
"//y2019/control_loops/superstructure/elevator:elevator_plants",
"//y2019/control_loops/superstructure/intake:intake_plants",
diff --git a/y2019/constants.cc b/y2019/constants.cc
index 10582ed..380899a 100644
--- a/y2019/constants.cc
+++ b/y2019/constants.cc
@@ -12,6 +12,8 @@
#include "aos/network/team_number.h"
#include "aos/stl_mutex/stl_mutex.h"
+#include "frc971/zeroing/absolute_encoder.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2019/control_loops/superstructure/elevator/integral_elevator_plant.h"
#include "y2019/control_loops/superstructure/intake/integral_intake_plant.h"
#include "y2019/control_loops/superstructure/stilts/integral_stilts_plant.h"
diff --git a/y2019/constants.h b/y2019/constants.h
index b6c1b55..a36e4b3 100644
--- a/y2019/constants.h
+++ b/y2019/constants.h
@@ -9,6 +9,8 @@
#include "frc971/control_loops/drivetrain/camera.h"
#include "frc971/control_loops/pose.h"
#include "frc971/control_loops/static_zeroing_single_dof_profiled_subsystem.h"
+#include "frc971/zeroing/absolute_encoder.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2019/control_loops/drivetrain/drivetrain_dog_motor_plant.h"
#include "y2019/control_loops/superstructure/elevator/elevator_plant.h"
#include "y2019/control_loops/superstructure/intake/intake_plant.h"
diff --git a/y2019/control_loops/drivetrain/BUILD b/y2019/control_loops/drivetrain/BUILD
index 80e9fe6..2ac689b 100644
--- a/y2019/control_loops/drivetrain/BUILD
+++ b/y2019/control_loops/drivetrain/BUILD
@@ -188,14 +188,14 @@
shard_count = 8,
target_compatible_with = ["@platforms//os:linux"],
deps = [
- ":localizer",
":drivetrain_base",
+ ":localizer",
"//aos/testing:googletest",
"//aos/testing:random_seed",
"//aos/testing:test_shm",
+ "//frc971/control_loops/drivetrain:splinedrivetrain",
"//frc971/control_loops/drivetrain:trajectory",
"//y2019:constants",
- "//frc971/control_loops/drivetrain:splinedrivetrain",
"@com_github_gflags_gflags//:gflags",
] + cpu_select({
"amd64": [
diff --git a/y2019/control_loops/drivetrain/drivetrain_base.h b/y2019/control_loops/drivetrain/drivetrain_base.h
index 5cee1b5..3a8bd6b 100644
--- a/y2019/control_loops/drivetrain/drivetrain_base.h
+++ b/y2019/control_loops/drivetrain/drivetrain_base.h
@@ -7,8 +7,8 @@
namespace control_loops {
namespace drivetrain {
-const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
- &GetDrivetrainConfig();
+const ::frc971::control_loops::drivetrain::DrivetrainConfig<double> &
+GetDrivetrainConfig();
} // namespace drivetrain
} // namespace control_loops
diff --git a/y2019/control_loops/superstructure/BUILD b/y2019/control_loops/superstructure/BUILD
index 9504c9f..f97c6f0 100644
--- a/y2019/control_loops/superstructure/BUILD
+++ b/y2019/control_loops/superstructure/BUILD
@@ -69,6 +69,8 @@
"//aos/events:event_loop",
"//frc971/control_loops:control_loop",
"//frc971/control_loops/drivetrain:drivetrain_status_fbs",
+ "//frc971/zeroing:absolute_encoder",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2019:constants",
"//y2019:status_light_fbs",
],
diff --git a/y2019/control_loops/superstructure/superstructure.h b/y2019/control_loops/superstructure/superstructure.h
index f8ad0fd..4d59132 100644
--- a/y2019/control_loops/superstructure/superstructure.h
+++ b/y2019/control_loops/superstructure/superstructure.h
@@ -5,6 +5,8 @@
#include "frc971/control_loops/control_loop.h"
#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
#include "frc971/control_loops/static_zeroing_single_dof_profiled_subsystem.h"
+#include "frc971/zeroing/absolute_encoder.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2019/constants.h"
#include "y2019/control_loops/superstructure/collision_avoidance.h"
#include "y2019/control_loops/superstructure/superstructure_goal_generated.h"
diff --git a/y2020/BUILD b/y2020/BUILD
index 32d392a..7c04d99 100644
--- a/y2020/BUILD
+++ b/y2020/BUILD
@@ -77,6 +77,9 @@
"//frc971:constants",
"//frc971/control_loops:static_zeroing_single_dof_profiled_subsystem",
"//frc971/shooter_interpolation:interpolation",
+ "//frc971/zeroing:absolute_and_absolute_encoder",
+ "//frc971/zeroing:absolute_encoder",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2020/control_loops/drivetrain:polydrivetrain_plants",
"//y2020/control_loops/superstructure/accelerator:accelerator_plants",
"//y2020/control_loops/superstructure/control_panel:control_panel_plants",
diff --git a/y2020/constants.cc b/y2020/constants.cc
index 4d9d066..6218f9b 100644
--- a/y2020/constants.cc
+++ b/y2020/constants.cc
@@ -12,6 +12,9 @@
#include "aos/network/team_number.h"
#include "aos/stl_mutex/stl_mutex.h"
+#include "frc971/zeroing/absolute_and_absolute_encoder.h"
+#include "frc971/zeroing/absolute_encoder.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2020/control_loops/superstructure/control_panel/integral_control_panel_plant.h"
#include "y2020/control_loops/superstructure/hood/integral_hood_plant.h"
#include "y2020/control_loops/superstructure/intake/integral_intake_plant.h"
diff --git a/y2020/constants.h b/y2020/constants.h
index 83b2cec..7332b4f 100644
--- a/y2020/constants.h
+++ b/y2020/constants.h
@@ -8,6 +8,9 @@
#include "frc971/constants.h"
#include "frc971/control_loops/static_zeroing_single_dof_profiled_subsystem.h"
#include "frc971/shooter_interpolation/interpolation.h"
+#include "frc971/zeroing/absolute_and_absolute_encoder.h"
+#include "frc971/zeroing/absolute_encoder.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2020/control_loops/drivetrain/drivetrain_dog_motor_plant.h"
#include "y2020/control_loops/superstructure/accelerator/accelerator_plant.h"
#include "y2020/control_loops/superstructure/control_panel/control_panel_plant.h"
diff --git a/y2020/control_loops/drivetrain/drivetrain_base.h b/y2020/control_loops/drivetrain/drivetrain_base.h
index c220088..e35c2af 100644
--- a/y2020/control_loops/drivetrain/drivetrain_base.h
+++ b/y2020/control_loops/drivetrain/drivetrain_base.h
@@ -7,8 +7,8 @@
namespace control_loops {
namespace drivetrain {
-const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
- &GetDrivetrainConfig();
+const ::frc971::control_loops::drivetrain::DrivetrainConfig<double> &
+GetDrivetrainConfig();
} // namespace drivetrain
} // namespace control_loops
diff --git a/y2020/control_loops/superstructure/BUILD b/y2020/control_loops/superstructure/BUILD
index d1f20a2..83af834 100644
--- a/y2020/control_loops/superstructure/BUILD
+++ b/y2020/control_loops/superstructure/BUILD
@@ -83,6 +83,9 @@
"//frc971/control_loops:control_loop",
"//frc971/control_loops:control_loops_fbs",
"//frc971/control_loops/drivetrain:drivetrain_status_fbs",
+ "//frc971/zeroing:absolute_and_absolute_encoder",
+ "//frc971/zeroing:absolute_encoder",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2020:constants",
"//y2020/control_loops/superstructure/hood:hood_encoder_zeroing_estimator",
"//y2020/control_loops/superstructure/shooter",
diff --git a/y2020/control_loops/superstructure/hood/BUILD b/y2020/control_loops/superstructure/hood/BUILD
index 437c67a..7983e62 100644
--- a/y2020/control_loops/superstructure/hood/BUILD
+++ b/y2020/control_loops/superstructure/hood/BUILD
@@ -44,6 +44,7 @@
target_compatible_with = ["@platforms//os:linux"],
deps = [
"//frc971/zeroing",
+ "//frc971/zeroing:absolute_and_absolute_encoder",
"//y2020:constants",
],
)
diff --git a/y2020/control_loops/superstructure/hood/hood_encoder_zeroing_estimator.cc b/y2020/control_loops/superstructure/hood/hood_encoder_zeroing_estimator.cc
index dee4461..249dd00 100644
--- a/y2020/control_loops/superstructure/hood/hood_encoder_zeroing_estimator.cc
+++ b/y2020/control_loops/superstructure/hood/hood_encoder_zeroing_estimator.cc
@@ -2,6 +2,8 @@
#include <cmath>
+#include "frc971/zeroing/absolute_and_absolute_encoder.h"
+
namespace y2020::control_loops::superstructure::hood {
HoodEncoderZeroingEstimator::HoodEncoderZeroingEstimator(
diff --git a/y2020/control_loops/superstructure/superstructure.h b/y2020/control_loops/superstructure/superstructure.h
index 5d371fc..8a00bf0 100644
--- a/y2020/control_loops/superstructure/superstructure.h
+++ b/y2020/control_loops/superstructure/superstructure.h
@@ -5,6 +5,9 @@
#include "frc971/control_loops/control_loop.h"
#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
#include "frc971/input/joystick_state_generated.h"
+#include "frc971/zeroing/absolute_and_absolute_encoder.h"
+#include "frc971/zeroing/absolute_encoder.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2020/constants.h"
#include "y2020/control_loops/superstructure/hood/hood_encoder_zeroing_estimator.h"
#include "y2020/control_loops/superstructure/shooter/shooter.h"
diff --git a/y2020/vision/sift/fast_gaussian_halide_generator.sh b/y2020/vision/sift/fast_gaussian_halide_generator.sh
index 793e56c..cf094b8 100755
--- a/y2020/vision/sift/fast_gaussian_halide_generator.sh
+++ b/y2020/vision/sift/fast_gaussian_halide_generator.sh
@@ -43,12 +43,12 @@
-isystem"${SYSROOT}/usr/include/c++/10" \
-isystem"${SYSROOT}/usr/include/${MULTIARCH}/c++/10" \
-isystem"${SYSROOT}/usr/include/c++/7/backward" \
- -isystem"${LLVM_TOOLCHAIN}/lib/clang/13.0.0/include" \
+ -isystem"${LLVM_TOOLCHAIN}/lib/clang/16/include" \
-isystem"${SYSROOT}/usr/include/${MULTIARCH}" \
-isystem"${SYSROOT}/usr/include" \
-isystem"${SYSROOT}/include" \
"--sysroot=${SYSROOT}" \
- -resource-dir "${LLVM_TOOLCHAIN}/lib/clang/13.0.0" \
+ -resource-dir "${LLVM_TOOLCHAIN}/lib/clang/16" \
-target "${TARGET}" \
-fuse-ld=lld \
-L"${LLVM_TOOLCHAIN}/lib" \
diff --git a/y2021_bot3/control_loops/drivetrain/drivetrain_base.h b/y2021_bot3/control_loops/drivetrain/drivetrain_base.h
index 7250f93..f796d4e 100644
--- a/y2021_bot3/control_loops/drivetrain/drivetrain_base.h
+++ b/y2021_bot3/control_loops/drivetrain/drivetrain_base.h
@@ -7,8 +7,8 @@
namespace control_loops {
namespace drivetrain {
-const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
- &GetDrivetrainConfig();
+const ::frc971::control_loops::drivetrain::DrivetrainConfig<double> &
+GetDrivetrainConfig();
} // namespace drivetrain
} // namespace control_loops
diff --git a/y2022/BUILD b/y2022/BUILD
index f25925e..8d9d901 100644
--- a/y2022/BUILD
+++ b/y2022/BUILD
@@ -224,6 +224,7 @@
"//frc971/control_loops:static_zeroing_single_dof_profiled_subsystem",
"//frc971/shooter_interpolation:interpolation",
"//frc971/wpilib:wpilib_utils",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2022/control_loops/drivetrain:polydrivetrain_plants",
"//y2022/control_loops/superstructure/catapult:catapult_plants",
"//y2022/control_loops/superstructure/climber:climber_plants",
diff --git a/y2022/constants.cc b/y2022/constants.cc
index ff1c738..8ba3367 100644
--- a/y2022/constants.cc
+++ b/y2022/constants.cc
@@ -13,6 +13,7 @@
#include "aos/mutex/mutex.h"
#include "aos/network/team_number.h"
#include "frc971/wpilib/wpilib_utils.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2022/control_loops/superstructure/catapult/integral_catapult_plant.h"
#include "y2022/control_loops/superstructure/climber/integral_climber_plant.h"
#include "y2022/control_loops/superstructure/intake/integral_intake_plant.h"
diff --git a/y2022/constants.h b/y2022/constants.h
index 62b9b4a..f27b6cd 100644
--- a/y2022/constants.h
+++ b/y2022/constants.h
@@ -9,6 +9,7 @@
#include "frc971/control_loops/pose.h"
#include "frc971/control_loops/static_zeroing_single_dof_profiled_subsystem.h"
#include "frc971/shooter_interpolation/interpolation.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2022/control_loops/drivetrain/drivetrain_dog_motor_plant.h"
#include "y2022/control_loops/superstructure/catapult/catapult_plant.h"
#include "y2022/control_loops/superstructure/climber/climber_plant.h"
diff --git a/y2022/control_loops/drivetrain/drivetrain_base.h b/y2022/control_loops/drivetrain/drivetrain_base.h
index 2983016..1f4cfe4 100644
--- a/y2022/control_loops/drivetrain/drivetrain_base.h
+++ b/y2022/control_loops/drivetrain/drivetrain_base.h
@@ -7,8 +7,8 @@
namespace control_loops {
namespace drivetrain {
-const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
- &GetDrivetrainConfig();
+const ::frc971::control_loops::drivetrain::DrivetrainConfig<double> &
+GetDrivetrainConfig();
} // namespace drivetrain
} // namespace control_loops
diff --git a/y2022/control_loops/superstructure/BUILD b/y2022/control_loops/superstructure/BUILD
index e0db64c..e370f0e 100644
--- a/y2022/control_loops/superstructure/BUILD
+++ b/y2022/control_loops/superstructure/BUILD
@@ -86,6 +86,7 @@
"//aos/events:event_loop",
"//frc971/control_loops:control_loop",
"//frc971/control_loops/drivetrain:drivetrain_status_fbs",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2022:constants",
"//y2022/control_loops/superstructure/catapult",
"//y2022/control_loops/superstructure/turret:aiming",
diff --git a/y2022/control_loops/superstructure/catapult/BUILD b/y2022/control_loops/superstructure/catapult/BUILD
index a43925e..36e34bd 100644
--- a/y2022/control_loops/superstructure/catapult/BUILD
+++ b/y2022/control_loops/superstructure/catapult/BUILD
@@ -41,6 +41,7 @@
deps = [
":catapult_plants",
"//aos:realtime",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//third_party/osqp-cpp",
"//y2022:constants",
"//y2022/control_loops/superstructure:superstructure_goal_fbs",
diff --git a/y2022/control_loops/superstructure/catapult/catapult.h b/y2022/control_loops/superstructure/catapult/catapult.h
index a4c82de..d30e8f5 100644
--- a/y2022/control_loops/superstructure/catapult/catapult.h
+++ b/y2022/control_loops/superstructure/catapult/catapult.h
@@ -5,6 +5,7 @@
#include "glog/logging.h"
#include "frc971/control_loops/state_feedback_loop.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "osqp++.h"
#include "y2022/constants.h"
#include "y2022/control_loops/superstructure/superstructure_goal_generated.h"
diff --git a/y2022/control_loops/superstructure/superstructure.h b/y2022/control_loops/superstructure/superstructure.h
index 5e3415c..36269e9 100644
--- a/y2022/control_loops/superstructure/superstructure.h
+++ b/y2022/control_loops/superstructure/superstructure.h
@@ -4,6 +4,7 @@
#include "aos/events/event_loop.h"
#include "frc971/control_loops/control_loop.h"
#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2022/constants.h"
#include "y2022/control_loops/superstructure/catapult/catapult.h"
#include "y2022/control_loops/superstructure/collision_avoidance.h"
diff --git a/y2022_bot3/BUILD b/y2022_bot3/BUILD
index 29debe7..125ff44 100644
--- a/y2022_bot3/BUILD
+++ b/y2022_bot3/BUILD
@@ -116,6 +116,7 @@
"//frc971/control_loops:pose",
"//frc971/control_loops:static_zeroing_single_dof_profiled_subsystem",
"//frc971/shooter_interpolation:interpolation",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2022_bot3/control_loops/drivetrain:polydrivetrain_plants",
"//y2022_bot3/control_loops/superstructure/climber:climber_plants",
"//y2022_bot3/control_loops/superstructure/intake:intake_plants",
diff --git a/y2022_bot3/constants.cc b/y2022_bot3/constants.cc
index 7ec5187..82982aa 100644
--- a/y2022_bot3/constants.cc
+++ b/y2022_bot3/constants.cc
@@ -12,6 +12,7 @@
#include "aos/mutex/mutex.h"
#include "aos/network/team_number.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2022_bot3/control_loops/superstructure/climber/integral_climber_plant.h"
#include "y2022_bot3/control_loops/superstructure/intake/integral_intake_plant.h"
diff --git a/y2022_bot3/constants.h b/y2022_bot3/constants.h
index 2ced38d..a87930f 100644
--- a/y2022_bot3/constants.h
+++ b/y2022_bot3/constants.h
@@ -9,6 +9,7 @@
#include "frc971/control_loops/pose.h"
#include "frc971/control_loops/static_zeroing_single_dof_profiled_subsystem.h"
#include "frc971/shooter_interpolation/interpolation.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2022_bot3/control_loops/drivetrain/drivetrain_dog_motor_plant.h"
#include "y2022_bot3/control_loops/superstructure/climber/climber_plant.h"
#include "y2022_bot3/control_loops/superstructure/intake/intake_plant.h"
diff --git a/y2022_bot3/control_loops/drivetrain/drivetrain_base.h b/y2022_bot3/control_loops/drivetrain/drivetrain_base.h
index cce197e..04c6c86 100644
--- a/y2022_bot3/control_loops/drivetrain/drivetrain_base.h
+++ b/y2022_bot3/control_loops/drivetrain/drivetrain_base.h
@@ -7,8 +7,8 @@
namespace control_loops {
namespace drivetrain {
-const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
- &GetDrivetrainConfig();
+const ::frc971::control_loops::drivetrain::DrivetrainConfig<double> &
+GetDrivetrainConfig();
} // namespace drivetrain
} // namespace control_loops
diff --git a/y2022_bot3/control_loops/superstructure/BUILD b/y2022_bot3/control_loops/superstructure/BUILD
index 7d89a0a..5b44e2a 100644
--- a/y2022_bot3/control_loops/superstructure/BUILD
+++ b/y2022_bot3/control_loops/superstructure/BUILD
@@ -75,6 +75,7 @@
"//aos/events:event_loop",
"//frc971/control_loops:control_loop",
"//frc971/control_loops/drivetrain:drivetrain_status_fbs",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2022_bot3:constants",
],
)
diff --git a/y2022_bot3/control_loops/superstructure/superstructure.h b/y2022_bot3/control_loops/superstructure/superstructure.h
index 4f33c3c..13d5dec 100644
--- a/y2022_bot3/control_loops/superstructure/superstructure.h
+++ b/y2022_bot3/control_loops/superstructure/superstructure.h
@@ -4,6 +4,7 @@
#include "aos/events/event_loop.h"
#include "frc971/control_loops/control_loop.h"
#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2022_bot3/constants.h"
#include "y2022_bot3/control_loops/superstructure/superstructure_goal_generated.h"
#include "y2022_bot3/control_loops/superstructure/superstructure_output_generated.h"
diff --git a/y2023/BUILD b/y2023/BUILD
index e200f87..d934927 100644
--- a/y2023/BUILD
+++ b/y2023/BUILD
@@ -254,6 +254,8 @@
"//frc971/control_loops:pose",
"//frc971/control_loops:static_zeroing_single_dof_profiled_subsystem",
"//frc971/shooter_interpolation:interpolation",
+ "//frc971/zeroing:absolute_encoder",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2023/control_loops/drivetrain:polydrivetrain_plants",
"//y2023/control_loops/superstructure/arm:arm_constants",
"//y2023/control_loops/superstructure/roll:roll_plants",
diff --git a/y2023/autonomous/autonomous_actor.cc b/y2023/autonomous/autonomous_actor.cc
index bedbab7..8891223 100644
--- a/y2023/autonomous/autonomous_actor.cc
+++ b/y2023/autonomous/autonomous_actor.cc
@@ -15,6 +15,7 @@
DEFINE_bool(spline_auto, false, "Run simple test S-spline auto mode.");
DEFINE_bool(charged_up, true, "If true run charged up autonomous mode");
DEFINE_bool(charged_up_cable, false, "If true run cable side autonomous mode");
+DEFINE_bool(do_balance, true, "If true run the balance.");
namespace y2023 {
namespace autonomous {
@@ -364,6 +365,7 @@
AOS_LOG(
INFO, "Placed second cube %lf s\n",
aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
+
InitializeEncoders();
const ProfileParametersT kDrive = MakeProfileParameters(2.0, 4.0);
@@ -381,6 +383,11 @@
INFO, "Done backing up %lf s\n",
aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
+ if (!FLAGS_do_balance) {
+ StopSpitting();
+ return;
+ }
+
const ProfileParametersT kInPlaceTurn = MakeProfileParameters(2.7, 8.0);
StartDrive(0.0, aos::math::NormalizeAngle(M_PI / 2.0 - Theta()), kDrive,
kInPlaceTurn);
diff --git a/y2023/autonomous/splines/spline.1.json b/y2023/autonomous/splines/spline.1.json
index 5240ad8..ae80ebe 100644
--- a/y2023/autonomous/splines/spline.1.json
+++ b/y2023/autonomous/splines/spline.1.json
@@ -1 +1 @@
-{"spline_count": 1, "spline_x": [1.609310857796625, 2.5819120488556946, 3.506443404506549, 5.555694235956169, 5.989575501273337, 6.418880858416194], "spline_y": [0.6043502546533336, 0.69141924611354, 1.0213742193777775, 0.38712949808092717, 0.40845524312381665, 0.40845524312381665], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3.5}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2}, {"constraint_type": "VOLTAGE", "value": 12.0}]}
\ No newline at end of file
+{"spline_count": 1, "spline_x": [1.609310857796625, 2.5819120488556946, 3.506443404506549, 5.571740737699863, 6.005622003017031, 6.434927360159888], "spline_y": [0.6043502546533336, 0.69141924611354, 1.0213742193777775, 0.47692519455739807, 0.49825093960028755, 0.49825093960028755], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3.5}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2}, {"constraint_type": "VOLTAGE", "value": 12.0}]}
\ No newline at end of file
diff --git a/y2023/autonomous/splines/spline.2.json b/y2023/autonomous/splines/spline.2.json
index 297966c..4afc161 100644
--- a/y2023/autonomous/splines/spline.2.json
+++ b/y2023/autonomous/splines/spline.2.json
@@ -1 +1 @@
-{"spline_count": 1, "spline_x": [6.418880858416194, 6.02775087044969, 5.275605833281384, 2.8053451665928835, 2.37026593061867, 1.5260719060059573], "spline_y": [0.40845524312381665, 0.40845524312381665, 0.4647376584428905, 1.3287637699876067, -0.026954142728124464, -0.5547144640218522], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3.5}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2.5}, {"constraint_type": "VOLTAGE", "value": 12.0}]}
\ No newline at end of file
+{"spline_count": 1, "spline_x": [6.434927360159888, 6.043797372193384, 5.291652335025078, 2.8053451665928835, 2.37026593061867, 1.5260719060059573], "spline_y": [0.49825093960028755, 0.49825093960028755, 0.5545333549193614, 1.3287637699876067, -0.026954142728124464, -0.5547144640218522], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3.5}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2.5}, {"constraint_type": "VOLTAGE", "value": 12.0}]}
\ No newline at end of file
diff --git a/y2023/constants.cc b/y2023/constants.cc
index 5ab6407..56be337 100644
--- a/y2023/constants.cc
+++ b/y2023/constants.cc
@@ -84,31 +84,34 @@
break;
case kCompTeamNumber:
- arm_proximal->zeroing.measured_absolute_position = 0.911194143585562;
+ arm_proximal->zeroing.measured_absolute_position = 0.911747959388894;
arm_proximal->potentiometer_offset =
10.5178592988554 + 0.0944609125285876 - 0.00826532984625095 +
- 0.167359305216504 + 0.135144500925909 - 0.214909475332252;
+ 0.167359305216504 + 0.135144500925909 - 0.214909475332252 +
+ 0.0377032255050543;
- arm_distal->zeroing.measured_absolute_position = 0.295329750530428;
+ arm_distal->zeroing.measured_absolute_position = 0.294291930885304;
arm_distal->potentiometer_offset =
7.673132586937 - 0.0799284644472573 - 0.0323574039310657 +
0.0143810684138064 + 0.00945555248207735 + 0.452446388633863 +
0.0194863477007102 + 0.235993332670562 + 0.00138417783482921 -
- 1.29562640607084;
+ 1.29562640607084 - 0.390356125757262 - 0.267002511437832 -
+ 0.611626839639182 + 2.55745730136924 + 0.503121678457021 +
+ 0.0440779746883177;
arm_distal->zeroing.one_revolution_distance =
M_PI * 2.0 * constants::Values::kDistalEncoderRatio() *
(3.12725165289659 + 0.002) / 3.1485739705977704;
- roll_joint->zeroing.measured_absolute_position = 1.79390317510529;
+ roll_joint->zeroing.measured_absolute_position = 1.82824749141201;
roll_joint->potentiometer_offset =
0.624713611895747 + 3.10458504917251 - 0.0966407797407789 +
0.0257708772364788 - 0.0395076737853459 - 6.87914956118006 -
0.097581301615046 + 3.3424421683095 - 3.97605190912604 +
- 0.709274294168941;
+ 0.709274294168941 - 0.0817908884966825;
wrist->subsystem_params.zeroing_constants.measured_absolute_position =
- 2.97717660361257;
+ 0.744036527649413;
break;
diff --git a/y2023/constants.h b/y2023/constants.h
index 32ed317..84d6499 100644
--- a/y2023/constants.h
+++ b/y2023/constants.h
@@ -8,6 +8,8 @@
#include "frc971/constants.h"
#include "frc971/control_loops/pose.h"
#include "frc971/control_loops/static_zeroing_single_dof_profiled_subsystem.h"
+#include "frc971/zeroing/absolute_encoder.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2023/control_loops/drivetrain/drivetrain_dog_motor_plant.h"
#include "y2023/control_loops/superstructure/arm/arm_constants.h"
#include "y2023/control_loops/superstructure/roll/roll_plant.h"
diff --git a/y2023/constants/971.json b/y2023/constants/971.json
index 3c3ba38..fc21b74 100644
--- a/y2023/constants/971.json
+++ b/y2023/constants/971.json
@@ -4,13 +4,13 @@
"calibration": {% include 'y2023/vision/calib_files/calibration_pi-971-1_cam-23-09_ext_2023-03-05.json' %}
},
{
- "calibration": {% include 'y2023/vision/calib_files/calibration_pi-971-2_cam-23-10_ext_2023-04-15.json' %}
+ "calibration": {% include 'y2023/vision/calib_files/calibration_pi-971-2_cam-23-10_ext_2023-09-23.json' %}
},
{
- "calibration": {% include 'y2023/vision/calib_files/calibration_pi-971-3_cam-23-11_ext_2023-04-15.json' %}
+ "calibration": {% include 'y2023/vision/calib_files/calibration_pi-971-3_cam-23-11_ext_2023-09-23.json' %}
},
{
- "calibration": {% include 'y2023/vision/calib_files/calibration_pi-971-4_cam-23-12_ext_2023-04-15.json' %}
+ "calibration": {% include 'y2023/vision/calib_files/calibration_pi-971-4_cam-23-12_ext_2023-09-23.json' %}
}
],
"robot": {
diff --git a/y2023/control_loops/drivetrain/drivetrain_base.h b/y2023/control_loops/drivetrain/drivetrain_base.h
index 6404081..98f984e 100644
--- a/y2023/control_loops/drivetrain/drivetrain_base.h
+++ b/y2023/control_loops/drivetrain/drivetrain_base.h
@@ -7,8 +7,8 @@
namespace control_loops {
namespace drivetrain {
-const ::frc971::control_loops::drivetrain::DrivetrainConfig<double>
- &GetDrivetrainConfig();
+const ::frc971::control_loops::drivetrain::DrivetrainConfig<double> &
+GetDrivetrainConfig();
} // namespace drivetrain
} // namespace control_loops
diff --git a/y2023/control_loops/python/graph_paths.py b/y2023/control_loops/python/graph_paths.py
index eb92ec8..52db9d8 100644
--- a/y2023/control_loops/python/graph_paths.py
+++ b/y2023/control_loops/python/graph_paths.py
@@ -231,7 +231,7 @@
))
points['GroundPickupBackCube'] = to_theta_with_circular_index_and_roll(
- -1.102, 0.28, -np.pi / 2.0, circular_index=1)
+ -1.102, 0.30, -np.pi / 2.0, circular_index=1)
named_segments.append(
ThetaSplineSegment(
@@ -246,7 +246,7 @@
))
points['GroundPickupFrontCube'] = to_theta_with_circular_index_and_roll(
- 0.325603, 0.255189, np.pi / 2.0, circular_index=0)
+ 0.325603, 0.275189, np.pi / 2.0, circular_index=0)
named_segments.append(
ThetaSplineSegment(
@@ -261,7 +261,7 @@
))
points['ScoreBackMidConeUp'] = to_theta_with_circular_index_and_roll(
- -1.45013, 1.00354, np.pi / 2.0, circular_index=1)
+ -1.45013, 1.02354, np.pi / 2.0, circular_index=1)
named_segments.append(
ThetaSplineSegment(
@@ -333,7 +333,7 @@
))
points['HPPickupBackConeUp'] = to_theta_with_circular_index_and_roll(
- -1.1200539, 1.335, np.pi / 2.0, circular_index=0)
+ -1.1200539, 1.330, np.pi / 2.0, circular_index=0)
named_segments.append(
ThetaSplineSegment(
@@ -346,7 +346,7 @@
))
points['HPPickupFrontConeUp'] = np.array(
- (5.16514378449353, 1.25, -np.pi / 2.0))
+ (5.16514378449353, 1.2461538461538462, -np.pi / 2.0))
# to_theta_with_circular_index_and_roll(
# 0.265749, 1.28332, -np.pi / 2.0, circular_index=1)
@@ -476,7 +476,7 @@
))
points['ScoreBackLowCube'] = to_theta_with_circular_index_and_roll(
- -1.102, 0.3712121, -np.pi / 2.0, circular_index=1)
+ -1.102, 0.4012121, -np.pi / 2.0, circular_index=1)
named_segments.append(
ThetaSplineSegment(
@@ -489,7 +489,7 @@
))
points['ScoreBackMidCube'] = to_theta_with_circular_index_and_roll(
- -1.27896, 0.84, -np.pi / 2.0, circular_index=1)
+ -1.27896, 0.89, -np.pi / 2.0, circular_index=1)
named_segments.append(
ThetaSplineSegment(
@@ -515,7 +515,7 @@
#points['ScoreBackHighCube'] = to_theta_with_circular_index_and_roll(
# -1.60932, 1.16839, np.pi / 2.0, circular_index=0)
points['ScoreBackHighCube'] = np.array(
- (4.77284735761704, -1.19952193130714, -np.pi / 2.0))
+ (4.77284735761704, -1.130291162076371, -np.pi / 2.0))
named_segments.append(
ThetaSplineSegment(
@@ -538,7 +538,7 @@
))
points['GroundPickupFrontConeUp'] = to_theta_with_circular_index_and_roll(
- 0.313099, 0.380, -np.pi / 2.0, circular_index=0)
+ 0.313099, 0.39, -np.pi / 2.0, circular_index=0)
named_segments.append(
ThetaSplineSegment(
diff --git a/y2023/control_loops/superstructure/BUILD b/y2023/control_loops/superstructure/BUILD
index 861bbf8..3d35dae 100644
--- a/y2023/control_loops/superstructure/BUILD
+++ b/y2023/control_loops/superstructure/BUILD
@@ -106,6 +106,8 @@
"//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
"//frc971/control_loops/drivetrain:drivetrain_status_fbs",
"//frc971/shooter_interpolation:interpolation",
+ "//frc971/zeroing:absolute_encoder",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2023:constants",
"//y2023/constants:constants_fbs",
"//y2023/constants:simulated_constants_sender",
diff --git a/y2023/control_loops/superstructure/arm/BUILD b/y2023/control_loops/superstructure/arm/BUILD
index a742c50..768a54e 100644
--- a/y2023/control_loops/superstructure/arm/BUILD
+++ b/y2023/control_loops/superstructure/arm/BUILD
@@ -16,6 +16,7 @@
"//frc971/control_loops/double_jointed_arm:graph",
"//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
"//frc971/zeroing",
+ "//frc971/zeroing:pot_and_absolute_encoder",
"//y2023:constants",
"//y2023/control_loops/superstructure:superstructure_position_fbs",
"//y2023/control_loops/superstructure:superstructure_status_fbs",
diff --git a/y2023/control_loops/superstructure/arm/arm.h b/y2023/control_loops/superstructure/arm/arm.h
index 1f97d80..6153400 100644
--- a/y2023/control_loops/superstructure/arm/arm.h
+++ b/y2023/control_loops/superstructure/arm/arm.h
@@ -5,6 +5,7 @@
#include "frc971/control_loops/double_jointed_arm/dynamics.h"
#include "frc971/control_loops/double_jointed_arm/ekf.h"
#include "frc971/control_loops/double_jointed_arm/graph.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "frc971/zeroing/zeroing.h"
#include "y2023/constants.h"
#include "y2023/control_loops/superstructure/arm/generated_graph.h"
diff --git a/y2023/control_loops/superstructure/end_effector.cc b/y2023/control_loops/superstructure/end_effector.cc
index 8628359..43f3d24 100644
--- a/y2023/control_loops/superstructure/end_effector.cc
+++ b/y2023/control_loops/superstructure/end_effector.cc
@@ -36,6 +36,9 @@
state_ = EndEffectorState::LOADED;
break;
case EndEffectorState::LOADED:
+ // In case we thought we had a cube, force it to cone.
+ game_piece_ = vision::Class::CONE_UP;
+ break;
case EndEffectorState::SPITTING:
break;
}
diff --git a/y2023/control_loops/superstructure/superstructure.h b/y2023/control_loops/superstructure/superstructure.h
index fdfef4e..bcee3ea 100644
--- a/y2023/control_loops/superstructure/superstructure.h
+++ b/y2023/control_loops/superstructure/superstructure.h
@@ -7,6 +7,8 @@
#include "frc971/control_loops/control_loop.h"
#include "frc971/control_loops/drivetrain/drivetrain_can_position_generated.h"
#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
+#include "frc971/zeroing/absolute_encoder.h"
+#include "frc971/zeroing/pot_and_absolute_encoder.h"
#include "y2023/constants.h"
#include "y2023/constants/constants_generated.h"
#include "y2023/control_loops/superstructure/arm/arm.h"
diff --git a/y2023/control_loops/superstructure/superstructure_lib_test.cc b/y2023/control_loops/superstructure/superstructure_lib_test.cc
index 26b88f3..926846e 100644
--- a/y2023/control_loops/superstructure/superstructure_lib_test.cc
+++ b/y2023/control_loops/superstructure/superstructure_lib_test.cc
@@ -9,6 +9,7 @@
#include "frc971/control_loops/position_sensor_sim.h"
#include "frc971/control_loops/subsystem_simulator.h"
#include "frc971/control_loops/team_number_test_environment.h"
+#include "frc971/zeroing/absolute_encoder.h"
#include "y2023/constants/simulated_constants_sender.h"
#include "y2023/control_loops/drivetrain/drivetrain_dog_motor_plant.h"
#include "y2023/control_loops/superstructure/roll/integral_roll_plant.h"
diff --git a/y2023/control_loops/superstructure/superstructure_plotter.ts b/y2023/control_loops/superstructure/superstructure_plotter.ts
index 2e32445..c7d14fd 100644
--- a/y2023/control_loops/superstructure/superstructure_plotter.ts
+++ b/y2023/control_loops/superstructure/superstructure_plotter.ts
@@ -11,15 +11,15 @@
export function plotSuperstructure(conn: Connection, element: Element): void {
const aosPlotter = new AosPlotter(conn);
- const goal = aosPlotter.addMessageSource(
- '/superstructure', 'y2023.control_loops.superstructure.Goal');
- const output = aosPlotter.addMessageSource(
- '/superstructure', 'y2023.control_loops.superstructure.Output');
- const status = aosPlotter.addMessageSource(
- '/superstructure', 'y2023.control_loops.superstructure.Status');
+ //const goal = aosPlotter.addMessageSource(
+ // '/superstructure', 'y2023.control_loops.superstructure.Goal');
+ //const output = aosPlotter.addMessageSource(
+ // '/superstructure', 'y2023.control_loops.superstructure.Output');
+ //const status = aosPlotter.addMessageSource(
+ // '/superstructure', 'y2023.control_loops.superstructure.Status');
const position = aosPlotter.addMessageSource(
'/superstructure', 'y2023.control_loops.superstructure.Position');
- const robotState = aosPlotter.addMessageSource('/aos', 'aos.RobotState');
+ //const robotState = aosPlotter.addMessageSource('/aos', 'aos.RobotState');
const positionPlot =
aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
@@ -28,88 +28,13 @@
positionPlot.plot.getAxisLabels().setYLabel('wonky state units');
positionPlot.plot.setDefaultYRange([-1.0, 2.0]);
- positionPlot.addMessageLine(position, ['turret_beambreak'])
+ positionPlot.addMessageLine(position, ['arm', 'distal', 'pot'])
.setColor(RED)
.setPointSize(4.0);
- positionPlot.addMessageLine(status, ['state'])
- .setColor(PINK)
- .setPointSize(4.0);
- positionPlot.addMessageLine(status, ['flippers_open'])
- .setColor(WHITE)
- .setPointSize(1.0);
- positionPlot.addMessageLine(status, ['reseating_in_catapult'])
- .setColor(BLUE)
- .setPointSize(1.0);
- positionPlot.addMessageLine(status, ['fire'])
- .setColor(BROWN)
- .setPointSize(1.0);
- positionPlot.addMessageLine(status, ['ready_to_fire'])
- .setColor(GREEN)
- .setPointSize(1.0);
- positionPlot.addMessageLine(status, ['collided'])
- .setColor(PINK)
- .setPointSize(1.0);
-
- const goalPlot =
- aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
- goalPlot.plot.getAxisLabels().setTitle('Goal');
- goalPlot.plot.getAxisLabels().setXLabel(TIME);
- goalPlot.plot.getAxisLabels().setYLabel('value');
- goalPlot.plot.setDefaultYRange([-1.0, 2.0]);
- goalPlot.addMessageLine(goal, ['fire']).setColor(RED).setPointSize(1.0);
- goalPlot.addMessageLine(goal, ['auto_aim']).setColor(BLUE).setPointSize(1.0);
-
-
- const shotCountPlot =
- aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
- shotCountPlot.plot.getAxisLabels().setTitle('Shot Count');
- shotCountPlot.plot.getAxisLabels().setXLabel(TIME);
- shotCountPlot.plot.getAxisLabels().setYLabel('balls');
- shotCountPlot.plot.setDefaultYRange([-1.0, 2.0]);
- shotCountPlot.addMessageLine(status, ['shot_count'])
- .setColor(RED)
- .setPointSize(1.0);
-
- const intakePlot =
- aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
- intakePlot.plot.getAxisLabels().setTitle('Intake');
- intakePlot.plot.getAxisLabels().setXLabel(TIME);
- intakePlot.plot.getAxisLabels().setYLabel('wonky state units');
- intakePlot.plot.setDefaultYRange([-1.0, 2.0]);
- intakePlot.addMessageLine(status, ['intake_state'])
- .setColor(RED)
- .setPointSize(1.0);
- intakePlot.addMessageLine(position, ['intake_beambreak_front'])
- .setColor(GREEN)
- .setPointSize(4.0);
- intakePlot.addMessageLine(position, ['intake_beambreak_back'])
- .setColor(PINK)
- .setPointSize(1.0);
- intakePlot.addMessageLine(output, ['transfer_roller_voltage'])
- .setColor(BROWN)
- .setPointSize(3.0);
-
-
- const otherPlot =
- aosPlotter.addPlot(element, [DEFAULT_WIDTH, DEFAULT_HEIGHT / 2]);
- otherPlot.plot.getAxisLabels().setTitle('Position');
- otherPlot.plot.getAxisLabels().setXLabel(TIME);
- otherPlot.plot.getAxisLabels().setYLabel('rad');
- otherPlot.plot.setDefaultYRange([-1.0, 2.0]);
-
- otherPlot.addMessageLine(status, ['catapult', 'position'])
- .setColor(PINK)
- .setPointSize(4.0);
- otherPlot.addMessageLine(status, ['turret', 'position'])
- .setColor(WHITE)
- .setPointSize(4.0);
- otherPlot.addMessageLine(position, ['flipper_arm_left', 'encoder'])
+ positionPlot.addMessageLine(position, ['arm', 'distal', 'absolute_encoder'])
.setColor(BLUE)
.setPointSize(4.0);
- otherPlot.addMessageLine(position, ['flipper_arm_right', 'encoder'])
- .setColor(CYAN)
- .setPointSize(4.0);
- otherPlot.addMessageLine(output, ['flipper_arms_voltage'])
- .setColor(BROWN)
+ positionPlot.addMessageLine(position, ['arm', 'distal', 'encoder'])
+ .setColor(GREEN)
.setPointSize(4.0);
}
diff --git a/y2023/copy_logs.sh b/y2023/copy_logs.sh
new file mode 100755
index 0000000..4d5669c
--- /dev/null
+++ b/y2023/copy_logs.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# Helper script to copy most recent logs off of the pis
+
+set -e
+
+ROBOT_PREFIX="79" # ..71 (Should be one of 79, 89, 99, or 9)
+PI_LIST="2 3" # Should be some set of {1,2,3,4,5,6}
+
+LOG_FILE_PATH=/media/sda1/fbs_log-current
+if [[ -z $1 || ! -d $1 ]]; then
+ echo "Please specify the base directory to store the logs ('$1' not found)"
+ exit -1
+fi
+
+# Create output directory based on given directory + a timestamp
+OUTPUT_DIR=$1"/"`date +"%Y-%m-%dT%H-%M-%S"`
+mkdir ${OUTPUT_DIR}
+
+echo "Copying logs from the robot ${ROBOT_PREFIX}71 and pis ${PI_LIST}"
+echo "Storing logs in folder ${OUTPUT_DIR}"
+
+for pi in $PI_LIST; do
+ echo "========================================================"
+ echo "Copying logs from pi-${ROBOT_PREFIX}71-$pi"
+ echo "========================================================"
+ scp -r pi@10.${ROBOT_PREFIX}.71.10${pi}:${LOG_FILE_PATH} ${OUTPUT_DIR}/fbs_log-pi${pi}
+done
+
diff --git a/y2023/joystick_reader.cc b/y2023/joystick_reader.cc
index 874e691..f4d9ea6 100644
--- a/y2023/joystick_reader.cc
+++ b/y2023/joystick_reader.cc
@@ -186,7 +186,7 @@
},
{
.index = arm::ScoreBackMidConeUpIndex(),
- .wrist_goal = kConeWrist,
+ .wrist_goal = kConeWrist + 0.05,
.game_piece = GamePiece::CONE_UP,
.buttons = {{kMidConeScoreRight, SpotSelectionHint::RIGHT},
{kMidConeScoreLeft, SpotSelectionHint::LEFT}},
diff --git a/y2023/pi_send_joystick.sh b/y2023/pi_send_joystick.sh
new file mode 100755
index 0000000..9b60e02
--- /dev/null
+++ b/y2023/pi_send_joystick.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/sh
+
+# Helper script to spoof joystick state of robot enabled, to triggger image logging
+
+# Currently, this is going through pi6. Need to set the right IP address for the bot
+imu_pi6="pi@10.79.71.106"
+
+# TODO(milind): add logger in the future
+echo "Sending Joystick command '$1' to $imu_pi6"
+ssh ${imu_pi6} "bin/aos_send /imu/aos aos.JoystickState '{\"enabled\": $1}'"
+
+if [ $1 = "false" ]
+then
+ # This extra sleep is necessary to make sure the logs rotate to a new file
+ sleep 6
+ echo "Sending Joystick command '$1' to $imu_pi6"
+ ssh ${imu_pi6} "bin/aos_send /imu/aos aos.JoystickState '{\"enabled\": $1}'"
+fi
diff --git a/y2023/vision/calib_files/calibration_pi-971-1_cam-23-09_ext_2023-03-05.json b/y2023/vision/calib_files/calibration_pi-971-1_cam-23-09_ext_2023-03-05.json
index ad8ab23..051897b 100644
--- a/y2023/vision/calib_files/calibration_pi-971-1_cam-23-09_ext_2023-03-05.json
+++ b/y2023/vision/calib_files/calibration_pi-971-1_cam-23-09_ext_2023-03-05.json
@@ -1 +1 @@
-{ "node_name": "pi1", "team_number": 971, "intrinsics": [ 893.617798, 0.0, 612.44397, 0.0, 893.193115, 375.196381, 0.0, 0.0, 1.0 ], "fixed_extrinsics": { "data": [ -0.483961, 0.220781, 0.84678, 0.176109, 0.868846, 0.005849, 0.495048, -0.191149, 0.104344, 0.975306, -0.194656, 0.550508, 0.0, 0.0, 0.0, 1.0 ] }, "dist_coeffs": [ -0.443805, 0.238734, 0.000133, 0.000448, -0.071068 ], "calibration_timestamp": 1358499779650270322, "camera_id": "23-09" }
+{ "node_name": "pi1", "team_number": 971, "intrinsics": [ 893.617798, 0.0, 612.44397, 0.0, 893.193115, 375.196381, 0.0, 0.0, 1.0 ], "fixed_extrinsics": { "data": [ -0.483961, 0.220781, 0.84678, 0.176109, 0.868846, 0.005849, 0.495048, -0.231149, 0.104344, 0.975306, -0.194656, 0.550508, 0.0, 0.0, 0.0, 1.0 ] }, "dist_coeffs": [ -0.443805, 0.238734, 0.000133, 0.000448, -0.071068 ], "calibration_timestamp": 1358499779650270322, "camera_id": "23-09" }
diff --git a/y2023/vision/calib_files/calibration_pi-971-2_cam-23-10_ext_2023-09-23.json b/y2023/vision/calib_files/calibration_pi-971-2_cam-23-10_ext_2023-09-23.json
new file mode 100644
index 0000000..f353533
--- /dev/null
+++ b/y2023/vision/calib_files/calibration_pi-971-2_cam-23-10_ext_2023-09-23.json
@@ -0,0 +1 @@
+{ "node_name": "pi2", "team_number": 971, "intrinsics": [ 894.002502, 0.0, 636.431335, 0.0, 893.723816, 377.069672, 0.0, 0.0, 1.0 ], "fixed_extrinsics": { "data": [ 0.84372, 0.233067, 0.483545, 0.188786, 0.499721,-0.0121191, -0.866102, -0.244606, -0.196001, 0.972385, -0.126693, 0.600451, 0.0, 0.0, 0.0, 1.0 ] }, "dist_coeffs": [ -0.446659, 0.244189, 0.000632, 0.000171, -0.074849 ], "calibration_timestamp": 1358503360377380613, "camera_id": "23-10" }
diff --git a/y2023/vision/calib_files/calibration_pi-971-3_cam-23-11_ext_2023-09-23.json b/y2023/vision/calib_files/calibration_pi-971-3_cam-23-11_ext_2023-09-23.json
new file mode 100644
index 0000000..d7851fa
--- /dev/null
+++ b/y2023/vision/calib_files/calibration_pi-971-3_cam-23-11_ext_2023-09-23.json
@@ -0,0 +1 @@
+{ "node_name": "pi3", "team_number": 971, "intrinsics": [ 891.026001, 0.0, 620.086731, 0.0, 890.566895, 385.035126, 0.0, 0.0, 1.0 ], "fixed_extrinsics": { "data": [ 0.484157, -0.154776, -0.861182, -0.0935153, -0.872577, -0.0125032, -0.488317, -0.225918, 0.0648126, 0.987871, -0.141107, 0.623926, 0.0, 0.0, 0.0, 1.0 ] }, "dist_coeffs": [ -0.448299, 0.250123, -0.00042, -0.000127, -0.078433 ], "calibration_timestamp": 1358503290177115986, "camera_id": "23-11" }
diff --git a/y2023/vision/calib_files/calibration_pi-971-4_cam-23-12_ext_2023-09-23.json b/y2023/vision/calib_files/calibration_pi-971-4_cam-23-12_ext_2023-09-23.json
new file mode 100644
index 0000000..e12c22c
--- /dev/null
+++ b/y2023/vision/calib_files/calibration_pi-971-4_cam-23-12_ext_2023-09-23.json
@@ -0,0 +1 @@
+{ "node_name": "pi4", "team_number": 971, "intrinsics": [ 891.127197, 0.0, 640.291321, 0.0, 891.176453, 359.578705, 0.0, 0.0, 1.0 ], "fixed_extrinsics": { "data": [ -0.864114, -0.173035, -0.472616, -0.111428, -0.477471, -0.0150962, 0.878518, -0.22396, -0.159149, 0.9848, -0.0695749, 0.696406, 0.0, 0.0, 0.0, 1.0 ] }, "dist_coeffs": [ -0.452948, 0.262567, 0.00088, -0.000253, -0.089368 ], "calibration_timestamp": 1358499579812698894, "camera_id": "23-12" }
diff --git a/y2023_bot3/BUILD b/y2023_bot3/BUILD
new file mode 100644
index 0000000..6025e3f
--- /dev/null
+++ b/y2023_bot3/BUILD
@@ -0,0 +1,240 @@
+load("//frc971:downloader.bzl", "robot_downloader")
+load("//aos:config.bzl", "aos_config")
+load("//aos/util:config_validator_macro.bzl", "config_validator_test")
+
+config_validator_test(
+ name = "config_validator_test",
+ config = "//y2023_bot3:aos_config",
+)
+
+robot_downloader(
+ binaries = [
+ "//aos/network:web_proxy_main",
+ "//aos/events/logging:log_cat",
+ "//y2023_bot3/constants:constants_sender",
+ "//aos/events:aos_timing_report_streamer",
+ ],
+ data = [
+ ":aos_config",
+ "//aos/starter:roborio_irq_config.json",
+ "@ctre_phoenix6_api_cpp_athena//:shared_libraries",
+ "@ctre_phoenix6_tools_athena//:shared_libraries",
+ "@ctre_phoenix_api_cpp_athena//:shared_libraries",
+ "@ctre_phoenix_cci_athena//:shared_libraries",
+ ],
+ dirs = [
+ "//y2023_bot3/www:www_files",
+ "//y2023_bot3/autonomous:splines",
+ ],
+ start_binaries = [
+ "//aos/events/logging:logger_main",
+ "//aos/network:web_proxy_main",
+ "//aos/starter:irq_affinity",
+ "//y2023_bot3/autonomous:binaries",
+ ":joystick_reader",
+ ":wpilib_interface",
+ "//frc971/can_logger",
+ "//aos/network:message_bridge_client",
+ "//aos/network:message_bridge_server",
+ "//y2023_bot3/control_loops/drivetrain:drivetrain",
+ "//y2023_bot3/control_loops/drivetrain:trajectory_generator",
+ "//y2023_bot3/control_loops/superstructure:superstructure",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+)
+
+robot_downloader(
+ name = "pi_download",
+ binaries = [
+ "//aos/starter:irq_affinity",
+ "//aos/util:foxglove_websocket",
+ "//aos/events:aos_timing_report_streamer",
+ "//y2023_bot3/constants:constants_sender",
+ "//aos/network:web_proxy_main",
+ "//aos/events/logging:log_cat",
+ "//y2023_bot3/rockpi:imu_main",
+ "//frc971/image_streamer:image_streamer",
+ ],
+ data = [
+ ":aos_config",
+ "//frc971/rockpi:rockpi_config.json",
+ "//y2023_bot3/constants:constants.json",
+ "//y2023_bot3/www:www_files",
+ ],
+ dirs = [
+ "//y2023_bot3/www:www_files",
+ "//frc971/image_streamer/www:www_files",
+ ],
+ start_binaries = [
+ "//aos/network:message_bridge_client",
+ "//aos/network:message_bridge_server",
+ "//aos/network:web_proxy_main",
+ "//aos/starter:irq_affinity",
+ "//aos/events/logging:logger_main",
+ ],
+ target_compatible_with = ["//tools/platforms/hardware:raspberry_pi"],
+ target_type = "pi",
+)
+
+aos_config(
+ name = "aos_config",
+ src = "y2023_bot3.json",
+ flatbuffers = [
+ "//aos/network:message_bridge_client_fbs",
+ "//aos/network:message_bridge_server_fbs",
+ "//aos/network:timestamp_fbs",
+ "//frc971/input:robot_state_fbs",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":config_imu",
+ ":config_roborio",
+ ],
+)
+
+aos_config(
+ name = "config_imu",
+ src = "y2023_bot3_imu.json",
+ flatbuffers = [
+ "//aos/network:message_bridge_client_fbs",
+ "//aos/network:message_bridge_server_fbs",
+ "//y2023_bot3/constants:constants_fbs",
+ "//aos/network:timestamp_fbs",
+ "//aos/network:remote_message_fbs",
+ "//frc971/control_loops/drivetrain/localization:localizer_output_fbs",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//aos/events:aos_config",
+ "//frc971/control_loops/drivetrain:aos_config",
+ ],
+)
+
+aos_config(
+ name = "config_roborio",
+ src = "y2023_bot3_roborio.json",
+ flatbuffers = [
+ "//aos/network:remote_message_fbs",
+ "//aos/network:message_bridge_client_fbs",
+ "//aos/network:message_bridge_server_fbs",
+ "//y2023_bot3/constants:constants_fbs",
+ "//aos/network:timestamp_fbs",
+ "//y2019/control_loops/drivetrain:target_selector_fbs",
+ "//y2023_bot3/control_loops/superstructure:superstructure_goal_fbs",
+ "//y2023_bot3/control_loops/superstructure:superstructure_output_fbs",
+ "//y2023_bot3/control_loops/superstructure:superstructure_position_fbs",
+ "//y2023_bot3/control_loops/superstructure:superstructure_status_fbs",
+ "//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
+ "//frc971:can_configuration_fbs",
+ "//frc971/can_logger:can_logging_fbs",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ deps = [
+ "//aos/events:aos_config",
+ "//frc971/autonomous:aos_config",
+ "//frc971/control_loops/drivetrain:aos_config",
+ "//frc971/input:aos_config",
+ "//frc971/wpilib:aos_config",
+ ],
+)
+
+cc_library(
+ name = "constants",
+ srcs = [
+ "constants.cc",
+ ],
+ hdrs = [
+ "constants.h",
+ ],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//aos/mutex",
+ "//aos/network:team_number",
+ "//frc971:constants",
+ "//frc971/control_loops:pose",
+ "//frc971/control_loops:static_zeroing_single_dof_profiled_subsystem",
+ "//frc971/shooter_interpolation:interpolation",
+ "//y2023_bot3/control_loops/drivetrain:polydrivetrain_plants",
+ "@com_github_google_glog//:glog",
+ "@com_google_absl//absl/base",
+ ],
+)
+
+cc_binary(
+ name = "wpilib_interface",
+ srcs = [
+ "wpilib_interface.cc",
+ ],
+ target_compatible_with = ["//tools/platforms/hardware:roborio"],
+ deps = [
+ ":constants",
+ "//aos:init",
+ "//aos:math",
+ "//aos/containers:sized_array",
+ "//aos/events:shm_event_loop",
+ "//aos/logging",
+ "//aos/stl_mutex",
+ "//aos/time",
+ "//aos/util:log_interval",
+ "//aos/util:phased_loop",
+ "//aos/util:wrapping_counter",
+ "//frc971:can_configuration_fbs",
+ "//frc971/autonomous:auto_mode_fbs",
+ "//frc971/control_loops:control_loop",
+ "//frc971/control_loops:control_loops_fbs",
+ "//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
+ "//frc971/control_loops/drivetrain:drivetrain_position_fbs",
+ "//frc971/input:robot_state_fbs",
+ "//frc971/queues:gyro_fbs",
+ "//frc971/wpilib:ADIS16448",
+ "//frc971/wpilib:buffered_pcm",
+ "//frc971/wpilib:drivetrain_writer",
+ "//frc971/wpilib:encoder_and_potentiometer",
+ "//frc971/wpilib:interrupt_edge_counting",
+ "//frc971/wpilib:joystick_sender",
+ "//frc971/wpilib:logging_fbs",
+ "//frc971/wpilib:loop_output_handler",
+ "//frc971/wpilib:pdp_fetcher",
+ "//frc971/wpilib:sensor_reader",
+ "//frc971/wpilib:wpilib_interface",
+ "//frc971/wpilib:wpilib_robot_base",
+ "//third_party:phoenix",
+ "//third_party:phoenix6",
+ "//third_party:wpilib",
+ "//y2023_bot3/control_loops/superstructure:led_indicator_lib",
+ "//y2023_bot3/control_loops/superstructure:superstructure_output_fbs",
+ "//y2023_bot3/control_loops/superstructure:superstructure_position_fbs",
+ ],
+)
+
+cc_binary(
+ name = "joystick_reader",
+ srcs = [
+ ":joystick_reader.cc",
+ ],
+ deps = [
+ ":constants",
+ "//aos:init",
+ "//aos/actions:action_lib",
+ "//aos/logging",
+ "//frc971/autonomous:auto_fbs",
+ "//frc971/autonomous:base_autonomous_actor",
+ "//frc971/control_loops:profiled_subsystem_fbs",
+ "//frc971/input:action_joystick_input",
+ "//frc971/input:drivetrain_input",
+ "//frc971/input:joystick_input",
+ "//frc971/input:redundant_joystick_data",
+ "//y2023_bot3/control_loops/drivetrain:drivetrain_base",
+ "//y2023_bot3/control_loops/superstructure:superstructure_goal_fbs",
+ "//y2023_bot3/control_loops/superstructure:superstructure_status_fbs",
+ ],
+)
+
+py_library(
+ name = "python_init",
+ srcs = ["__init__.py"],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+)
diff --git a/y2023_bot3/__init__.py b/y2023_bot3/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/y2023_bot3/__init__.py
diff --git a/y2023_bot3/autonomous/BUILD b/y2023_bot3/autonomous/BUILD
new file mode 100644
index 0000000..940d591
--- /dev/null
+++ b/y2023_bot3/autonomous/BUILD
@@ -0,0 +1,74 @@
+load("//frc971/downloader:downloader.bzl", "aos_downloader_dir")
+
+filegroup(
+ name = "binaries.stripped",
+ srcs = [
+ ":autonomous_action.stripped",
+ ],
+ visibility = ["//visibility:public"],
+)
+
+filegroup(
+ name = "binaries",
+ srcs = [
+ ":autonomous_action",
+ ],
+ visibility = ["//visibility:public"],
+)
+
+filegroup(
+ name = "spline_jsons",
+ srcs = glob([
+ "splines/*.json",
+ ]),
+ visibility = ["//visibility:public"],
+)
+
+aos_downloader_dir(
+ name = "splines",
+ srcs = [
+ ":spline_jsons",
+ ],
+ dir = "splines",
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+)
+
+cc_library(
+ name = "autonomous_action_lib",
+ srcs = [
+ "auto_splines.cc",
+ "autonomous_actor.cc",
+ ],
+ hdrs = [
+ "auto_splines.h",
+ "autonomous_actor.h",
+ ],
+ deps = [
+ "//aos/events:event_loop",
+ "//aos/logging",
+ "//aos/util:phased_loop",
+ "//frc971/autonomous:base_autonomous_actor",
+ "//frc971/control_loops:control_loops_fbs",
+ "//frc971/control_loops:profiled_subsystem_fbs",
+ "//frc971/control_loops/drivetrain:drivetrain_config",
+ "//frc971/control_loops/drivetrain:localizer_fbs",
+ "//y2023_bot3:constants",
+ "//y2023_bot3/control_loops/drivetrain:drivetrain_base",
+ "//y2023_bot3/control_loops/superstructure:superstructure_goal_fbs",
+ "//y2023_bot3/control_loops/superstructure:superstructure_status_fbs",
+ ],
+)
+
+cc_binary(
+ name = "autonomous_action",
+ srcs = [
+ "autonomous_actor_main.cc",
+ ],
+ deps = [
+ ":autonomous_action_lib",
+ "//aos:init",
+ "//aos/events:shm_event_loop",
+ "//frc971/autonomous:auto_fbs",
+ ],
+)
diff --git a/y2023_bot3/autonomous/auto_splines.cc b/y2023_bot3/autonomous/auto_splines.cc
new file mode 100644
index 0000000..e2779c4
--- /dev/null
+++ b/y2023_bot3/autonomous/auto_splines.cc
@@ -0,0 +1,126 @@
+#include "y2023_bot3/autonomous/auto_splines.h"
+
+#include "aos/flatbuffer_merge.h"
+#include "frc971/control_loops/control_loops_generated.h"
+
+namespace y2023_bot3 {
+namespace autonomous {
+
+namespace {
+flatbuffers::Offset<frc971::MultiSpline> FixSpline(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ flatbuffers::Offset<frc971::MultiSpline> spline_offset,
+ aos::Alliance alliance) {
+ frc971::MultiSpline *spline =
+ GetMutableTemporaryPointer(*builder->fbb(), spline_offset);
+ flatbuffers::Vector<float> *spline_x = spline->mutable_spline_x();
+
+ // For 2023: The field is mirrored across the center line, and is not
+ // rotationally symmetric. As such, we only flip the X coordinates when
+ // changing side of the field.
+ if (alliance == aos::Alliance::kBlue) {
+ for (size_t ii = 0; ii < spline_x->size(); ++ii) {
+ spline_x->Mutate(ii, -spline_x->Get(ii));
+ }
+ }
+ return spline_offset;
+}
+} // namespace
+
+flatbuffers::Offset<frc971::MultiSpline> AutonomousSplines::BasicSSpline(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance) {
+ flatbuffers::Offset<frc971::Constraint> longitudinal_constraint_offset;
+ flatbuffers::Offset<frc971::Constraint> lateral_constraint_offset;
+ flatbuffers::Offset<frc971::Constraint> voltage_constraint_offset;
+
+ {
+ frc971::Constraint::Builder longitudinal_constraint_builder =
+ builder->MakeBuilder<frc971::Constraint>();
+ longitudinal_constraint_builder.add_constraint_type(
+ frc971::ConstraintType::LONGITUDINAL_ACCELERATION);
+ longitudinal_constraint_builder.add_value(1.0);
+ longitudinal_constraint_offset = longitudinal_constraint_builder.Finish();
+ }
+
+ {
+ frc971::Constraint::Builder lateral_constraint_builder =
+ builder->MakeBuilder<frc971::Constraint>();
+ lateral_constraint_builder.add_constraint_type(
+ frc971::ConstraintType::LATERAL_ACCELERATION);
+ lateral_constraint_builder.add_value(1.0);
+ lateral_constraint_offset = lateral_constraint_builder.Finish();
+ }
+
+ {
+ frc971::Constraint::Builder voltage_constraint_builder =
+ builder->MakeBuilder<frc971::Constraint>();
+ voltage_constraint_builder.add_constraint_type(
+ frc971::ConstraintType::VOLTAGE);
+ voltage_constraint_builder.add_value(6.0);
+ voltage_constraint_offset = voltage_constraint_builder.Finish();
+ }
+
+ flatbuffers::Offset<
+ flatbuffers::Vector<flatbuffers::Offset<frc971::Constraint>>>
+ constraints_offset =
+ builder->fbb()->CreateVector<flatbuffers::Offset<frc971::Constraint>>(
+ {longitudinal_constraint_offset, lateral_constraint_offset,
+ voltage_constraint_offset});
+
+ const float startx = 0.4;
+ const float starty = 3.4;
+ flatbuffers::Offset<flatbuffers::Vector<float>> spline_x_offset =
+ builder->fbb()->CreateVector<float>({0.0f + startx, 0.6f + startx,
+ 0.6f + startx, 0.4f + startx,
+ 0.4f + startx, 1.0f + startx});
+ flatbuffers::Offset<flatbuffers::Vector<float>> spline_y_offset =
+ builder->fbb()->CreateVector<float>({starty - 0.0f, starty - 0.0f,
+ starty - 0.3f, starty - 0.7f,
+ starty - 1.0f, starty - 1.0f});
+
+ frc971::MultiSpline::Builder multispline_builder =
+ builder->MakeBuilder<frc971::MultiSpline>();
+
+ multispline_builder.add_spline_count(1);
+ multispline_builder.add_constraints(constraints_offset);
+ multispline_builder.add_spline_x(spline_x_offset);
+ multispline_builder.add_spline_y(spline_y_offset);
+
+ return FixSpline(builder, multispline_builder.Finish(), alliance);
+}
+
+flatbuffers::Offset<frc971::MultiSpline> AutonomousSplines::TestSpline(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance) {
+ return FixSpline(
+ builder,
+ aos::CopyFlatBuffer<frc971::MultiSpline>(test_spline_, builder->fbb()),
+ alliance);
+}
+
+flatbuffers::Offset<frc971::MultiSpline> AutonomousSplines::StraightLine(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance) {
+ flatbuffers::Offset<flatbuffers::Vector<float>> spline_x_offset =
+ builder->fbb()->CreateVector<float>(
+ {-12.3, -11.9, -11.5, -11.1, -10.6, -10.0});
+ flatbuffers::Offset<flatbuffers::Vector<float>> spline_y_offset =
+ builder->fbb()->CreateVector<float>({1.25, 1.25, 1.25, 1.25, 1.25, 1.25});
+
+ frc971::MultiSpline::Builder multispline_builder =
+ builder->MakeBuilder<frc971::MultiSpline>();
+
+ multispline_builder.add_spline_count(1);
+ multispline_builder.add_spline_x(spline_x_offset);
+ multispline_builder.add_spline_y(spline_y_offset);
+
+ return FixSpline(builder, multispline_builder.Finish(), alliance);
+}
+
+} // namespace autonomous
+} // namespace y2023_bot3
diff --git a/y2023_bot3/autonomous/auto_splines.h b/y2023_bot3/autonomous/auto_splines.h
new file mode 100644
index 0000000..0c9d92f
--- /dev/null
+++ b/y2023_bot3/autonomous/auto_splines.h
@@ -0,0 +1,45 @@
+#ifndef Y2023_AUTONOMOUS_AUTO_SPLINES_H_
+#define Y2023_AUTONOMOUS_AUTO_SPLINES_H_
+
+#include "aos/events/event_loop.h"
+#include "aos/flatbuffer_merge.h"
+#include "frc971/control_loops/control_loops_generated.h"
+#include "frc971/control_loops/drivetrain/drivetrain_goal_generated.h"
+#include "frc971/input/joystick_state_generated.h"
+/*
+
+ The cooridinate system for the autonomous splines is the same as the spline
+ python generator and drivetrain spline systems.
+
+*/
+
+namespace y2023_bot3 {
+namespace autonomous {
+
+class AutonomousSplines {
+ public:
+ AutonomousSplines()
+ : test_spline_(aos::JsonFileToFlatbuffer<frc971::MultiSpline>(
+ "splines/test_spline.json")) {}
+ static flatbuffers::Offset<frc971::MultiSpline> BasicSSpline(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance);
+ static flatbuffers::Offset<frc971::MultiSpline> StraightLine(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance);
+
+ flatbuffers::Offset<frc971::MultiSpline> TestSpline(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance);
+
+ private:
+ aos::FlatbufferDetachedBuffer<frc971::MultiSpline> test_spline_;
+};
+
+} // namespace autonomous
+} // namespace y2023_bot3
+
+#endif // Y2023_AUTONOMOUS_AUTO_SPLINES_H_
diff --git a/y2023_bot3/autonomous/autonomous_actor.cc b/y2023_bot3/autonomous/autonomous_actor.cc
new file mode 100644
index 0000000..0aacbd1
--- /dev/null
+++ b/y2023_bot3/autonomous/autonomous_actor.cc
@@ -0,0 +1,198 @@
+#include "y2023_bot3/autonomous/autonomous_actor.h"
+
+#include <chrono>
+#include <cinttypes>
+#include <cmath>
+
+#include "aos/logging/logging.h"
+#include "aos/util/math.h"
+#include "frc971/control_loops/drivetrain/localizer_generated.h"
+#include "y2023_bot3/autonomous/auto_splines.h"
+#include "y2023_bot3/constants.h"
+#include "y2023_bot3/control_loops/drivetrain/drivetrain_base.h"
+
+DEFINE_bool(spline_auto, false, "Run simple test S-spline auto mode.");
+
+namespace y2023_bot3 {
+namespace autonomous {
+
+using ::frc971::ProfileParametersT;
+
+ProfileParametersT MakeProfileParameters(float max_velocity,
+ float max_acceleration) {
+ ProfileParametersT result;
+ result.max_velocity = max_velocity;
+ result.max_acceleration = max_acceleration;
+ return result;
+}
+
+using ::aos::monotonic_clock;
+using frc971::CreateProfileParameters;
+using ::frc971::ProfileParametersT;
+using frc971::control_loops::CreateStaticZeroingSingleDOFProfiledSubsystemGoal;
+using frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal;
+using frc971::control_loops::drivetrain::LocalizerControl;
+namespace chrono = ::std::chrono;
+
+AutonomousActor::AutonomousActor(::aos::EventLoop *event_loop)
+ : frc971::autonomous::BaseAutonomousActor(
+ event_loop, control_loops::drivetrain::GetDrivetrainConfig()),
+ localizer_control_sender_(
+ event_loop->MakeSender<
+ ::frc971::control_loops::drivetrain::LocalizerControl>(
+ "/drivetrain")),
+ joystick_state_fetcher_(
+ event_loop->MakeFetcher<aos::JoystickState>("/aos")),
+ robot_state_fetcher_(event_loop->MakeFetcher<aos::RobotState>("/aos")),
+ auto_splines_(),
+ superstructure_goal_sender_(
+ event_loop
+ ->MakeSender<::y2023_bot3::control_loops::superstructure::Goal>(
+ "/superstructure")),
+ superstructure_status_fetcher_(
+ event_loop->MakeFetcher<
+ ::y2023_bot3::control_loops::superstructure::Status>(
+ "/superstructure")) {
+ drivetrain_status_fetcher_.Fetch();
+ replan_timer_ = event_loop->AddTimer([this]() { Replan(); });
+
+ event_loop->OnRun([this, event_loop]() {
+ replan_timer_->Schedule(event_loop->monotonic_now());
+ button_poll_->Schedule(event_loop->monotonic_now(),
+ chrono::milliseconds(50));
+ });
+
+ // TODO(james): Really need to refactor this code since we keep using it.
+ button_poll_ = event_loop->AddTimer([this]() {
+ const aos::monotonic_clock::time_point now =
+ this->event_loop()->context().monotonic_event_time;
+ if (robot_state_fetcher_.Fetch()) {
+ if (robot_state_fetcher_->user_button()) {
+ user_indicated_safe_to_reset_ = true;
+ MaybeSendStartingPosition();
+ }
+ }
+ if (joystick_state_fetcher_.Fetch()) {
+ if (joystick_state_fetcher_->has_alliance() &&
+ (joystick_state_fetcher_->alliance() != alliance_)) {
+ alliance_ = joystick_state_fetcher_->alliance();
+ is_planned_ = false;
+ // Only kick the planning out by 2 seconds. If we end up enabled in
+ // that second, then we will kick it out further based on the code
+ // below.
+ replan_timer_->Schedule(now + std::chrono::seconds(2));
+ }
+ if (joystick_state_fetcher_->enabled()) {
+ if (!is_planned_) {
+ // Only replan once we've been disabled for 5 seconds.
+ replan_timer_->Schedule(now + std::chrono::seconds(5));
+ }
+ }
+ }
+ });
+}
+
+void AutonomousActor::Replan() {
+ if (!drivetrain_status_fetcher_.Fetch()) {
+ replan_timer_->Schedule(event_loop()->monotonic_now() + chrono::seconds(1));
+ AOS_LOG(INFO, "Drivetrain not up, replanning in 1 second");
+ return;
+ }
+
+ if (alliance_ == aos::Alliance::kInvalid) {
+ return;
+ }
+ sent_starting_position_ = false;
+ if (FLAGS_spline_auto) {
+ test_spline_ =
+ PlanSpline(std::bind(&AutonomousSplines::TestSpline, &auto_splines_,
+ std::placeholders::_1, alliance_),
+ SplineDirection::kForward);
+
+ starting_position_ = test_spline_->starting_position();
+ }
+ is_planned_ = true;
+
+ MaybeSendStartingPosition();
+}
+
+void AutonomousActor::MaybeSendStartingPosition() {
+ if (is_planned_ && user_indicated_safe_to_reset_ &&
+ !sent_starting_position_) {
+ CHECK(starting_position_);
+ SendStartingPosition(starting_position_.value());
+ }
+}
+
+void AutonomousActor::Reset() {
+ InitializeEncoders();
+ ResetDrivetrain();
+
+ joystick_state_fetcher_.Fetch();
+ CHECK(joystick_state_fetcher_.get() != nullptr)
+ << "Expect at least one JoystickState message before running auto...";
+ alliance_ = joystick_state_fetcher_->alliance();
+
+ preloaded_ = false;
+ SendSuperstructureGoal();
+}
+
+bool AutonomousActor::RunAction(
+ const ::frc971::autonomous::AutonomousActionParams *params) {
+ Reset();
+
+ AOS_LOG(INFO, "Params are %d\n", params->mode());
+
+ if (!user_indicated_safe_to_reset_) {
+ AOS_LOG(WARNING, "Didn't send starting position prior to starting auto.");
+ CHECK(starting_position_);
+ SendStartingPosition(starting_position_.value());
+ }
+ // Clear this so that we don't accidentally resend things as soon as we
+ // replan later.
+ user_indicated_safe_to_reset_ = false;
+ is_planned_ = false;
+ starting_position_.reset();
+
+ AOS_LOG(INFO, "Params are %d\n", params->mode());
+ if (alliance_ == aos::Alliance::kInvalid) {
+ AOS_LOG(INFO, "Aborting autonomous due to invalid alliance selection.");
+ return false;
+ }
+
+ return true;
+}
+
+void AutonomousActor::SendStartingPosition(const Eigen::Vector3d &start) {
+ // Set up the starting position for the blue alliance.
+
+ auto builder = localizer_control_sender_.MakeBuilder();
+
+ LocalizerControl::Builder localizer_control_builder =
+ builder.MakeBuilder<LocalizerControl>();
+ localizer_control_builder.add_x(start(0));
+ localizer_control_builder.add_y(start(1));
+ localizer_control_builder.add_theta(start(2));
+ localizer_control_builder.add_theta_uncertainty(0.00001);
+ AOS_LOG(INFO, "User button pressed, x: %f y: %f theta: %f", start(0),
+ start(1), start(2));
+ if (builder.Send(localizer_control_builder.Finish()) !=
+ aos::RawSender::Error::kOk) {
+ AOS_LOG(ERROR, "Failed to reset localizer.\n");
+ }
+}
+
+void AutonomousActor::SendSuperstructureGoal() {
+ auto builder = superstructure_goal_sender_.MakeBuilder();
+
+ control_loops::superstructure::Goal::Builder superstructure_builder =
+ builder.MakeBuilder<control_loops::superstructure::Goal>();
+
+ if (builder.Send(superstructure_builder.Finish()) !=
+ aos::RawSender::Error::kOk) {
+ AOS_LOG(ERROR, "Sending superstructure goal failed.\n");
+ }
+}
+
+} // namespace autonomous
+} // namespace y2023_bot3
diff --git a/y2023_bot3/autonomous/autonomous_actor.h b/y2023_bot3/autonomous/autonomous_actor.h
new file mode 100644
index 0000000..b7978c7
--- /dev/null
+++ b/y2023_bot3/autonomous/autonomous_actor.h
@@ -0,0 +1,64 @@
+#ifndef Y2023_AUTONOMOUS_AUTONOMOUS_ACTOR_H_
+#define Y2023_AUTONOMOUS_AUTONOMOUS_ACTOR_H_
+
+#include "aos/actions/actions.h"
+#include "aos/actions/actor.h"
+#include "frc971/autonomous/base_autonomous_actor.h"
+#include "frc971/control_loops/control_loops_generated.h"
+#include "frc971/control_loops/drivetrain/drivetrain_config.h"
+#include "frc971/control_loops/drivetrain/localizer_generated.h"
+#include "y2023_bot3/autonomous/auto_splines.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_goal_generated.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_status_generated.h"
+
+namespace y2023_bot3 {
+namespace autonomous {
+
+class AutonomousActor : public ::frc971::autonomous::BaseAutonomousActor {
+ public:
+ explicit AutonomousActor(::aos::EventLoop *event_loop);
+
+ bool RunAction(
+ const ::frc971::autonomous::AutonomousActionParams *params) override;
+
+ private:
+ void set_preloaded(bool preloaded) { preloaded_ = preloaded; }
+
+ void SendSuperstructureGoal();
+
+ void Reset();
+
+ void SendStartingPosition(const Eigen::Vector3d &start);
+ void MaybeSendStartingPosition();
+ void Replan();
+
+ aos::Sender<frc971::control_loops::drivetrain::LocalizerControl>
+ localizer_control_sender_;
+ aos::Fetcher<aos::JoystickState> joystick_state_fetcher_;
+ aos::Fetcher<aos::RobotState> robot_state_fetcher_;
+
+ aos::TimerHandler *replan_timer_;
+ aos::TimerHandler *button_poll_;
+
+ aos::Alliance alliance_ = aos::Alliance::kInvalid;
+ AutonomousSplines auto_splines_;
+ bool user_indicated_safe_to_reset_ = false;
+ bool sent_starting_position_ = false;
+
+ bool is_planned_ = false;
+
+ std::optional<Eigen::Vector3d> starting_position_;
+
+ bool preloaded_ = false;
+
+ aos::Sender<control_loops::superstructure::Goal> superstructure_goal_sender_;
+ aos::Fetcher<y2023_bot3::control_loops::superstructure::Status>
+ superstructure_status_fetcher_;
+
+ std::optional<SplineHandle> test_spline_;
+};
+
+} // namespace autonomous
+} // namespace y2023_bot3
+
+#endif // Y2023_AUTONOMOUS_AUTONOMOUS_ACTOR_H_
diff --git a/y2023_bot3/autonomous/autonomous_actor_main.cc b/y2023_bot3/autonomous/autonomous_actor_main.cc
new file mode 100644
index 0000000..3947359
--- /dev/null
+++ b/y2023_bot3/autonomous/autonomous_actor_main.cc
@@ -0,0 +1,19 @@
+#include <cstdio>
+
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "y2023_bot3/autonomous/autonomous_actor.h"
+
+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());
+ ::y2023_bot3::autonomous::AutonomousActor autonomous(&event_loop);
+
+ event_loop.Run();
+
+ return 0;
+}
diff --git a/y2023_bot3/autonomous/splines/README.md b/y2023_bot3/autonomous/splines/README.md
new file mode 100644
index 0000000..c655416
--- /dev/null
+++ b/y2023_bot3/autonomous/splines/README.md
@@ -0,0 +1,3 @@
+# Spline Descriptions
+This folder contains reference material for what each spline does
+
diff --git a/y2023_bot3/autonomous/splines/test_spline.json b/y2023_bot3/autonomous/splines/test_spline.json
new file mode 100644
index 0000000..733d516
--- /dev/null
+++ b/y2023_bot3/autonomous/splines/test_spline.json
@@ -0,0 +1 @@
+{"spline_count": 1, "spline_x": [0, 0.4, 0.4, 0.6, 0.6, 1.0], "spline_y": [0, 0, 0.05, 0.1, 0.15, 0.15], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 1}, {"constraint_type": "LATERAL_ACCELERATION", "value": 1}, {"constraint_type": "VOLTAGE", "value": 2}]}
diff --git a/y2023_bot3/constants.cc b/y2023_bot3/constants.cc
new file mode 100644
index 0000000..909d508
--- /dev/null
+++ b/y2023_bot3/constants.cc
@@ -0,0 +1,41 @@
+#include "y2023_bot3/constants.h"
+
+#include <cinttypes>
+#include <map>
+
+#if __has_feature(address_sanitizer)
+#include "sanitizer/lsan_interface.h"
+#endif
+
+#include "absl/base/call_once.h"
+#include "glog/logging.h"
+
+#include "aos/mutex/mutex.h"
+#include "aos/network/team_number.h"
+
+namespace y2023_bot3 {
+namespace constants {
+
+Values MakeValues(uint16_t team) {
+ LOG(INFO) << "creating a Constants for team: " << team;
+
+ Values r;
+ switch (team) {
+ // A set of constants for tests.
+ case 1:
+ break;
+
+ case kThirdRobotTeamNumber:
+ break;
+
+ default:
+ LOG(FATAL) << "unknown team: " << team;
+ }
+
+ return r;
+}
+
+Values MakeValues() { return MakeValues(aos::network::GetTeamNumber()); }
+
+} // namespace constants
+} // namespace y2023_bot3
diff --git a/y2023_bot3/constants.h b/y2023_bot3/constants.h
new file mode 100644
index 0000000..500b836
--- /dev/null
+++ b/y2023_bot3/constants.h
@@ -0,0 +1,73 @@
+#ifndef Y2023_CONSTANTS_H_
+#define Y2023_CONSTANTS_H_
+
+#include <array>
+#include <cmath>
+#include <cstdint>
+
+#include "frc971/constants.h"
+#include "frc971/control_loops/pose.h"
+#include "frc971/control_loops/static_zeroing_single_dof_profiled_subsystem.h"
+#include "y2023_bot3/control_loops/drivetrain/drivetrain_dog_motor_plant.h"
+
+namespace y2023_bot3 {
+namespace constants {
+
+constexpr uint16_t kThirdRobotTeamNumber = 8971;
+
+struct Values {
+ static const int kZeroingSampleSize = 200;
+
+ static const int kSuperstructureCANWriterPriority = 35;
+ static const int kDrivetrainWriterPriority = 35;
+ static const int kDrivetrainTxPriority = 36;
+ static const int kDrivetrainRxPriority = 36;
+
+ // TODO(max): Change these constants based on 3rd drivetrain CAD
+ static constexpr double kDrivetrainCyclesPerRevolution() { return 512.0; }
+ static constexpr double kDrivetrainEncoderCountsPerRevolution() {
+ return kDrivetrainCyclesPerRevolution() * 4;
+ }
+ static constexpr double kDrivetrainEncoderRatio() { return 1.0; }
+ static constexpr double kMaxDrivetrainEncoderPulsesPerSecond() {
+ return control_loops::drivetrain::kFreeSpeed / (2.0 * M_PI) *
+ control_loops::drivetrain::kHighOutputRatio /
+ constants::Values::kDrivetrainEncoderRatio() *
+ kDrivetrainEncoderCountsPerRevolution();
+ }
+
+ static constexpr double kDrivetrainSupplyCurrentLimit() { return 35.0; }
+ static constexpr double kDrivetrainStatorCurrentLimit() { return 60.0; }
+
+ // timeout to ensure code doesn't get stuck after releasing the "intake"
+ // button
+ static constexpr std::chrono::milliseconds kExtraIntakingTime() {
+ return std::chrono::milliseconds{100};
+ }
+
+ static double DrivetrainEncoderToMeters(int32_t in) {
+ return ((static_cast<double>(in) /
+ kDrivetrainEncoderCountsPerRevolution()) *
+ (2.0 * M_PI)) *
+ kDrivetrainEncoderRatio() * control_loops::drivetrain::kWheelRadius;
+ }
+
+ static double DrivetrainCANEncoderToMeters(double rotations) {
+ return (rotations * (2.0 * M_PI)) *
+ control_loops::drivetrain::kHighOutputRatio *
+ control_loops::drivetrain::kWheelRadius;
+ }
+};
+
+// Creates and returns a Values instance for the constants.
+// Should be called before realtime because this allocates memory.
+// Only the first call to either of these will be used.
+Values MakeValues(uint16_t team);
+
+// Calls MakeValues with aos::network::GetTeamNumber()
+Values MakeValues();
+
+} // namespace constants
+} // namespace y2023_bot3
+
+#endif // Y2023_CONSTANTS_H_
diff --git a/y2023_bot3/constants/8971.json b/y2023_bot3/constants/8971.json
new file mode 100644
index 0000000..aea0c6f
--- /dev/null
+++ b/y2023_bot3/constants/8971.json
@@ -0,0 +1,5 @@
+{
+ "robot": {
+ },
+ {% include 'y2023_bot3/constants/common.json' %}
+}
diff --git a/y2023_bot3/constants/BUILD b/y2023_bot3/constants/BUILD
new file mode 100644
index 0000000..40d77be
--- /dev/null
+++ b/y2023_bot3/constants/BUILD
@@ -0,0 +1,65 @@
+load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_cc_library")
+load("//tools/build_rules:template.bzl", "jinja2_template")
+
+cc_library(
+ name = "simulated_constants_sender",
+ srcs = ["simulated_constants_sender.cc"],
+ hdrs = ["simulated_constants_sender.h"],
+ data = [":test_constants.json"],
+ visibility = ["//y2023_bot3:__subpackages__"],
+ deps = [
+ ":constants_fbs",
+ ":constants_list_fbs",
+ "//aos/events:simulated_event_loop",
+ "//aos/testing:path",
+ "//frc971/constants:constants_sender_lib",
+ ],
+)
+
+jinja2_template(
+ name = "constants.json",
+ src = "constants.jinja2.json",
+ includes = [
+ "8971.json",
+ "common.json",
+ ],
+ parameters = {},
+ visibility = ["//visibility:public"],
+)
+
+jinja2_template(
+ name = "test_constants.json",
+ src = "test_constants.jinja2.json",
+ includes = glob(["test_data/*.json"]),
+ parameters = {},
+ visibility = ["//visibility:public"],
+)
+
+flatbuffer_cc_library(
+ name = "constants_fbs",
+ srcs = ["constants.fbs"],
+ gen_reflections = True,
+ visibility = ["//visibility:public"],
+)
+
+flatbuffer_cc_library(
+ name = "constants_list_fbs",
+ srcs = ["constants_list.fbs"],
+ gen_reflections = True,
+ visibility = ["//visibility:public"],
+ deps = [":constants_fbs"],
+)
+
+cc_binary(
+ name = "constants_sender",
+ srcs = ["constants_sender.cc"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":constants_fbs",
+ ":constants_list_fbs",
+ "//aos:init",
+ "//aos/events:shm_event_loop",
+ "//aos/testing:path",
+ "//frc971/constants:constants_sender_lib",
+ ],
+)
diff --git a/y2023_bot3/constants/common.json b/y2023_bot3/constants/common.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/y2023_bot3/constants/common.json
@@ -0,0 +1 @@
+{}
diff --git a/y2023_bot3/constants/constants.fbs b/y2023_bot3/constants/constants.fbs
new file mode 100644
index 0000000..08f03be
--- /dev/null
+++ b/y2023_bot3/constants/constants.fbs
@@ -0,0 +1,10 @@
+namespace y2023_bot3;
+
+table RobotConstants {
+}
+
+table Constants {
+ robot:RobotConstants (id: 0);
+}
+
+root_type Constants;
diff --git a/y2023_bot3/constants/constants.jinja2.json b/y2023_bot3/constants/constants.jinja2.json
new file mode 100644
index 0000000..be1ea14
--- /dev/null
+++ b/y2023_bot3/constants/constants.jinja2.json
@@ -0,0 +1,8 @@
+{
+ "constants": [
+ {
+ "team": 8971,
+ "data": {% include 'y2023_bot3/constants/8971.json' %}
+ },
+ ]
+}
diff --git a/y2023_bot3/constants/constants_list.fbs b/y2023_bot3/constants/constants_list.fbs
new file mode 100644
index 0000000..8b132e8
--- /dev/null
+++ b/y2023_bot3/constants/constants_list.fbs
@@ -0,0 +1,14 @@
+include "y2023_bot3/constants/constants.fbs";
+
+namespace y2023_bot3;
+
+table TeamAndConstants {
+ team:long (id: 0);
+ data:Constants (id: 1);
+}
+
+table ConstantsList {
+ constants:[TeamAndConstants] (id: 0);
+}
+
+root_type ConstantsList;
diff --git a/y2023_bot3/constants/constants_sender.cc b/y2023_bot3/constants/constants_sender.cc
new file mode 100644
index 0000000..d6e5c28
--- /dev/null
+++ b/y2023_bot3/constants/constants_sender.cc
@@ -0,0 +1,25 @@
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+
+#include "aos/configuration.h"
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "aos/json_to_flatbuffer.h"
+#include "frc971/constants/constants_sender_lib.h"
+#include "y2023_bot3/constants/constants_generated.h"
+#include "y2023_bot3/constants/constants_list_generated.h"
+
+DEFINE_string(config, "aos_config.json", "Path to the AOS config.");
+DEFINE_string(constants_path, "constants.json", "Path to the constant file");
+
+int main(int argc, char **argv) {
+ aos::InitGoogle(&argc, &argv);
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig(FLAGS_config);
+ aos::ShmEventLoop event_loop(&config.message());
+ frc971::constants::ConstantSender<y2023_bot3::Constants,
+ y2023_bot3::ConstantsList>
+ constants_sender(&event_loop, FLAGS_constants_path);
+ // Don't need to call Run().
+ return 0;
+}
diff --git a/y2023_bot3/constants/simulated_constants_sender.cc b/y2023_bot3/constants/simulated_constants_sender.cc
new file mode 100644
index 0000000..36c1891
--- /dev/null
+++ b/y2023_bot3/constants/simulated_constants_sender.cc
@@ -0,0 +1,18 @@
+#include "aos/events/simulated_event_loop.h"
+#include "aos/testing/path.h"
+#include "frc971/constants/constants_sender_lib.h"
+#include "y2023_bot3/constants/constants_generated.h"
+#include "y2023_bot3/constants/constants_list_generated.h"
+
+namespace y2023_bot3 {
+bool SendSimulationConstants(aos::SimulatedEventLoopFactory *factory, int team,
+ std::string constants_path) {
+ for (const aos::Node *node : factory->nodes()) {
+ std::unique_ptr<aos::EventLoop> event_loop =
+ factory->MakeEventLoop("constants_sender", node);
+ frc971::constants::ConstantSender<Constants, ConstantsList> sender(
+ event_loop.get(), constants_path, team, "/constants");
+ }
+ return true;
+}
+} // namespace y2023_bot3
diff --git a/y2023_bot3/constants/simulated_constants_sender.h b/y2023_bot3/constants/simulated_constants_sender.h
new file mode 100644
index 0000000..3f1495f
--- /dev/null
+++ b/y2023_bot3/constants/simulated_constants_sender.h
@@ -0,0 +1,16 @@
+#ifndef Y2023_CONSTANTS_SIMULATED_CONFIG_SENDER_H_
+#define Y2023_CONSTANTS_SIMULATED_CONFIG_SENDER_H_
+
+#include "aos/events/simulated_event_loop.h"
+#include "aos/testing/path.h"
+
+namespace y2023_bot3 {
+// Returns true, to allow this to be easily called in the initializer list of a
+// constructor.
+bool SendSimulationConstants(
+ aos::SimulatedEventLoopFactory *factory, int team,
+ std::string constants_path =
+ aos::testing::ArtifactPath("y2023_bot3/constants/test_constants.json"));
+} // namespace y2023_bot3
+
+#endif // Y2023_CONSTANTS_SIMULATED_CONFIG_SENDER_H_
diff --git a/y2023_bot3/constants/test_constants.jinja2.json b/y2023_bot3/constants/test_constants.jinja2.json
new file mode 100644
index 0000000..f05194b
--- /dev/null
+++ b/y2023_bot3/constants/test_constants.jinja2.json
@@ -0,0 +1,8 @@
+{
+ "constants": [
+ {
+ "team": 7971,
+ "data": {% include 'y2023_bot3/constants/test_data/test_team.json' %}
+ }
+ ]
+}
diff --git a/y2023_bot3/constants/test_data/scoring_map.json b/y2023_bot3/constants/test_data/scoring_map.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/y2023_bot3/constants/test_data/scoring_map.json
@@ -0,0 +1 @@
+{}
diff --git a/y2023_bot3/constants/test_data/test_team.json b/y2023_bot3/constants/test_data/test_team.json
new file mode 100644
index 0000000..97bab66
--- /dev/null
+++ b/y2023_bot3/constants/test_data/test_team.json
@@ -0,0 +1,3 @@
+{
+ "robot": {}
+}
diff --git a/y2023_bot3/control_loops/BUILD b/y2023_bot3/control_loops/BUILD
new file mode 100644
index 0000000..77007e7
--- /dev/null
+++ b/y2023_bot3/control_loops/BUILD
@@ -0,0 +1,7 @@
+py_library(
+ name = "python_init",
+ srcs = ["__init__.py"],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = ["//y2023_bot3:python_init"],
+)
diff --git a/y2023_bot3/control_loops/__init__.py b/y2023_bot3/control_loops/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/y2023_bot3/control_loops/__init__.py
diff --git a/y2023_bot3/control_loops/drivetrain/BUILD b/y2023_bot3/control_loops/drivetrain/BUILD
new file mode 100644
index 0000000..46654ec
--- /dev/null
+++ b/y2023_bot3/control_loops/drivetrain/BUILD
@@ -0,0 +1,102 @@
+genrule(
+ name = "genrule_drivetrain",
+ outs = [
+ "drivetrain_dog_motor_plant.h",
+ "drivetrain_dog_motor_plant.cc",
+ "kalman_drivetrain_motor_plant.h",
+ "kalman_drivetrain_motor_plant.cc",
+ ],
+ cmd = "$(location //y2023_bot3/control_loops/python:drivetrain) $(OUTS)",
+ target_compatible_with = ["@platforms//os:linux"],
+ tools = [
+ "//y2023_bot3/control_loops/python:drivetrain",
+ ],
+)
+
+genrule(
+ name = "genrule_polydrivetrain",
+ outs = [
+ "polydrivetrain_dog_motor_plant.h",
+ "polydrivetrain_dog_motor_plant.cc",
+ "polydrivetrain_cim_plant.h",
+ "polydrivetrain_cim_plant.cc",
+ "hybrid_velocity_drivetrain.h",
+ "hybrid_velocity_drivetrain.cc",
+ ],
+ cmd = "$(location //y2023_bot3/control_loops/python:polydrivetrain) $(OUTS)",
+ target_compatible_with = ["@platforms//os:linux"],
+ tools = [
+ "//y2023_bot3/control_loops/python:polydrivetrain",
+ ],
+)
+
+cc_library(
+ name = "polydrivetrain_plants",
+ srcs = [
+ "drivetrain_dog_motor_plant.cc",
+ "hybrid_velocity_drivetrain.cc",
+ "kalman_drivetrain_motor_plant.cc",
+ "polydrivetrain_dog_motor_plant.cc",
+ ],
+ hdrs = [
+ "drivetrain_dog_motor_plant.h",
+ "hybrid_velocity_drivetrain.h",
+ "kalman_drivetrain_motor_plant.h",
+ "polydrivetrain_dog_motor_plant.h",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//frc971/control_loops:hybrid_state_feedback_loop",
+ "//frc971/control_loops:state_feedback_loop",
+ ],
+)
+
+cc_library(
+ name = "drivetrain_base",
+ srcs = [
+ "drivetrain_base.cc",
+ ],
+ hdrs = [
+ "drivetrain_base.h",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":polydrivetrain_plants",
+ "//frc971:shifter_hall_effect",
+ "//frc971/control_loops/drivetrain:drivetrain_config",
+ ],
+)
+
+cc_binary(
+ name = "drivetrain",
+ srcs = [
+ "drivetrain_main.cc",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":drivetrain_base",
+ "//aos:init",
+ "//aos/events:shm_event_loop",
+ "//frc971/control_loops/drivetrain:drivetrain_lib",
+ "//frc971/control_loops/drivetrain/localization:puppet_localizer",
+ "//y2023_bot3/constants:constants_sender",
+ ],
+)
+
+cc_binary(
+ name = "trajectory_generator",
+ srcs = [
+ "trajectory_generator_main.cc",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":drivetrain_base",
+ "//aos:init",
+ "//aos/events:shm_event_loop",
+ "//frc971/control_loops/drivetrain:trajectory_generator",
+ ],
+)
diff --git a/y2023_bot3/control_loops/drivetrain/drivetrain_base.cc b/y2023_bot3/control_loops/drivetrain/drivetrain_base.cc
new file mode 100644
index 0000000..5b30097
--- /dev/null
+++ b/y2023_bot3/control_loops/drivetrain/drivetrain_base.cc
@@ -0,0 +1,90 @@
+#include "y2023_bot3/control_loops/drivetrain/drivetrain_base.h"
+
+#include <chrono>
+
+#include "frc971/control_loops/drivetrain/drivetrain_config.h"
+#include "frc971/control_loops/state_feedback_loop.h"
+#include "y2023_bot3/control_loops/drivetrain/drivetrain_dog_motor_plant.h"
+#include "y2023_bot3/control_loops/drivetrain/hybrid_velocity_drivetrain.h"
+#include "y2023_bot3/control_loops/drivetrain/kalman_drivetrain_motor_plant.h"
+#include "y2023_bot3/control_loops/drivetrain/polydrivetrain_dog_motor_plant.h"
+
+using ::frc971::control_loops::drivetrain::DownEstimatorConfig;
+using ::frc971::control_loops::drivetrain::DrivetrainConfig;
+using ::frc971::control_loops::drivetrain::LineFollowConfig;
+
+namespace chrono = ::std::chrono;
+
+namespace y2023_bot3 {
+namespace control_loops {
+namespace drivetrain {
+
+using ::frc971::constants::ShifterHallEffect;
+
+const ShifterHallEffect kThreeStateDriveShifter{0.0, 0.0, 0.25, 0.75};
+
+const DrivetrainConfig<double> &GetDrivetrainConfig() {
+ // Yaw of the IMU relative to the robot frame.
+ static constexpr double kImuYaw = 0.0;
+ static DrivetrainConfig<double> kDrivetrainConfig{
+ ::frc971::control_loops::drivetrain::ShifterType::SIMPLE_SHIFTER,
+ ::frc971::control_loops::drivetrain::LoopType::CLOSED_LOOP,
+ ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
+ ::frc971::control_loops::drivetrain::IMUType::IMU_FLIPPED_X,
+
+ drivetrain::MakeDrivetrainLoop,
+ drivetrain::MakeVelocityDrivetrainLoop,
+ drivetrain::MakeKFDrivetrainLoop,
+ drivetrain::MakeHybridVelocityDrivetrainLoop,
+
+ chrono::duration_cast<chrono::nanoseconds>(
+ chrono::duration<double>(drivetrain::kDt)),
+ drivetrain::kRobotRadius,
+ drivetrain::kWheelRadius,
+ drivetrain::kV,
+
+ drivetrain::kHighGearRatio,
+ drivetrain::kLowGearRatio,
+ drivetrain::kJ,
+ drivetrain::kMass,
+ kThreeStateDriveShifter,
+ kThreeStateDriveShifter,
+ true /* default_high_gear */,
+ 0 /* down_offset if using constants use
+ constants::GetValues().down_error */
+ ,
+ 0.7 /* wheel_non_linearity */,
+ 1.2 /* quickturn_wheel_multiplier */,
+ 1.2 /* wheel_multiplier */,
+ true /*pistol_grip_shift_enables_line_follow*/,
+ (Eigen::Matrix<double, 3, 3>() << std::cos(kImuYaw), -std::sin(kImuYaw),
+ 0.0, std::sin(kImuYaw), std::cos(kImuYaw), 0.0, 0.0, 0.0, 1.0)
+ .finished(),
+ false /*is_simulated*/,
+ DownEstimatorConfig{.gravity_threshold = 0.015,
+ .do_accel_corrections = 1000},
+ LineFollowConfig{
+ .Q = Eigen::Matrix3d((::Eigen::DiagonalMatrix<double, 3>().diagonal()
+ << 1.0 / ::std::pow(0.1, 2),
+ 1.0 / ::std::pow(1.0, 2),
+ 1.0 / ::std::pow(1.0, 2))
+ .finished()
+ .asDiagonal()),
+ .R = Eigen::Matrix2d((::Eigen::DiagonalMatrix<double, 2>().diagonal()
+ << 10.0 / ::std::pow(12.0, 2),
+ 10.0 / ::std::pow(12.0, 2))
+ .finished()
+ .asDiagonal()),
+ .max_controllable_offset = 0.5},
+ frc971::control_loops::drivetrain::PistolTopButtonUse::kNone,
+ frc971::control_loops::drivetrain::PistolSecondButtonUse::kTurn1,
+ frc971::control_loops::drivetrain::PistolBottomButtonUse::
+ kControlLoopDriving,
+ };
+
+ return kDrivetrainConfig;
+};
+
+} // namespace drivetrain
+} // namespace control_loops
+} // namespace y2023_bot3
diff --git a/y2023_bot3/control_loops/drivetrain/drivetrain_base.h b/y2023_bot3/control_loops/drivetrain/drivetrain_base.h
new file mode 100644
index 0000000..6922ea6
--- /dev/null
+++ b/y2023_bot3/control_loops/drivetrain/drivetrain_base.h
@@ -0,0 +1,17 @@
+#ifndef Y2023_CONTROL_LOOPS_DRIVETRAIN_DRIVETRAIN_BASE_H_
+#define Y2023_CONTROL_LOOPS_DRIVETRAIN_DRIVETRAIN_BASE_H_
+
+#include "frc971/control_loops/drivetrain/drivetrain_config.h"
+
+namespace y2023_bot3 {
+namespace control_loops {
+namespace drivetrain {
+
+const ::frc971::control_loops::drivetrain::DrivetrainConfig<double> &
+GetDrivetrainConfig();
+
+} // namespace drivetrain
+} // namespace control_loops
+} // namespace y2023_bot3
+
+#endif // Y2023_CONTROL_LOOPS_DRIVETRAIN_DRIVETRAIN_BASE_H_
diff --git a/y2023_bot3/control_loops/drivetrain/drivetrain_main.cc b/y2023_bot3/control_loops/drivetrain/drivetrain_main.cc
new file mode 100644
index 0000000..55c51aa
--- /dev/null
+++ b/y2023_bot3/control_loops/drivetrain/drivetrain_main.cc
@@ -0,0 +1,35 @@
+#include <memory>
+
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "frc971/constants/constants_sender_lib.h"
+#include "frc971/control_loops/drivetrain/drivetrain.h"
+#include "frc971/control_loops/drivetrain/localization/puppet_localizer.h"
+#include "y2023_bot3/constants/constants_generated.h"
+#include "y2023_bot3/control_loops/drivetrain/drivetrain_base.h"
+
+using ::frc971::control_loops::drivetrain::DrivetrainLoop;
+
+int main(int argc, char **argv) {
+ aos::InitGoogle(&argc, &argv);
+
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig("aos_config.json");
+
+ frc971::constants::WaitForConstants<y2023_bot3::Constants>(&config.message());
+
+ aos::ShmEventLoop event_loop(&config.message());
+ std::unique_ptr<::frc971::control_loops::drivetrain::PuppetLocalizer>
+ localizer = std::make_unique<
+ ::frc971::control_loops::drivetrain::PuppetLocalizer>(
+ &event_loop,
+ ::y2023_bot3::control_loops::drivetrain::GetDrivetrainConfig());
+ ;
+ std::unique_ptr<DrivetrainLoop> drivetrain = std::make_unique<DrivetrainLoop>(
+ y2023_bot3::control_loops::drivetrain::GetDrivetrainConfig(), &event_loop,
+ localizer.get());
+
+ event_loop.Run();
+
+ return 0;
+}
diff --git a/y2023_bot3/control_loops/drivetrain/trajectory_generator_main.cc b/y2023_bot3/control_loops/drivetrain/trajectory_generator_main.cc
new file mode 100644
index 0000000..7d6d5f2
--- /dev/null
+++ b/y2023_bot3/control_loops/drivetrain/trajectory_generator_main.cc
@@ -0,0 +1,40 @@
+#include <sys/resource.h>
+#include <sys/time.h>
+
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "frc971/control_loops/drivetrain/trajectory_generator.h"
+#include "y2023_bot3/control_loops/drivetrain/drivetrain_base.h"
+
+using ::frc971::control_loops::drivetrain::TrajectoryGenerator;
+
+DEFINE_bool(skip_renicing, false,
+ "If true, skip renicing the trajectory generator.");
+
+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());
+ TrajectoryGenerator generator(
+ &event_loop,
+ ::y2023_bot3::control_loops::drivetrain::GetDrivetrainConfig());
+
+ event_loop.OnRun([]() {
+ if (FLAGS_skip_renicing) {
+ LOG(WARNING) << "Ignoring request to renice to -20 due to "
+ "--skip_renicing.";
+ } else {
+ errno = 0;
+ setpriority(PRIO_PROCESS, 0, -20);
+ PCHECK(errno == 0)
+ << ": Renicing to -20 failed, use --skip_renicing to skip renicing.";
+ }
+ });
+
+ event_loop.Run();
+
+ return 0;
+}
diff --git a/y2023_bot3/control_loops/python/BUILD b/y2023_bot3/control_loops/python/BUILD
new file mode 100644
index 0000000..fe7666f
--- /dev/null
+++ b/y2023_bot3/control_loops/python/BUILD
@@ -0,0 +1,57 @@
+package(default_visibility = ["//y2023_bot3:__subpackages__"])
+
+py_binary(
+ name = "drivetrain",
+ srcs = [
+ "drivetrain.py",
+ ],
+ legacy_create_init = False,
+ target_compatible_with = ["@platforms//cpu:x86_64"],
+ deps = [
+ ":python_init",
+ "//frc971/control_loops/python:drivetrain",
+ "@pip//glog",
+ "@pip//python_gflags",
+ ],
+)
+
+py_binary(
+ name = "polydrivetrain",
+ srcs = [
+ "drivetrain.py",
+ "polydrivetrain.py",
+ ],
+ legacy_create_init = False,
+ target_compatible_with = ["@platforms//cpu:x86_64"],
+ deps = [
+ ":python_init",
+ "//frc971/control_loops/python:polydrivetrain",
+ "@pip//glog",
+ "@pip//python_gflags",
+ ],
+)
+
+py_library(
+ name = "polydrivetrain_lib",
+ srcs = [
+ "drivetrain.py",
+ "polydrivetrain.py",
+ ],
+ target_compatible_with = ["@platforms//cpu:x86_64"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//frc971/control_loops/python:controls",
+ "//frc971/control_loops/python:drivetrain",
+ "//frc971/control_loops/python:polydrivetrain",
+ "@pip//glog",
+ "@pip//python_gflags",
+ ],
+)
+
+py_library(
+ name = "python_init",
+ srcs = ["__init__.py"],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = ["//y2023_bot3/control_loops:python_init"],
+)
diff --git a/y2023_bot3/control_loops/python/__init__.py b/y2023_bot3/control_loops/python/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/y2023_bot3/control_loops/python/__init__.py
diff --git a/y2023_bot3/control_loops/python/drivetrain.py b/y2023_bot3/control_loops/python/drivetrain.py
new file mode 100644
index 0000000..26cb043
--- /dev/null
+++ b/y2023_bot3/control_loops/python/drivetrain.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+
+from __future__ import print_function
+from frc971.control_loops.python import drivetrain
+from frc971.control_loops.python import control_loop
+import sys
+
+import gflags
+import glog
+
+FLAGS = gflags.FLAGS
+
+gflags.DEFINE_bool('plot', False, 'If true, plot the loop response.')
+
+# TODO(max): Change constants based on robot / CAD
+kDrivetrain = drivetrain.DrivetrainParams(
+ J=2.2,
+ mass=44.7,
+ # TODO(austin): Measure radius a bit better.
+ robot_radius=0.25,
+ wheel_radius=2.5 * 0.0254,
+ motor_type=control_loop.Falcon(),
+ num_motors=2,
+ G=(14.0 / 68.0) * (30.0 / 54.0),
+ q_pos=0.24,
+ q_vel=2.5,
+ efficiency=0.92,
+ has_imu=False,
+ force=True,
+ kf_q_voltage=1.0,
+ controller_poles=[0.82, 0.82])
+
+
+def main(argv):
+ argv = FLAGS(argv)
+ glog.init()
+
+ if FLAGS.plot:
+ drivetrain.PlotDrivetrainMotions(kDrivetrain)
+ elif len(argv) != 5:
+ print("Expected .h file name and .cc file name")
+ else:
+ # Write the generated constants out to a file.
+ drivetrain.WriteDrivetrain(argv[1:3], argv[3:5], 'y2023_bot3',
+ kDrivetrain)
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/y2023_bot3/control_loops/python/polydrivetrain.py b/y2023_bot3/control_loops/python/polydrivetrain.py
new file mode 100644
index 0000000..80e4f13
--- /dev/null
+++ b/y2023_bot3/control_loops/python/polydrivetrain.py
@@ -0,0 +1,34 @@
+#!/usr/bin/python3
+
+import sys
+from y2023_bot3.control_loops.python import drivetrain
+from frc971.control_loops.python import polydrivetrain
+
+import gflags
+import glog
+
+__author__ = 'Austin Schuh (austin.linux@gmail.com)'
+
+FLAGS = gflags.FLAGS
+
+try:
+ gflags.DEFINE_bool('plot', False, 'If true, plot the loop response.')
+except gflags.DuplicateFlagError:
+ pass
+
+
+def main(argv):
+ if FLAGS.plot:
+ polydrivetrain.PlotPolyDrivetrainMotions(drivetrain.kDrivetrain)
+ elif len(argv) != 7:
+ glog.fatal('Expected .h file name and .cc file name')
+ else:
+ polydrivetrain.WritePolyDrivetrain(argv[1:3], argv[3:5], argv[5:7],
+ 'y2023_bot3',
+ drivetrain.kDrivetrain)
+
+
+if __name__ == '__main__':
+ argv = FLAGS(sys.argv)
+ glog.init()
+ sys.exit(main(argv))
diff --git a/y2023_bot3/control_loops/superstructure/BUILD b/y2023_bot3/control_loops/superstructure/BUILD
new file mode 100644
index 0000000..0330182
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/BUILD
@@ -0,0 +1,190 @@
+load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_cc_library")
+load("@com_github_google_flatbuffers//:typescript.bzl", "flatbuffer_ts_library")
+
+package(default_visibility = ["//visibility:public"])
+
+flatbuffer_cc_library(
+ name = "superstructure_goal_fbs",
+ srcs = [
+ "superstructure_goal.fbs",
+ ],
+ gen_reflections = 1,
+ deps = [
+ "//frc971/control_loops:control_loops_fbs",
+ "//frc971/control_loops:profiled_subsystem_fbs",
+ ],
+)
+
+flatbuffer_cc_library(
+ name = "superstructure_output_fbs",
+ srcs = [
+ "superstructure_output.fbs",
+ ],
+ gen_reflections = 1,
+)
+
+flatbuffer_cc_library(
+ name = "superstructure_status_fbs",
+ srcs = [
+ "superstructure_status.fbs",
+ ],
+ gen_reflections = 1,
+ deps = [
+ "//frc971/control_loops:control_loops_fbs",
+ "//frc971/control_loops:profiled_subsystem_fbs",
+ ],
+)
+
+flatbuffer_ts_library(
+ name = "superstructure_status_ts_fbs",
+ srcs = [
+ "superstructure_status.fbs",
+ ],
+ deps = [
+ "//frc971/control_loops:control_loops_ts_fbs",
+ "//frc971/control_loops:profiled_subsystem_ts_fbs",
+ ],
+)
+
+flatbuffer_cc_library(
+ name = "superstructure_position_fbs",
+ srcs = [
+ "superstructure_position.fbs",
+ ],
+ gen_reflections = 1,
+ deps = [
+ "//frc971:can_configuration_fbs",
+ "//frc971/control_loops:can_falcon_fbs",
+ "//frc971/control_loops:control_loops_fbs",
+ "//frc971/control_loops:profiled_subsystem_fbs",
+ ],
+)
+
+cc_library(
+ name = "end_effector",
+ srcs = [
+ "end_effector.cc",
+ ],
+ hdrs = [
+ "end_effector.h",
+ ],
+ deps = [
+ ":superstructure_goal_fbs",
+ ":superstructure_status_fbs",
+ "//aos/events:event_loop",
+ "//aos/time",
+ "//frc971/control_loops:control_loop",
+ "//y2023_bot3:constants",
+ ],
+)
+
+cc_library(
+ name = "superstructure_lib",
+ srcs = [
+ "superstructure.cc",
+ ],
+ hdrs = [
+ "superstructure.h",
+ ],
+ data = [
+ ],
+ deps = [
+ ":end_effector",
+ ":superstructure_goal_fbs",
+ ":superstructure_output_fbs",
+ ":superstructure_position_fbs",
+ ":superstructure_status_fbs",
+ "//aos:flatbuffer_merge",
+ "//aos/events:event_loop",
+ "//frc971/constants:constants_sender_lib",
+ "//frc971/control_loops:control_loop",
+ "//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
+ "//frc971/control_loops/drivetrain:drivetrain_status_fbs",
+ "//frc971/shooter_interpolation:interpolation",
+ "//y2023_bot3:constants",
+ "//y2023_bot3/constants:constants_fbs",
+ "//y2023_bot3/constants:simulated_constants_sender",
+ ],
+)
+
+cc_binary(
+ name = "superstructure",
+ srcs = [
+ "superstructure_main.cc",
+ ],
+ deps = [
+ ":superstructure_lib",
+ "//aos:init",
+ "//aos/events:shm_event_loop",
+ ],
+)
+
+cc_test(
+ name = "superstructure_lib_test",
+ srcs = [
+ "superstructure_lib_test.cc",
+ ],
+ data = [
+ "//y2023_bot3:aos_config",
+ ],
+ deps = [
+ ":superstructure_goal_fbs",
+ ":superstructure_lib",
+ ":superstructure_output_fbs",
+ ":superstructure_position_fbs",
+ ":superstructure_status_fbs",
+ "//aos:json_to_flatbuffer",
+ "//aos:math",
+ "//aos/events/logging:log_writer",
+ "//aos/testing:googletest",
+ "//aos/time",
+ "//frc971/control_loops:capped_test_plant",
+ "//frc971/control_loops:control_loop_test",
+ "//frc971/control_loops:position_sensor_sim",
+ "//frc971/control_loops:subsystem_simulator",
+ "//frc971/control_loops:team_number_test_environment",
+ "//frc971/control_loops/drivetrain:drivetrain_status_fbs",
+ ],
+)
+
+cc_library(
+ name = "led_indicator_lib",
+ srcs = ["led_indicator.cc"],
+ hdrs = ["led_indicator.h"],
+ data = [
+ "@ctre_phoenix_api_cpp_athena//:shared_libraries",
+ "@ctre_phoenix_cci_athena//:shared_libraries",
+ ],
+ target_compatible_with = ["//tools/platforms/hardware:roborio"],
+ deps = [
+ ":superstructure_goal_fbs",
+ ":superstructure_output_fbs",
+ ":superstructure_position_fbs",
+ ":superstructure_status_fbs",
+ "//aos/events:event_loop",
+ "//aos/network:message_bridge_client_fbs",
+ "//aos/network:message_bridge_server_fbs",
+ "//frc971/control_loops:control_loop",
+ "//frc971/control_loops:control_loops_fbs",
+ "//frc971/control_loops:profiled_subsystem_fbs",
+ "//frc971/control_loops/drivetrain:drivetrain_output_fbs",
+ "//frc971/control_loops/drivetrain:drivetrain_status_fbs",
+ "//frc971/control_loops/drivetrain/localization:localizer_output_fbs",
+ "//frc971/queues:gyro_fbs",
+ "//third_party:phoenix",
+ "//third_party:wpilib",
+ ],
+)
+
+cc_binary(
+ name = "superstructure_replay",
+ srcs = ["superstructure_replay.cc"],
+ deps = [
+ ":superstructure_lib",
+ "//aos:configuration",
+ "//aos:init",
+ "//aos/events:simulated_event_loop",
+ "//aos/events/logging:log_reader",
+ "//aos/network:team_number",
+ ],
+)
diff --git a/y2023_bot3/control_loops/superstructure/end_effector.cc b/y2023_bot3/control_loops/superstructure/end_effector.cc
new file mode 100644
index 0000000..a98d06f
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/end_effector.cc
@@ -0,0 +1,88 @@
+#include "y2023_bot3/control_loops/superstructure/end_effector.h"
+
+#include "aos/events/event_loop.h"
+#include "aos/time/time.h"
+#include "frc971/control_loops/control_loop.h"
+
+namespace y2023_bot3 {
+namespace control_loops {
+namespace superstructure {
+
+using ::aos::monotonic_clock;
+
+EndEffector::EndEffector()
+ : state_(EndEffectorState::IDLE), timer_(aos::monotonic_clock::min_time) {}
+
+void EndEffector::RunIteration(
+ const ::aos::monotonic_clock::time_point timestamp, RollerGoal roller_goal,
+ bool beambreak_status, double *roller_voltage, bool preloaded_with_cube) {
+ *roller_voltage = 0.0;
+
+ if (roller_goal == RollerGoal::SPIT) {
+ state_ = EndEffectorState::SPITTING;
+ }
+
+ if (roller_goal == RollerGoal::SPIT_MID) {
+ state_ = EndEffectorState::SPITTING_MID;
+ }
+
+ // If we started off preloaded, skip to the loaded state.
+ // Make sure we weren't already there just in case.
+ if (preloaded_with_cube) {
+ switch (state_) {
+ case EndEffectorState::IDLE:
+ case EndEffectorState::INTAKING:
+ state_ = EndEffectorState::LOADED;
+ break;
+ case EndEffectorState::LOADED:
+ break;
+ case EndEffectorState::SPITTING:
+ break;
+ case EndEffectorState::SPITTING_MID:
+ break;
+ }
+ }
+
+ switch (state_) {
+ case EndEffectorState::IDLE:
+ // If idle and intake requested, intake
+ if (roller_goal == RollerGoal::INTAKE_CUBE) {
+ state_ = EndEffectorState::INTAKING;
+ timer_ = timestamp;
+ }
+ break;
+ case EndEffectorState::INTAKING:
+ // If intaking and beam break is not triggered, keep intaking
+ if (roller_goal == RollerGoal::INTAKE_CUBE) {
+ timer_ = timestamp;
+ }
+
+ if (beambreak_status) {
+ // Beam has been broken, switch to loaded.
+ state_ = EndEffectorState::LOADED;
+ break;
+ } else if (timestamp > timer_ + constants::Values::kExtraIntakingTime()) {
+ // Intaking failed, waited 1 second with no beambreak
+ state_ = EndEffectorState::IDLE;
+ break;
+ }
+
+ *roller_voltage = kRollerCubeSuckVoltage();
+
+ break;
+ case EndEffectorState::LOADED:
+ timer_ = timestamp;
+ break;
+ case EndEffectorState::SPITTING:
+ *roller_voltage = kRollerCubeSpitVoltage();
+ break;
+ case EndEffectorState::SPITTING_MID:
+ *roller_voltage = kRollerCubeSpitMidVoltage();
+ }
+}
+
+void EndEffector::Reset() { state_ = EndEffectorState::IDLE; }
+
+} // namespace superstructure
+} // namespace control_loops
+} // namespace y2023_bot3
\ No newline at end of file
diff --git a/y2023_bot3/control_loops/superstructure/end_effector.h b/y2023_bot3/control_loops/superstructure/end_effector.h
new file mode 100644
index 0000000..ab4e117
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/end_effector.h
@@ -0,0 +1,39 @@
+#ifndef Y2023_BOT3_CONTROL_LOOPS_SUPERSTRUCTURE_END_EFFECTOR_H_
+#define Y2023_BOT3_CONTROL_LOOPS_SUPERSTRUCTURE_END_EFFECTOR_H_
+
+#include "aos/events/event_loop.h"
+#include "aos/time/time.h"
+#include "frc971/control_loops/control_loop.h"
+#include "y2023_bot3/constants.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_goal_generated.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_status_generated.h"
+
+namespace y2023_bot3 {
+namespace control_loops {
+namespace superstructure {
+
+class EndEffector {
+ public:
+ static constexpr double kRollerCubeSuckVoltage() { return -7.0; }
+ static constexpr double kRollerCubeSpitVoltage() { return 3.0; }
+ static constexpr double kRollerCubeSpitMidVoltage() { return 5.0; }
+
+ EndEffector();
+ void RunIteration(const ::aos::monotonic_clock::time_point timestamp,
+ RollerGoal roller_goal, bool beambreak_status,
+ double *intake_roller_voltage, bool preloaded_with_cube);
+ EndEffectorState state() const { return state_; }
+ void Reset();
+
+ private:
+ EndEffectorState state_;
+
+ // variable which records the last time at which "intake" button was pressed
+ aos::monotonic_clock::time_point timer_;
+};
+
+} // namespace superstructure
+} // namespace control_loops
+} // namespace y2023_bot3
+
+#endif // Y2023_CONTROL_LOOPS_SUPERSTRUCTURE_END_EFFECTOR_H_
diff --git a/y2023_bot3/control_loops/superstructure/led_indicator.cc b/y2023_bot3/control_loops/superstructure/led_indicator.cc
new file mode 100644
index 0000000..f0a9838
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/led_indicator.cc
@@ -0,0 +1,142 @@
+#include "y2023_bot3/control_loops/superstructure/led_indicator.h"
+
+namespace led = ctre::phoenix::led;
+namespace chrono = std::chrono;
+
+namespace y2023_bot3::control_loops::superstructure {
+
+LedIndicator::LedIndicator(aos::EventLoop *event_loop)
+ : event_loop_(event_loop),
+ drivetrain_output_fetcher_(
+ event_loop_->MakeFetcher<frc971::control_loops::drivetrain::Output>(
+ "/drivetrain")),
+ superstructure_status_fetcher_(
+ event_loop_->MakeFetcher<Status>("/superstructure")),
+ superstructure_position_fetcher_(
+ event_loop_->MakeFetcher<Position>("/superstructure")),
+ superstructure_goal_fetcher_(
+ event_loop_->MakeFetcher<Goal>("/superstructure")),
+ server_statistics_fetcher_(
+ event_loop_->MakeFetcher<aos::message_bridge::ServerStatistics>(
+ "/roborio/aos")),
+ client_statistics_fetcher_(
+ event_loop_->MakeFetcher<aos::message_bridge::ClientStatistics>(
+ "/roborio/aos")),
+ localizer_output_fetcher_(
+ event_loop_->MakeFetcher<frc971::controls::LocalizerOutput>(
+ "/localizer")),
+ gyro_reading_fetcher_(
+ event_loop_->MakeFetcher<frc971::sensors::GyroReading>(
+ "/drivetrain")),
+ drivetrain_status_fetcher_(
+ event_loop_->MakeFetcher<frc971::control_loops::drivetrain::Status>(
+ "/drivetrain")) {
+ led::CANdleConfiguration config;
+ config.statusLedOffWhenActive = true;
+ config.disableWhenLOS = false;
+ config.brightnessScalar = 1.0;
+ candle_.ConfigAllSettings(config, 0);
+
+ event_loop_->AddPhasedLoop([this](int) { DecideColor(); },
+ chrono::milliseconds(20));
+ event_loop_->OnRun(
+ [this]() { startup_time_ = event_loop_->monotonic_now(); });
+}
+
+// This method will be called once per scheduler run
+void LedIndicator::DisplayLed(uint8_t r, uint8_t g, uint8_t b) {
+ candle_.SetLEDs(static_cast<int>(r), static_cast<int>(g),
+ static_cast<int>(b));
+}
+
+bool DisconnectedIMUPiServer(
+ const aos::message_bridge::ServerStatistics &server_statistics) {
+ for (const auto *node_status : *server_statistics.connections()) {
+ if (node_status->state() == aos::message_bridge::State::DISCONNECTED) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool DisconnectedIMUPiClient(
+ const aos::message_bridge::ClientStatistics &client_statistics) {
+ for (const auto *node_status : *client_statistics.connections()) {
+ if (node_status->state() == aos::message_bridge::State::DISCONNECTED) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool PisDisconnected(
+ const frc971::controls::LocalizerOutput &localizer_output) {
+ if (!localizer_output.all_pis_connected()) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void LedIndicator::DecideColor() {
+ superstructure_status_fetcher_.Fetch();
+ superstructure_position_fetcher_.Fetch();
+ server_statistics_fetcher_.Fetch();
+ drivetrain_output_fetcher_.Fetch();
+ drivetrain_status_fetcher_.Fetch();
+ client_statistics_fetcher_.Fetch();
+ superstructure_goal_fetcher_.Fetch();
+ gyro_reading_fetcher_.Fetch();
+ localizer_output_fetcher_.Fetch();
+
+ // Estopped
+ if (superstructure_status_fetcher_.get() &&
+ superstructure_status_fetcher_->estopped()) {
+ DisplayLed(255, 0, 0);
+ return;
+ }
+
+ // Not zeroed
+ if (superstructure_status_fetcher_.get() &&
+ !superstructure_status_fetcher_->zeroed()) {
+ DisplayLed(255, 255, 0);
+ return;
+ }
+
+ // If the imu gyro readings are not being sent/updated recently. Only do this
+ // after we've been on for a bit.
+ if (event_loop_->context().monotonic_event_time >
+ startup_time_ + chrono::seconds(5) &&
+ (!gyro_reading_fetcher_.get() ||
+ gyro_reading_fetcher_.context().monotonic_event_time +
+ frc971::controls::kLoopFrequency * 10 <
+ event_loop_->monotonic_now())) {
+ if (flash_counter_.Flash()) {
+ DisplayLed(255, 0, 0);
+ } else {
+ DisplayLed(255, 255, 255);
+ }
+ return;
+ }
+
+ if (localizer_output_fetcher_.get() == nullptr ||
+ server_statistics_fetcher_.get() == nullptr ||
+ client_statistics_fetcher_.get() == nullptr ||
+ PisDisconnected(*localizer_output_fetcher_) ||
+ DisconnectedIMUPiServer(*server_statistics_fetcher_) ||
+ DisconnectedIMUPiClient(*client_statistics_fetcher_)) {
+ if (flash_counter_.Flash()) {
+ DisplayLed(255, 0, 0);
+ } else {
+ DisplayLed(0, 255, 0);
+ }
+
+ return;
+ }
+
+ DisplayLed(0, 0, 0);
+}
+
+} // namespace y2023_bot3::control_loops::superstructure
diff --git a/y2023_bot3/control_loops/superstructure/led_indicator.h b/y2023_bot3/control_loops/superstructure/led_indicator.h
new file mode 100644
index 0000000..d878bfe
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/led_indicator.h
@@ -0,0 +1,80 @@
+#ifndef Y2023_CONTROL_LOOPS_SUPERSTRUCTURE_LED_INDICATOR_H_
+#define Y2023_CONTROL_LOOPS_SUPERSTRUCTURE_LED_INDICATOR_H_
+
+#include "ctre/phoenix/led/CANdle.h"
+
+#include "aos/events/event_loop.h"
+#include "aos/network/message_bridge_client_generated.h"
+#include "aos/network/message_bridge_server_generated.h"
+#include "frc971/control_loops/control_loop.h"
+#include "frc971/control_loops/control_loops_generated.h"
+#include "frc971/control_loops/drivetrain/drivetrain_output_generated.h"
+#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
+#include "frc971/control_loops/drivetrain/localization/localizer_output_generated.h"
+#include "frc971/control_loops/profiled_subsystem_generated.h"
+#include "frc971/queues/gyro_generated.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_goal_generated.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_output_generated.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_position_generated.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_status_generated.h"
+
+namespace y2023_bot3::control_loops::superstructure {
+
+class FlashCounter {
+ public:
+ FlashCounter(size_t flash_iterations) : flash_iterations_(flash_iterations) {}
+
+ bool Flash() {
+ if (counter_ % flash_iterations_ == 0) {
+ flash_ = !flash_;
+ }
+ counter_++;
+ return flash_;
+ }
+
+ private:
+ size_t flash_iterations_;
+ size_t counter_ = 0;
+ bool flash_ = false;
+};
+
+class LedIndicator {
+ public:
+ LedIndicator(aos::EventLoop *event_loop);
+
+ void DecideColor();
+
+ private:
+ static constexpr size_t kFlashIterations = 5;
+
+ void DisplayLed(uint8_t r, uint8_t g, uint8_t b);
+
+ ctre::phoenix::led::CANdle candle_{8, "rio"};
+
+ aos::EventLoop *event_loop_;
+ aos::Fetcher<frc971::control_loops::drivetrain::Output>
+ drivetrain_output_fetcher_;
+ aos::Fetcher<Status> superstructure_status_fetcher_;
+ aos::Fetcher<Position> superstructure_position_fetcher_;
+ aos::Fetcher<Goal> superstructure_goal_fetcher_;
+ aos::Fetcher<aos::message_bridge::ServerStatistics>
+ server_statistics_fetcher_;
+ aos::Fetcher<aos::message_bridge::ClientStatistics>
+ client_statistics_fetcher_;
+ aos::Fetcher<frc971::controls::LocalizerOutput> localizer_output_fetcher_;
+ aos::Fetcher<frc971::sensors::GyroReading> gyro_reading_fetcher_;
+ aos::Fetcher<frc971::control_loops::drivetrain::Status>
+ drivetrain_status_fetcher_;
+
+ aos::monotonic_clock::time_point last_accepted_time_ =
+ aos::monotonic_clock::min_time;
+
+ aos::monotonic_clock::time_point startup_time_ =
+ aos::monotonic_clock::min_time;
+
+ FlashCounter flash_counter_{kFlashIterations};
+};
+
+} // namespace y2023_bot3::control_loops::superstructure
+
+#endif // Y2023_CONTROL_LOOPS_SUPERSTRUCTURE_LED_INDICATOR_H_
diff --git a/y2023_bot3/control_loops/superstructure/superstructure.cc b/y2023_bot3/control_loops/superstructure/superstructure.cc
new file mode 100644
index 0000000..e9df534
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/superstructure.cc
@@ -0,0 +1,61 @@
+#include "y2023_bot3/control_loops/superstructure/superstructure.h"
+
+#include "aos/events/event_loop.h"
+#include "aos/flatbuffer_merge.h"
+#include "aos/network/team_number.h"
+#include "frc971/shooter_interpolation/interpolation.h"
+#include "frc971/zeroing/wrap.h"
+
+DEFINE_bool(ignore_distance, false,
+ "If true, ignore distance when shooting and obay joystick_reader");
+
+namespace y2023_bot3 {
+namespace control_loops {
+namespace superstructure {
+
+using ::aos::monotonic_clock;
+
+using frc971::control_loops::AbsoluteEncoderProfiledJointStatus;
+using frc971::control_loops::PotAndAbsoluteEncoderProfiledJointStatus;
+using frc971::control_loops::RelativeEncoderProfiledJointStatus;
+
+Superstructure::Superstructure(::aos::EventLoop *event_loop,
+ std::shared_ptr<const constants::Values> values,
+ const ::std::string &name)
+ : frc971::controls::ControlLoop<Goal, Position, Status, Output>(event_loop,
+ name),
+ values_(values),
+ constants_fetcher_(event_loop) {
+ event_loop->SetRuntimeRealtimePriority(30);
+}
+
+void Superstructure::RunIteration(const Goal *unsafe_goal,
+ const Position *position,
+ aos::Sender<Output>::Builder *output,
+ aos::Sender<Status>::Builder *status) {
+ (void)unsafe_goal;
+ (void)position;
+
+ const monotonic_clock::time_point timestamp =
+ event_loop()->context().monotonic_event_time;
+ (void)timestamp;
+
+ if (WasReset()) {
+ AOS_LOG(ERROR, "WPILib reset, restarting\n");
+ }
+
+ OutputT output_struct;
+
+ if (output) {
+ output->CheckOk(output->Send(Output::Pack(*output->fbb(), &output_struct)));
+ }
+
+ Status::Builder status_builder = status->MakeBuilder<Status>();
+ status_builder.add_zeroed(true);
+
+ (void)status->Send(status_builder.Finish());
+}
+
+} // namespace superstructure
+} // namespace control_loops
+} // namespace y2023_bot3
diff --git a/y2023_bot3/control_loops/superstructure/superstructure.h b/y2023_bot3/control_loops/superstructure/superstructure.h
new file mode 100644
index 0000000..4b3d488
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/superstructure.h
@@ -0,0 +1,56 @@
+#ifndef Y2023_CONTROL_LOOPS_SUPERSTRUCTURE_SUPERSTRUCTURE_H_
+#define Y2023_CONTROL_LOOPS_SUPERSTRUCTURE_SUPERSTRUCTURE_H_
+
+#include "aos/events/event_loop.h"
+#include "aos/json_to_flatbuffer.h"
+#include "frc971/constants/constants_sender_lib.h"
+#include "frc971/control_loops/control_loop.h"
+#include "frc971/control_loops/drivetrain/drivetrain_can_position_generated.h"
+#include "frc971/control_loops/drivetrain/drivetrain_status_generated.h"
+#include "y2023_bot3/constants.h"
+#include "y2023_bot3/constants/constants_generated.h"
+#include "y2023_bot3/control_loops/superstructure/end_effector.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_goal_generated.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_output_generated.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_position_generated.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_status_generated.h"
+
+namespace y2023_bot3 {
+namespace control_loops {
+namespace superstructure {
+
+class Superstructure
+ : public ::frc971::controls::ControlLoop<Goal, Position, Status, Output> {
+ public:
+ explicit Superstructure(::aos::EventLoop *event_loop,
+ std::shared_ptr<const constants::Values> values,
+ const ::std::string &name = "/superstructure");
+
+ double robot_velocity() const;
+
+ inline const EndEffector &end_effector() const { return end_effector_; }
+
+ protected:
+ virtual void RunIteration(const Goal *unsafe_goal, const Position *position,
+ aos::Sender<Output>::Builder *output,
+ aos::Sender<Status>::Builder *status) override;
+
+ private:
+ // Returns the Y coordinate of a game piece given the time-of-flight reading.
+ std::optional<double> LateralOffsetForTimeOfFlight(double reading);
+
+ std::shared_ptr<const constants::Values> values_;
+ frc971::constants::ConstantsFetcher<Constants> constants_fetcher_;
+
+ EndEffector end_effector_;
+
+ aos::Alliance alliance_ = aos::Alliance::kInvalid;
+
+ DISALLOW_COPY_AND_ASSIGN(Superstructure);
+};
+
+} // namespace superstructure
+} // namespace control_loops
+} // namespace y2023_bot3
+
+#endif // Y2023_CONTROL_LOOPS_SUPERSTRUCTURE_SUPERSTRUCTURE_H_
diff --git a/y2023_bot3/control_loops/superstructure/superstructure_goal.fbs b/y2023_bot3/control_loops/superstructure/superstructure_goal.fbs
new file mode 100644
index 0000000..5659e1f
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/superstructure_goal.fbs
@@ -0,0 +1,28 @@
+include "frc971/control_loops/profiled_subsystem.fbs";
+
+namespace y2023_bot3.control_loops.superstructure;
+
+enum PivotGoal: ubyte {
+ PICKUP_FRONT = 0,
+ PICKUP_BACK = 1,
+ SCORE_LOW_FRONT = 2,
+ SCORE_LOW_BACK = 3,
+ SCORE_MID_FRONT = 4,
+ SCORE_MID_BACK = 5,
+}
+
+enum RollerGoal: ubyte {
+ IDLE = 0,
+ INTAKE_CUBE = 1,
+ SPIT = 2,
+ SPIT_MID = 3,
+}
+
+table Goal {
+ pivot_goal:PivotGoal (id: 0);
+ roller_goal:RollerGoal (id: 1);
+ preloaded_with_cube:bool (id: 2);
+}
+
+
+root_type Goal;
diff --git a/y2023_bot3/control_loops/superstructure/superstructure_lib_test.cc b/y2023_bot3/control_loops/superstructure/superstructure_lib_test.cc
new file mode 100644
index 0000000..24c4f2a
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/superstructure_lib_test.cc
@@ -0,0 +1,248 @@
+#include <chrono>
+#include <memory>
+
+#include "gtest/gtest.h"
+
+#include "aos/events/logging/log_writer.h"
+#include "frc971/control_loops/capped_test_plant.h"
+#include "frc971/control_loops/control_loop_test.h"
+#include "frc971/control_loops/position_sensor_sim.h"
+#include "frc971/control_loops/subsystem_simulator.h"
+#include "frc971/control_loops/team_number_test_environment.h"
+#include "y2023_bot3/constants/simulated_constants_sender.h"
+#include "y2023_bot3/control_loops/drivetrain/drivetrain_dog_motor_plant.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure.h"
+
+DEFINE_string(output_folder, "",
+ "If set, logs all channels to the provided logfile.");
+
+namespace y2023_bot3 {
+namespace control_loops {
+namespace superstructure {
+namespace testing {
+namespace {} // namespace
+namespace chrono = std::chrono;
+
+using ::aos::monotonic_clock;
+using ::frc971::CreateProfileParameters;
+using ::frc971::control_loops::CappedTestPlant;
+using ::frc971::control_loops::
+ CreateStaticZeroingSingleDOFProfiledSubsystemGoal;
+using ::frc971::control_loops::PositionSensorSimulator;
+using ::frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal;
+using DrivetrainStatus = ::frc971::control_loops::drivetrain::Status;
+
+// Class which simulates the superstructure and sends out queue messages with
+// the position.
+class SuperstructureSimulation {
+ public:
+ SuperstructureSimulation(::aos::EventLoop *event_loop,
+ std::shared_ptr<const constants::Values> values,
+ chrono::nanoseconds dt)
+ : event_loop_(event_loop),
+ superstructure_position_sender_(
+ event_loop_->MakeSender<Position>("/superstructure")),
+ superstructure_status_fetcher_(
+ event_loop_->MakeFetcher<Status>("/superstructure")),
+ superstructure_output_fetcher_(
+ event_loop_->MakeFetcher<Output>("/superstructure")) {
+ (void)values;
+ phased_loop_handle_ = event_loop_->AddPhasedLoop(
+ [this](int) {
+ // Skip this the first time.
+ if (!first_) {
+ EXPECT_TRUE(superstructure_output_fetcher_.Fetch());
+ EXPECT_TRUE(superstructure_status_fetcher_.Fetch());
+ }
+ first_ = false;
+ SendPositionMessage();
+ },
+ dt);
+ }
+
+ // Sends a queue message with the position of the superstructure.
+ void SendPositionMessage() {
+ ::aos::Sender<Position>::Builder builder =
+ superstructure_position_sender_.MakeBuilder();
+
+ Position::Builder position_builder = builder.MakeBuilder<Position>();
+ CHECK_EQ(builder.Send(position_builder.Finish()),
+ aos::RawSender::Error::kOk);
+ }
+
+ private:
+ ::aos::EventLoop *event_loop_;
+ ::aos::PhasedLoopHandler *phased_loop_handle_ = nullptr;
+
+ ::aos::Sender<Position> superstructure_position_sender_;
+ ::aos::Fetcher<Status> superstructure_status_fetcher_;
+ ::aos::Fetcher<Output> superstructure_output_fetcher_;
+
+ bool first_ = true;
+};
+
+class SuperstructureTest : public ::frc971::testing::ControlLoopTest {
+ public:
+ SuperstructureTest()
+ : ::frc971::testing::ControlLoopTest(
+ aos::configuration::ReadConfig("y2023_bot3/aos_config.json"),
+ std::chrono::microseconds(5050)),
+ values_(std::make_shared<constants::Values>(constants::MakeValues())),
+ simulated_constants_dummy_(SendSimulationConstants(
+ event_loop_factory(), 7971,
+ "y2023_bot3/constants/test_constants.json")),
+ roborio_(aos::configuration::GetNode(configuration(), "roborio")),
+ superstructure_event_loop(MakeEventLoop("Superstructure", roborio_)),
+ superstructure_(superstructure_event_loop.get(), values_),
+ test_event_loop_(MakeEventLoop("test", roborio_)),
+ superstructure_goal_fetcher_(
+ test_event_loop_->MakeFetcher<Goal>("/superstructure")),
+ superstructure_goal_sender_(
+ test_event_loop_->MakeSender<Goal>("/superstructure")),
+ superstructure_status_fetcher_(
+ test_event_loop_->MakeFetcher<Status>("/superstructure")),
+ superstructure_output_fetcher_(
+ test_event_loop_->MakeFetcher<Output>("/superstructure")),
+ superstructure_position_fetcher_(
+ test_event_loop_->MakeFetcher<Position>("/superstructure")),
+ superstructure_position_sender_(
+ test_event_loop_->MakeSender<Position>("/superstructure")),
+ drivetrain_status_sender_(
+ test_event_loop_->MakeSender<DrivetrainStatus>("/drivetrain")),
+ superstructure_plant_event_loop_(MakeEventLoop("plant", roborio_)),
+ superstructure_plant_(superstructure_plant_event_loop_.get(), values_,
+ dt()) {
+ set_team_id(frc971::control_loops::testing::kTeamNumber);
+
+ SetEnabled(true);
+
+ if (!FLAGS_output_folder.empty()) {
+ unlink(FLAGS_output_folder.c_str());
+ logger_event_loop_ = MakeEventLoop("logger", roborio_);
+ logger_ = std::make_unique<aos::logger::Logger>(logger_event_loop_.get());
+ logger_->StartLoggingOnRun(FLAGS_output_folder);
+ }
+ }
+
+ void VerifyNearGoal() {
+ superstructure_goal_fetcher_.Fetch();
+ superstructure_status_fetcher_.Fetch();
+
+ ASSERT_TRUE(superstructure_goal_fetcher_.get() != nullptr) << ": No goal";
+ ASSERT_TRUE(superstructure_status_fetcher_.get() != nullptr)
+ << ": No status";
+ }
+
+ void CheckIfZeroed() {
+ superstructure_status_fetcher_.Fetch();
+ ASSERT_TRUE(superstructure_status_fetcher_.get()->zeroed());
+ }
+
+ void WaitUntilZeroed() {
+ int i = 0;
+ do {
+ i++;
+ RunFor(dt());
+ superstructure_status_fetcher_.Fetch();
+ // 2 Seconds
+ ASSERT_LE(i, 2.0 / ::aos::time::DurationInSeconds(dt()));
+
+ // Since there is a delay when sending running, make sure we have a
+ // status before checking it.
+ } while (superstructure_status_fetcher_.get() == nullptr ||
+ !superstructure_status_fetcher_.get()->zeroed());
+ }
+
+ void SendRobotVelocity(double robot_velocity) {
+ SendDrivetrainStatus(robot_velocity, {0.0, 0.0}, 0.0);
+ }
+
+ void SendDrivetrainStatus(double robot_velocity, Eigen::Vector2d pos,
+ double theta) {
+ // Send a robot velocity to test compensation
+ auto builder = drivetrain_status_sender_.MakeBuilder();
+ auto drivetrain_status_builder = builder.MakeBuilder<DrivetrainStatus>();
+ drivetrain_status_builder.add_robot_speed(robot_velocity);
+ drivetrain_status_builder.add_estimated_left_velocity(robot_velocity);
+ drivetrain_status_builder.add_estimated_right_velocity(robot_velocity);
+ drivetrain_status_builder.add_x(pos.x());
+ drivetrain_status_builder.add_y(pos.y());
+ drivetrain_status_builder.add_theta(theta);
+ builder.CheckOk(builder.Send(drivetrain_status_builder.Finish()));
+ }
+
+ std::shared_ptr<const constants::Values> values_;
+ const bool simulated_constants_dummy_;
+
+ const aos::Node *const roborio_;
+
+ ::std::unique_ptr<::aos::EventLoop> superstructure_event_loop;
+ ::y2023_bot3::control_loops::superstructure::Superstructure superstructure_;
+ ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
+ ::aos::PhasedLoopHandler *phased_loop_handle_ = nullptr;
+
+ ::aos::Fetcher<Goal> superstructure_goal_fetcher_;
+ ::aos::Sender<Goal> superstructure_goal_sender_;
+ ::aos::Fetcher<Status> superstructure_status_fetcher_;
+ ::aos::Fetcher<Output> superstructure_output_fetcher_;
+ ::aos::Fetcher<Position> superstructure_position_fetcher_;
+ ::aos::Sender<Position> superstructure_position_sender_;
+ ::aos::Sender<DrivetrainStatus> drivetrain_status_sender_;
+
+ ::std::unique_ptr<::aos::EventLoop> superstructure_plant_event_loop_;
+ SuperstructureSimulation superstructure_plant_;
+
+ std::unique_ptr<aos::EventLoop> logger_event_loop_;
+ std::unique_ptr<aos::logger::Logger> logger_;
+};
+
+// Makes sure that the voltage on a motor is properly pulled back after
+// saturation such that we don't get weird or bad (e.g. oscillating)
+// behaviour.
+TEST_F(SuperstructureTest, SaturationTest) {
+ SetEnabled(true);
+
+ // Zero it before we move.
+ WaitUntilZeroed();
+ {
+ auto builder = superstructure_goal_sender_.MakeBuilder();
+
+ Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+
+ ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
+ }
+ RunFor(chrono::seconds(20));
+ VerifyNearGoal();
+
+ // Try a low acceleration move with a high max velocity and verify the
+ // acceleration is capped like expected.
+ {
+ auto builder = superstructure_goal_sender_.MakeBuilder();
+
+ Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+
+ ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
+ }
+
+ // TODO(Milo): Make this a sane time
+ RunFor(chrono::seconds(20));
+ VerifyNearGoal();
+}
+
+// Tests that the loop zeroes when run for a while without a goal.
+TEST_F(SuperstructureTest, ZeroNoGoal) {
+ SetEnabled(true);
+ WaitUntilZeroed();
+ RunFor(chrono::seconds(2));
+}
+
+// Tests that running disabled works
+TEST_F(SuperstructureTest, DisableTest) {
+ RunFor(chrono::seconds(2));
+ CheckIfZeroed();
+}
+
+} // namespace testing
+} // namespace superstructure
+} // namespace control_loops
+} // namespace y2023_bot3
diff --git a/y2023_bot3/control_loops/superstructure/superstructure_main.cc b/y2023_bot3/control_loops/superstructure/superstructure_main.cc
new file mode 100644
index 0000000..1abfe88
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/superstructure_main.cc
@@ -0,0 +1,25 @@
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure.h"
+
+using y2023_bot3::control_loops::superstructure::Superstructure;
+
+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());
+
+ frc971::constants::WaitForConstants<y2023_bot3::Constants>(&config.message());
+
+ std::shared_ptr<const y2023_bot3::constants::Values> values =
+ std::make_shared<const y2023_bot3::constants::Values>(
+ y2023_bot3::constants::MakeValues());
+ Superstructure superstructure(&event_loop, values);
+
+ event_loop.Run();
+
+ return 0;
+}
diff --git a/y2023_bot3/control_loops/superstructure/superstructure_output.fbs b/y2023_bot3/control_loops/superstructure/superstructure_output.fbs
new file mode 100644
index 0000000..652d247
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/superstructure_output.fbs
@@ -0,0 +1,10 @@
+namespace y2023_bot3.control_loops.superstructure;
+
+table Output {
+ // Pivot joint voltage
+ pivot_joint_voltage:double (id: 0);
+ // Roller voltage on the end effector (positive is spitting, negative is sucking)
+ roller_voltage:double (id: 1);
+}
+
+root_type Output;
diff --git a/y2023_bot3/control_loops/superstructure/superstructure_position.fbs b/y2023_bot3/control_loops/superstructure/superstructure_position.fbs
new file mode 100644
index 0000000..a629e56
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/superstructure_position.fbs
@@ -0,0 +1,18 @@
+include "frc971/control_loops/control_loops.fbs";
+include "frc971/can_configuration.fbs";
+include "frc971/control_loops/can_falcon.fbs";
+
+namespace y2023_bot3.control_loops.superstructure;
+
+table Position {
+ // The position of the pivot joint in radians
+ pivot_joint_position:frc971.PotAndAbsolutePosition (id: 0);
+
+ // If this is true, the cube beam break is triggered.
+ end_effector_cube_beam_break:bool (id: 1);
+
+ // Roller falcon data
+ roller_falcon:frc971.control_loops.CANFalcon (id: 2);
+}
+
+root_type Position;
diff --git a/y2023_bot3/control_loops/superstructure/superstructure_replay.cc b/y2023_bot3/control_loops/superstructure/superstructure_replay.cc
new file mode 100644
index 0000000..ed39461
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/superstructure_replay.cc
@@ -0,0 +1,74 @@
+// This binary allows us to replay the superstructure code over existing
+// logfile. When you run this code, it generates a new logfile with the data all
+// replayed, so that it can then be run through the plotting tool or analyzed
+// in some other way. The original superstructure status data will be on the
+// /original/superstructure channel.
+#include "gflags/gflags.h"
+
+#include "aos/events/logging/log_reader.h"
+#include "aos/events/logging/log_writer.h"
+#include "aos/events/simulated_event_loop.h"
+#include "aos/init.h"
+#include "aos/json_to_flatbuffer.h"
+#include "aos/logging/log_message_generated.h"
+#include "aos/network/team_number.h"
+#include "y2023_bot3/constants.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure.h"
+
+DEFINE_int32(team, 971, "Team number to use for logfile replay.");
+DEFINE_string(output_folder, "/tmp/superstructure_replay/",
+ "Logs all channels to the provided logfile.");
+
+int main(int argc, char **argv) {
+ aos::InitGoogle(&argc, &argv);
+
+ aos::network::OverrideTeamNumber(FLAGS_team);
+
+ // open logfiles
+ aos::logger::LogReader reader(
+ aos::logger::SortParts(aos::logger::FindLogs(argc, argv)));
+ reader.RemapLoggedChannel("/superstructure",
+ "y2023_bot3.control_loops.superstructure.Status");
+ reader.RemapLoggedChannel("/superstructure",
+ "y2023_bot3.control_loops.superstructure.Output");
+
+ aos::SimulatedEventLoopFactory factory(reader.configuration());
+ reader.Register(&factory);
+
+ aos::NodeEventLoopFactory *roborio =
+ factory.GetNodeEventLoopFactory("roborio");
+
+ unlink(FLAGS_output_folder.c_str());
+ std::unique_ptr<aos::EventLoop> logger_event_loop =
+ roborio->MakeEventLoop("logger");
+ auto logger = std::make_unique<aos::logger::Logger>(logger_event_loop.get());
+ logger->StartLoggingOnRun(FLAGS_output_folder);
+
+ roborio->OnStartup([roborio]() {
+ roborio->AlwaysStart<
+ y2023_bot3::control_loops::superstructure::Superstructure>(
+ "superstructure", std::make_shared<y2023_bot3::constants::Values>(
+ y2023_bot3::constants::MakeValues()));
+ });
+
+ std::unique_ptr<aos::EventLoop> print_loop = roborio->MakeEventLoop("print");
+ print_loop->SkipAosLog();
+ print_loop->MakeWatcher(
+ "/aos", [&print_loop](const aos::logging::LogMessageFbs &msg) {
+ LOG(INFO) << print_loop->context().monotonic_event_time << " "
+ << aos::FlatbufferToJson(&msg);
+ });
+ print_loop->MakeWatcher(
+ "/superstructure",
+ [&](const y2023_bot3::control_loops::superstructure::Status &status) {
+ if (status.estopped()) {
+ LOG(ERROR) << "Estopped";
+ }
+ });
+
+ factory.Run();
+
+ reader.Deregister();
+
+ return 0;
+}
diff --git a/y2023_bot3/control_loops/superstructure/superstructure_status.fbs b/y2023_bot3/control_loops/superstructure/superstructure_status.fbs
new file mode 100644
index 0000000..f3df83c
--- /dev/null
+++ b/y2023_bot3/control_loops/superstructure/superstructure_status.fbs
@@ -0,0 +1,34 @@
+include "frc971/control_loops/control_loops.fbs";
+include "frc971/control_loops/profiled_subsystem.fbs";
+
+namespace y2023_bot3.control_loops.superstructure;
+
+enum EndEffectorState : ubyte {
+ // Not doing anything
+ IDLE = 0,
+ // Intaking the game object into the end effector
+ INTAKING = 1,
+ // The game object is loaded into the end effector
+ LOADED = 2,
+ // Waiting for the arm to be at shooting goal and then telling the
+ // end effector to spit
+ SPITTING = 3,
+ // Waiting for the arm to be at MID shooting goal and then telling the
+ // end effector to spit mid
+ SPITTING_MID = 4
+}
+
+table Status {
+ // All subsystems know their location.
+ zeroed:bool (id: 0);
+
+ // If true, we have aborted. This is the or of all subsystem estops.
+ estopped:bool (id: 1);
+
+ // The current state of the arm.
+ pivot_joint_state:frc971.control_loops.PotAndAbsoluteEncoderProfiledJointStatus (id: 2);
+
+ end_effector_state:EndEffectorState (id: 3);
+}
+
+root_type Status;
diff --git a/y2023_bot3/joystick_reader.cc b/y2023_bot3/joystick_reader.cc
new file mode 100644
index 0000000..2e874d3
--- /dev/null
+++ b/y2023_bot3/joystick_reader.cc
@@ -0,0 +1,109 @@
+#include <unistd.h>
+
+#include <cmath>
+#include <cstdio>
+#include <cstring>
+
+#include "aos/actions/actions.h"
+#include "aos/init.h"
+#include "aos/logging/logging.h"
+#include "aos/network/team_number.h"
+#include "aos/util/log_interval.h"
+#include "frc971/autonomous/base_autonomous_actor.h"
+#include "frc971/control_loops/drivetrain/localizer_generated.h"
+#include "frc971/control_loops/profiled_subsystem_generated.h"
+#include "frc971/input/action_joystick_input.h"
+#include "frc971/input/driver_station_data.h"
+#include "frc971/input/drivetrain_input.h"
+#include "frc971/input/joystick_input.h"
+#include "frc971/input/redundant_joystick_data.h"
+#include "frc971/zeroing/wrap.h"
+#include "y2023_bot3/constants.h"
+#include "y2023_bot3/control_loops/drivetrain/drivetrain_base.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_goal_generated.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_status_generated.h"
+
+using frc971::CreateProfileParameters;
+using frc971::control_loops::CreateStaticZeroingSingleDOFProfiledSubsystemGoal;
+using frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal;
+using frc971::input::driver_station::ButtonLocation;
+using frc971::input::driver_station::ControlBit;
+using frc971::input::driver_station::JoystickAxis;
+using frc971::input::driver_station::POVLocation;
+using Side = frc971::control_loops::drivetrain::RobotSide;
+
+namespace y2023_bot3 {
+namespace input {
+namespace joysticks {
+
+namespace superstructure = y2023_bot3::control_loops::superstructure;
+
+struct ButtonData {
+ ButtonLocation button;
+};
+
+class Reader : public ::frc971::input::ActionJoystickInput {
+ public:
+ Reader(::aos::EventLoop *event_loop)
+ : ::frc971::input::ActionJoystickInput(
+ event_loop,
+ ::y2023_bot3::control_loops::drivetrain::GetDrivetrainConfig(),
+ ::frc971::input::DrivetrainInputReader::InputType::kPistol,
+ {.use_redundant_joysticks = true}),
+ superstructure_goal_sender_(
+ event_loop->MakeSender<superstructure::Goal>("/superstructure")),
+ superstructure_status_fetcher_(
+ event_loop->MakeFetcher<superstructure::Status>(
+ "/superstructure")) {}
+
+ void AutoEnded() override { AOS_LOG(INFO, "Auto ended.\n"); }
+
+ bool has_scored_ = false;
+
+ void HandleTeleop(
+ const ::frc971::input::driver_station::Data &data) override {
+ (void)data;
+ superstructure_status_fetcher_.Fetch();
+ if (!superstructure_status_fetcher_.get()) {
+ AOS_LOG(ERROR, "Got no superstructure status message.\n");
+ return;
+ }
+
+ std::optional<double> place_index = std::nullopt;
+ (void)place_index;
+
+ {
+ auto builder = superstructure_goal_sender_.MakeBuilder();
+
+ superstructure::Goal::Builder superstructure_goal_builder =
+ builder.MakeBuilder<superstructure::Goal>();
+ if (builder.Send(superstructure_goal_builder.Finish()) !=
+ aos::RawSender::Error::kOk) {
+ AOS_LOG(ERROR, "Sending superstructure goal failed.\n");
+ }
+ }
+ }
+
+ private:
+ ::aos::Sender<superstructure::Goal> superstructure_goal_sender_;
+
+ ::aos::Fetcher<superstructure::Status> superstructure_status_fetcher_;
+};
+
+} // namespace joysticks
+} // namespace input
+} // namespace y2023_bot3
+
+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());
+ ::y2023_bot3::input::joysticks::Reader reader(&event_loop);
+
+ event_loop.Run();
+
+ return 0;
+}
diff --git a/y2023_bot3/log_web_proxy.sh b/y2023_bot3/log_web_proxy.sh
new file mode 100755
index 0000000..a2c3acc
--- /dev/null
+++ b/y2023_bot3/log_web_proxy.sh
@@ -0,0 +1 @@
+./aos/network/log_web_proxy_main --data_dir=y2023_bot3/www $@
diff --git a/y2023_bot3/rockpi/BUILD b/y2023_bot3/rockpi/BUILD
new file mode 100644
index 0000000..f3a9d94
--- /dev/null
+++ b/y2023_bot3/rockpi/BUILD
@@ -0,0 +1,12 @@
+cc_binary(
+ name = "imu_main",
+ srcs = ["imu_main.cc"],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//aos:init",
+ "//aos/events:shm_event_loop",
+ "//frc971/imu_reader:imu",
+ "//y2023_bot3:constants",
+ ],
+)
diff --git a/y2023_bot3/rockpi/imu_main.cc b/y2023_bot3/rockpi/imu_main.cc
new file mode 100644
index 0000000..cd443f2
--- /dev/null
+++ b/y2023_bot3/rockpi/imu_main.cc
@@ -0,0 +1,25 @@
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "aos/realtime.h"
+#include "frc971/imu_reader/imu.h"
+#include "y2023_bot3/constants.h"
+
+DEFINE_string(config, "aos_config.json", "Path to the config file to use.");
+
+int main(int argc, char *argv[]) {
+ aos::InitGoogle(&argc, &argv);
+
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig(FLAGS_config);
+
+ aos::ShmEventLoop event_loop(&config.message());
+ frc971::imu::Imu imu(
+ &event_loop, y2023_bot3::constants::Values::DrivetrainEncoderToMeters(1));
+
+ event_loop.SetRuntimeAffinity(aos::MakeCpusetFromCpus({0}));
+ event_loop.SetRuntimeRealtimePriority(55);
+
+ event_loop.Run();
+
+ return 0;
+}
diff --git a/y2023_bot3/wpilib_interface.cc b/y2023_bot3/wpilib_interface.cc
new file mode 100644
index 0000000..2b5a9f4
--- /dev/null
+++ b/y2023_bot3/wpilib_interface.cc
@@ -0,0 +1,784 @@
+#include <unistd.h>
+
+#include <array>
+#include <chrono>
+#include <cinttypes>
+#include <cmath>
+#include <cstdio>
+#include <cstring>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include "ctre/phoenix/CANifier.h"
+
+#include "frc971/wpilib/ahal/AnalogInput.h"
+#include "frc971/wpilib/ahal/Counter.h"
+#include "frc971/wpilib/ahal/DigitalGlitchFilter.h"
+#include "frc971/wpilib/ahal/DriverStation.h"
+#include "frc971/wpilib/ahal/Encoder.h"
+#include "frc971/wpilib/ahal/Servo.h"
+#include "frc971/wpilib/ahal/TalonFX.h"
+#include "frc971/wpilib/ahal/VictorSP.h"
+#undef ERROR
+
+#include "ctre/phoenix/cci/Diagnostics_CCI.h"
+#include "ctre/phoenix/motorcontrol/can/TalonFX.h"
+#include "ctre/phoenix/motorcontrol/can/TalonSRX.h"
+#include "ctre/phoenix6/TalonFX.hpp"
+
+#include "aos/commonmath.h"
+#include "aos/containers/sized_array.h"
+#include "aos/events/event_loop.h"
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "aos/logging/logging.h"
+#include "aos/realtime.h"
+#include "aos/time/time.h"
+#include "aos/util/log_interval.h"
+#include "aos/util/phased_loop.h"
+#include "aos/util/wrapping_counter.h"
+#include "frc971/autonomous/auto_mode_generated.h"
+#include "frc971/can_configuration_generated.h"
+#include "frc971/control_loops/drivetrain/drivetrain_can_position_generated.h"
+#include "frc971/control_loops/drivetrain/drivetrain_position_generated.h"
+#include "frc971/input/robot_state_generated.h"
+#include "frc971/queues/gyro_generated.h"
+#include "frc971/wpilib/ADIS16448.h"
+#include "frc971/wpilib/buffered_pcm.h"
+#include "frc971/wpilib/buffered_solenoid.h"
+#include "frc971/wpilib/dma.h"
+#include "frc971/wpilib/drivetrain_writer.h"
+#include "frc971/wpilib/encoder_and_potentiometer.h"
+#include "frc971/wpilib/joystick_sender.h"
+#include "frc971/wpilib/logging_generated.h"
+#include "frc971/wpilib/loop_output_handler.h"
+#include "frc971/wpilib/pdp_fetcher.h"
+#include "frc971/wpilib/sensor_reader.h"
+#include "frc971/wpilib/wpilib_robot_base.h"
+#include "y2023_bot3/constants.h"
+#include "y2023_bot3/control_loops/superstructure/led_indicator.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_output_generated.h"
+#include "y2023_bot3/control_loops/superstructure/superstructure_position_generated.h"
+
+DEFINE_bool(ctre_diag_server, false,
+ "If true, enable the diagnostics server for interacting with "
+ "devices on the CAN bus using Phoenix Tuner");
+
+using ::aos::monotonic_clock;
+using ::y2023_bot3::constants::Values;
+namespace superstructure = ::y2023_bot3::control_loops::superstructure;
+namespace drivetrain = ::y2023_bot3::control_loops::drivetrain;
+namespace chrono = ::std::chrono;
+using std::make_unique;
+
+namespace y2023_bot3 {
+namespace wpilib {
+namespace {
+
+constexpr double kMaxBringupPower = 12.0;
+
+// TODO(Brian): Fix the interpretation of the result of GetRaw here and in the
+// DMA stuff and then removing the * 2.0 in *_translate.
+// The low bit is direction.
+
+double drivetrain_velocity_translate(double in) {
+ return (((1.0 / in) / Values::kDrivetrainCyclesPerRevolution()) *
+ (2.0 * M_PI)) *
+ Values::kDrivetrainEncoderRatio() *
+ control_loops::drivetrain::kWheelRadius;
+}
+
+constexpr double kMaxFastEncoderPulsesPerSecond = std::max({
+ Values::kMaxDrivetrainEncoderPulsesPerSecond(),
+});
+static_assert(kMaxFastEncoderPulsesPerSecond <= 1300000,
+ "fast encoders are too fast");
+
+} // namespace
+
+static constexpr int kCANFalconCount = 6;
+static constexpr units::frequency::hertz_t kCANUpdateFreqHz = 200_Hz;
+
+class Falcon {
+ public:
+ Falcon(int device_id, std::string canbus,
+ std::vector<ctre::phoenix6::BaseStatusSignal *> *signals)
+ : talon_(device_id, canbus),
+ device_id_(device_id),
+ device_temp_(talon_.GetDeviceTemp()),
+ supply_voltage_(talon_.GetSupplyVoltage()),
+ supply_current_(talon_.GetSupplyCurrent()),
+ torque_current_(talon_.GetTorqueCurrent()),
+ position_(talon_.GetPosition()),
+ duty_cycle_(talon_.GetDutyCycle()) {
+ // device temp is not timesynced so don't add it to the list of signals
+ device_temp_.SetUpdateFrequency(kCANUpdateFreqHz);
+
+ CHECK_NOTNULL(signals);
+
+ supply_voltage_.SetUpdateFrequency(kCANUpdateFreqHz);
+ signals->push_back(&supply_voltage_);
+
+ supply_current_.SetUpdateFrequency(kCANUpdateFreqHz);
+ signals->push_back(&supply_current_);
+
+ torque_current_.SetUpdateFrequency(kCANUpdateFreqHz);
+ signals->push_back(&torque_current_);
+
+ position_.SetUpdateFrequency(kCANUpdateFreqHz);
+ signals->push_back(&position_);
+
+ duty_cycle_.SetUpdateFrequency(kCANUpdateFreqHz);
+ signals->push_back(&duty_cycle_);
+ }
+
+ void PrintConfigs() {
+ ctre::phoenix6::configs::TalonFXConfiguration configuration;
+ ctre::phoenix::StatusCode status =
+ talon_.GetConfigurator().Refresh(configuration);
+ if (!status.IsOK()) {
+ AOS_LOG(ERROR, "Failed to get falcon configuration: %s: %s",
+ status.GetName(), status.GetDescription());
+ }
+ AOS_LOG(INFO, "configuration: %s", configuration.ToString().c_str());
+ }
+
+ void WriteConfigs(ctre::phoenix6::signals::InvertedValue invert) {
+ inverted_ = invert;
+
+ ctre::phoenix6::configs::CurrentLimitsConfigs current_limits;
+ current_limits.StatorCurrentLimit =
+ constants::Values::kDrivetrainStatorCurrentLimit();
+ current_limits.StatorCurrentLimitEnable = true;
+ current_limits.SupplyCurrentLimit =
+ constants::Values::kDrivetrainSupplyCurrentLimit();
+ current_limits.SupplyCurrentLimitEnable = true;
+
+ ctre::phoenix6::configs::MotorOutputConfigs output_configs;
+ output_configs.NeutralMode =
+ ctre::phoenix6::signals::NeutralModeValue::Brake;
+ output_configs.DutyCycleNeutralDeadband = 0;
+
+ output_configs.Inverted = inverted_;
+
+ ctre::phoenix6::configs::TalonFXConfiguration configuration;
+ configuration.CurrentLimits = current_limits;
+ configuration.MotorOutput = output_configs;
+
+ ctre::phoenix::StatusCode status =
+ talon_.GetConfigurator().Apply(configuration);
+ if (!status.IsOK()) {
+ AOS_LOG(ERROR, "Failed to set falcon configuration: %s: %s",
+ status.GetName(), status.GetDescription());
+ }
+
+ PrintConfigs();
+ }
+
+ ctre::phoenix6::hardware::TalonFX *talon() { return &talon_; }
+
+ flatbuffers::Offset<frc971::control_loops::CANFalcon> WritePosition(
+ flatbuffers::FlatBufferBuilder *fbb) {
+ frc971::control_loops::CANFalcon::Builder builder(*fbb);
+ builder.add_id(device_id_);
+ builder.add_device_temp(device_temp());
+ builder.add_supply_voltage(supply_voltage());
+ builder.add_supply_current(supply_current());
+ builder.add_torque_current(torque_current());
+ builder.add_duty_cycle(duty_cycle());
+
+ double invert =
+ (inverted_ == ctre::phoenix6::signals::InvertedValue::Clockwise_Positive
+ ? 1
+ : -1);
+
+ builder.add_position(
+ constants::Values::DrivetrainCANEncoderToMeters(position()) * invert);
+
+ return builder.Finish();
+ }
+
+ int device_id() const { return device_id_; }
+ float device_temp() const { return device_temp_.GetValue().value(); }
+ float supply_voltage() const { return supply_voltage_.GetValue().value(); }
+ float supply_current() const { return supply_current_.GetValue().value(); }
+ float torque_current() const { return torque_current_.GetValue().value(); }
+ float duty_cycle() const { return duty_cycle_.GetValue().value(); }
+ float position() const { return position_.GetValue().value(); }
+
+ // returns the monotonic timestamp of the latest timesynced reading in the
+ // timebase of the the syncronized CAN bus clock.
+ int64_t GetTimestamp() {
+ std::chrono::nanoseconds latest_timestamp =
+ torque_current_.GetTimestamp().GetTime();
+
+ return latest_timestamp.count();
+ }
+
+ void RefreshNontimesyncedSignals() { device_temp_.Refresh(); };
+
+ private:
+ ctre::phoenix6::hardware::TalonFX talon_;
+ int device_id_;
+
+ ctre::phoenix6::signals::InvertedValue inverted_;
+
+ ctre::phoenix6::StatusSignal<units::temperature::celsius_t> device_temp_;
+ ctre::phoenix6::StatusSignal<units::voltage::volt_t> supply_voltage_;
+ ctre::phoenix6::StatusSignal<units::current::ampere_t> supply_current_,
+ torque_current_;
+ ctre::phoenix6::StatusSignal<units::angle::turn_t> position_;
+ ctre::phoenix6::StatusSignal<units::dimensionless::scalar_t> duty_cycle_;
+};
+
+class CANSensorReader {
+ public:
+ CANSensorReader(
+ aos::EventLoop *event_loop,
+ std::vector<ctre::phoenix6::BaseStatusSignal *> signals_registry)
+ : event_loop_(event_loop),
+ signals_(signals_registry.begin(), signals_registry.end()),
+ can_position_sender_(
+ event_loop
+ ->MakeSender<frc971::control_loops::drivetrain::CANPosition>(
+ "/drivetrain")) {
+ event_loop->SetRuntimeRealtimePriority(40);
+ event_loop->SetRuntimeAffinity(aos::MakeCpusetFromCpus({1}));
+ timer_handler_ = event_loop->AddTimer([this]() { Loop(); });
+ timer_handler_->set_name("CANSensorReader Loop");
+
+ event_loop->OnRun([this]() {
+ timer_handler_->Schedule(event_loop_->monotonic_now(),
+ 1 / kCANUpdateFreqHz);
+ });
+ }
+
+ void set_falcons(std::shared_ptr<Falcon> right_front,
+ std::shared_ptr<Falcon> right_back,
+ std::shared_ptr<Falcon> left_front,
+ std::shared_ptr<Falcon> left_back,
+ std::shared_ptr<Falcon> roller_falcon) {
+ right_front_ = std::move(right_front);
+ right_back_ = std::move(right_back);
+ left_front_ = std::move(left_front);
+ left_back_ = std::move(left_back);
+ roller_falcon = std::move(roller_falcon);
+ }
+
+ std::optional<frc971::control_loops::CANFalconT> roller_falcon_data() {
+ std::unique_lock<aos::stl_mutex> lock(roller_mutex_);
+ return roller_falcon_data_;
+ }
+
+ private:
+ void Loop() {
+ ctre::phoenix::StatusCode status =
+ ctre::phoenix6::BaseStatusSignal::WaitForAll(2000_ms, signals_);
+
+ if (!status.IsOK()) {
+ AOS_LOG(ERROR, "Failed to read signals from falcons: %s: %s",
+ status.GetName(), status.GetDescription());
+ }
+
+ auto builder = can_position_sender_.MakeBuilder();
+
+ for (auto falcon : {right_front_, right_back_, left_front_, left_back_}) {
+ falcon->RefreshNontimesyncedSignals();
+ }
+
+ aos::SizedArray<flatbuffers::Offset<frc971::control_loops::CANFalcon>,
+ kCANFalconCount>
+ falcons;
+
+ for (auto falcon : {right_front_, right_back_, left_front_, left_back_}) {
+ falcons.push_back(falcon->WritePosition(builder.fbb()));
+ }
+
+ auto falcons_list =
+ builder.fbb()
+ ->CreateVector<
+ flatbuffers::Offset<frc971::control_loops::CANFalcon>>(falcons);
+
+ frc971::control_loops::drivetrain::CANPosition::Builder
+ can_position_builder =
+ builder
+ .MakeBuilder<frc971::control_loops::drivetrain::CANPosition>();
+
+ can_position_builder.add_falcons(falcons_list);
+ can_position_builder.add_timestamp(right_front_->GetTimestamp());
+ can_position_builder.add_status(static_cast<int>(status));
+
+ builder.CheckOk(builder.Send(can_position_builder.Finish()));
+ }
+
+ aos::EventLoop *event_loop_;
+
+ const std::vector<ctre::phoenix6::BaseStatusSignal *> signals_;
+ aos::Sender<frc971::control_loops::drivetrain::CANPosition>
+ can_position_sender_;
+
+ std::shared_ptr<Falcon> right_front_, right_back_, left_front_, left_back_,
+ roller_falcon;
+
+ std::optional<frc971::control_loops::CANFalconT> roller_falcon_data_;
+
+ aos::stl_mutex roller_mutex_;
+
+ // Pointer to the timer handler used to modify the wakeup.
+ ::aos::TimerHandler *timer_handler_;
+};
+
+// Class to send position messages with sensor readings to our loops.
+class SensorReader : public ::frc971::wpilib::SensorReader {
+ public:
+ SensorReader(::aos::ShmEventLoop *event_loop,
+ std::shared_ptr<const Values> values,
+ CANSensorReader *can_sensor_reader)
+ : ::frc971::wpilib::SensorReader(event_loop),
+ values_(std::move(values)),
+ auto_mode_sender_(
+ event_loop->MakeSender<::frc971::autonomous::AutonomousMode>(
+ "/autonomous")),
+ superstructure_position_sender_(
+ event_loop->MakeSender<superstructure::Position>(
+ "/superstructure")),
+ drivetrain_position_sender_(
+ event_loop
+ ->MakeSender<::frc971::control_loops::drivetrain::Position>(
+ "/drivetrain")),
+ gyro_sender_(event_loop->MakeSender<::frc971::sensors::GyroReading>(
+ "/drivetrain")),
+ can_sensor_reader_(can_sensor_reader) {
+ // Set to filter out anything shorter than 1/4 of the minimum pulse width
+ // we should ever see.
+ UpdateFastEncoderFilterHz(kMaxFastEncoderPulsesPerSecond);
+ event_loop->SetRuntimeAffinity(aos::MakeCpusetFromCpus({0}));
+ }
+
+ void Start() override { AddToDMA(&imu_yaw_rate_reader_); }
+
+ // Auto mode switches.
+ void set_autonomous_mode(int i, ::std::unique_ptr<frc::DigitalInput> sensor) {
+ autonomous_modes_.at(i) = ::std::move(sensor);
+ }
+
+ void set_yaw_rate_input(::std::unique_ptr<frc::DigitalInput> sensor) {
+ imu_yaw_rate_input_ = ::std::move(sensor);
+ imu_yaw_rate_reader_.set_input(imu_yaw_rate_input_.get());
+ }
+
+ void RunIteration() override {
+ superstructure_reading_->Set(true);
+ {
+ auto builder = superstructure_position_sender_.MakeBuilder();
+
+ flatbuffers::Offset<frc971::control_loops::CANFalcon>
+ roller_falcon_offset;
+ auto optional_roller_falcon = can_sensor_reader_->roller_falcon_data();
+ if (optional_roller_falcon.has_value()) {
+ roller_falcon_offset = frc971::control_loops::CANFalcon::Pack(
+ *builder.fbb(), &optional_roller_falcon.value());
+ }
+
+ superstructure::Position::Builder position_builder =
+ builder.MakeBuilder<superstructure::Position>();
+ position_builder.add_end_effector_cube_beam_break(
+ end_effector_cube_beam_break_->Get());
+
+ if (!roller_falcon_offset.IsNull()) {
+ position_builder.add_roller_falcon(roller_falcon_offset);
+ }
+ builder.CheckOk(builder.Send(position_builder.Finish()));
+ }
+
+ {
+ auto builder = drivetrain_position_sender_.MakeBuilder();
+ frc971::control_loops::drivetrain::Position::Builder drivetrain_builder =
+ builder.MakeBuilder<frc971::control_loops::drivetrain::Position>();
+ drivetrain_builder.add_left_encoder(
+ constants::Values::DrivetrainEncoderToMeters(
+ drivetrain_left_encoder_->GetRaw()));
+ drivetrain_builder.add_left_speed(
+ drivetrain_velocity_translate(drivetrain_left_encoder_->GetPeriod()));
+
+ drivetrain_builder.add_right_encoder(
+ -constants::Values::DrivetrainEncoderToMeters(
+ drivetrain_right_encoder_->GetRaw()));
+ drivetrain_builder.add_right_speed(-drivetrain_velocity_translate(
+ drivetrain_right_encoder_->GetPeriod()));
+
+ builder.CheckOk(builder.Send(drivetrain_builder.Finish()));
+ }
+
+ {
+ auto builder = gyro_sender_.MakeBuilder();
+ ::frc971::sensors::GyroReading::Builder gyro_reading_builder =
+ builder.MakeBuilder<::frc971::sensors::GyroReading>();
+ // +/- 2000 deg / sec
+ constexpr double kMaxVelocity = 4000; // degrees / second
+ constexpr double kVelocityRadiansPerSecond =
+ kMaxVelocity / 360 * (2.0 * M_PI);
+
+ // Only part of the full range is used to prevent being 100% on or off.
+ constexpr double kScaledRangeLow = 0.1;
+ constexpr double kScaledRangeHigh = 0.9;
+
+ constexpr double kPWMFrequencyHz = 200;
+ double velocity_duty_cycle =
+ imu_yaw_rate_reader_.last_width() * kPWMFrequencyHz;
+
+ constexpr double kDutyCycleScale =
+ 1 / (kScaledRangeHigh - kScaledRangeLow);
+ // scale from 0.1 - 0.9 to 0 - 1
+ double rescaled_velocity_duty_cycle =
+ (velocity_duty_cycle - kScaledRangeLow) * kDutyCycleScale;
+
+ if (!std::isnan(rescaled_velocity_duty_cycle)) {
+ gyro_reading_builder.add_velocity((rescaled_velocity_duty_cycle - 0.5) *
+ kVelocityRadiansPerSecond);
+ }
+ builder.CheckOk(builder.Send(gyro_reading_builder.Finish()));
+ }
+
+ {
+ auto builder = auto_mode_sender_.MakeBuilder();
+
+ uint32_t mode = 0;
+ for (size_t i = 0; i < autonomous_modes_.size(); ++i) {
+ if (autonomous_modes_[i] && autonomous_modes_[i]->Get()) {
+ mode |= 1 << i;
+ }
+ }
+
+ auto auto_mode_builder =
+ builder.MakeBuilder<frc971::autonomous::AutonomousMode>();
+
+ auto_mode_builder.add_mode(mode);
+
+ builder.CheckOk(builder.Send(auto_mode_builder.Finish()));
+ }
+ }
+
+ std::shared_ptr<frc::DigitalOutput> superstructure_reading_;
+
+ void set_superstructure_reading(
+ std::shared_ptr<frc::DigitalOutput> superstructure_reading) {
+ superstructure_reading_ = superstructure_reading;
+ }
+
+ private:
+ std::shared_ptr<const Values> values_;
+
+ aos::Sender<frc971::autonomous::AutonomousMode> auto_mode_sender_;
+ aos::Sender<superstructure::Position> superstructure_position_sender_;
+ aos::Sender<frc971::control_loops::drivetrain::Position>
+ drivetrain_position_sender_;
+ ::aos::Sender<::frc971::sensors::GyroReading> gyro_sender_;
+
+ std::array<std::unique_ptr<frc::DigitalInput>, 2> autonomous_modes_;
+
+ std::unique_ptr<frc::DigitalInput> imu_yaw_rate_input_,
+ end_effector_cube_beam_break_;
+
+ frc971::wpilib::DMAPulseWidthReader imu_yaw_rate_reader_;
+
+ CANSensorReader *can_sensor_reader_;
+};
+
+class SuperstructureWriter
+ : public ::frc971::wpilib::LoopOutputHandler<superstructure::Output> {
+ public:
+ SuperstructureWriter(aos::EventLoop *event_loop)
+ : frc971::wpilib::LoopOutputHandler<superstructure::Output>(
+ event_loop, "/superstructure") {
+ event_loop->SetRuntimeRealtimePriority(
+ constants::Values::kDrivetrainWriterPriority);
+ }
+
+ std::shared_ptr<frc::DigitalOutput> superstructure_reading_;
+
+ void set_superstructure_reading(
+ std::shared_ptr<frc::DigitalOutput> superstructure_reading) {
+ superstructure_reading_ = superstructure_reading;
+ }
+
+ private:
+ void Stop() override { AOS_LOG(WARNING, "Superstructure output too old.\n"); }
+
+ void Write(const superstructure::Output &output) override { (void)output; }
+
+ static void WriteCan(const double voltage,
+ ::ctre::phoenix::motorcontrol::can::TalonFX *falcon) {
+ falcon->Set(
+ ctre::phoenix::motorcontrol::ControlMode::PercentOutput,
+ std::clamp(voltage, -kMaxBringupPower, kMaxBringupPower) / 12.0);
+ }
+
+ template <typename T>
+ static void WritePwm(const double voltage, T *motor) {
+ motor->SetSpeed(std::clamp(voltage, -kMaxBringupPower, kMaxBringupPower) /
+ 12.0);
+ }
+};
+
+class SuperstructureCANWriter
+ : public ::frc971::wpilib::LoopOutputHandler<superstructure::Output> {
+ public:
+ SuperstructureCANWriter(::aos::EventLoop *event_loop)
+ : ::frc971::wpilib::LoopOutputHandler<superstructure::Output>(
+ event_loop, "/superstructure") {
+ event_loop->SetRuntimeRealtimePriority(
+ constants::Values::kSuperstructureCANWriterPriority);
+
+ event_loop->OnRun([this]() { WriteConfigs(); });
+ };
+
+ void HandleCANConfiguration(const frc971::CANConfiguration &configuration) {
+ if (configuration.reapply()) {
+ WriteConfigs();
+ }
+ }
+
+ private:
+ void WriteConfigs() {}
+
+ void Write(const superstructure::Output &output) override { (void)output; }
+
+ void Stop() override {
+ AOS_LOG(WARNING, "Superstructure CAN output too old.\n");
+ ctre::phoenix6::controls::DutyCycleOut stop_command(0.0);
+ stop_command.UpdateFreqHz = 0_Hz;
+ stop_command.EnableFOC = true;
+ }
+
+ double SafeSpeed(double voltage) {
+ return (::aos::Clip(voltage, -kMaxBringupPower, kMaxBringupPower) / 12.0);
+ }
+};
+
+class DrivetrainWriter : public ::frc971::wpilib::LoopOutputHandler<
+ ::frc971::control_loops::drivetrain::Output> {
+ public:
+ DrivetrainWriter(::aos::EventLoop *event_loop)
+ : ::frc971::wpilib::LoopOutputHandler<
+ ::frc971::control_loops::drivetrain::Output>(event_loop,
+ "/drivetrain") {
+ event_loop->SetRuntimeRealtimePriority(
+ constants::Values::kDrivetrainWriterPriority);
+
+ event_loop->OnRun([this]() { WriteConfigs(); });
+ }
+
+ void set_falcons(std::shared_ptr<Falcon> right_front,
+ std::shared_ptr<Falcon> right_back,
+ std::shared_ptr<Falcon> left_front,
+ std::shared_ptr<Falcon> left_back) {
+ right_front_ = std::move(right_front);
+ right_back_ = std::move(right_back);
+ left_front_ = std::move(left_front);
+ left_back_ = std::move(left_back);
+ }
+
+ void set_right_inverted(ctre::phoenix6::signals::InvertedValue invert) {
+ right_inverted_ = invert;
+ }
+
+ void set_left_inverted(ctre::phoenix6::signals::InvertedValue invert) {
+ left_inverted_ = invert;
+ }
+
+ void HandleCANConfiguration(const frc971::CANConfiguration &configuration) {
+ for (auto falcon : {right_front_, right_back_, left_front_, left_back_}) {
+ falcon->PrintConfigs();
+ }
+ if (configuration.reapply()) {
+ WriteConfigs();
+ }
+ }
+
+ private:
+ void WriteConfigs() {
+ for (auto falcon : {right_front_.get(), right_back_.get()}) {
+ falcon->WriteConfigs(right_inverted_);
+ }
+
+ for (auto falcon : {left_front_.get(), left_back_.get()}) {
+ falcon->WriteConfigs(left_inverted_);
+ }
+ }
+
+ void Write(
+ const ::frc971::control_loops::drivetrain::Output &output) override {
+ ctre::phoenix6::controls::DutyCycleOut left_control(
+ SafeSpeed(output.left_voltage()));
+ left_control.UpdateFreqHz = 0_Hz;
+ left_control.EnableFOC = true;
+
+ ctre::phoenix6::controls::DutyCycleOut right_control(
+ SafeSpeed(output.right_voltage()));
+ right_control.UpdateFreqHz = 0_Hz;
+ right_control.EnableFOC = true;
+
+ for (auto falcon : {left_front_.get(), left_back_.get()}) {
+ ctre::phoenix::StatusCode status =
+ falcon->talon()->SetControl(left_control);
+
+ if (!status.IsOK()) {
+ AOS_LOG(ERROR, "Failed to write control to falcon: %s: %s",
+ status.GetName(), status.GetDescription());
+ }
+ }
+
+ for (auto falcon : {right_front_.get(), right_back_.get()}) {
+ ctre::phoenix::StatusCode status =
+ falcon->talon()->SetControl(right_control);
+
+ if (!status.IsOK()) {
+ AOS_LOG(ERROR, "Failed to write control to falcon: %s: %s",
+ status.GetName(), status.GetDescription());
+ }
+ }
+ }
+
+ void Stop() override {
+ AOS_LOG(WARNING, "drivetrain output too old\n");
+ ctre::phoenix6::controls::DutyCycleOut stop_command(0.0);
+ stop_command.UpdateFreqHz = 0_Hz;
+ stop_command.EnableFOC = true;
+
+ for (auto falcon : {right_front_.get(), right_back_.get(),
+ left_front_.get(), left_back_.get()}) {
+ falcon->talon()->SetControl(stop_command);
+ }
+ }
+
+ double SafeSpeed(double voltage) {
+ return (::aos::Clip(voltage, -kMaxBringupPower, kMaxBringupPower) / 12.0);
+ }
+
+ ctre::phoenix6::signals::InvertedValue left_inverted_, right_inverted_;
+ std::shared_ptr<Falcon> right_front_, right_back_, left_front_, left_back_;
+};
+
+class WPILibRobot : public ::frc971::wpilib::WPILibRobotBase {
+ public:
+ ::std::unique_ptr<frc::Encoder> make_encoder(int index) {
+ return make_unique<frc::Encoder>(10 + index * 2, 11 + index * 2, false,
+ frc::Encoder::k4X);
+ }
+
+ void Run() override {
+ std::shared_ptr<const Values> values =
+ std::make_shared<const Values>(constants::MakeValues());
+
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig("aos_config.json");
+
+ // Thread 1.
+ ::aos::ShmEventLoop joystick_sender_event_loop(&config.message());
+ ::frc971::wpilib::JoystickSender joystick_sender(
+ &joystick_sender_event_loop);
+ AddLoop(&joystick_sender_event_loop);
+
+ // Thread 2.
+ ::aos::ShmEventLoop pdp_fetcher_event_loop(&config.message());
+ ::frc971::wpilib::PDPFetcher pdp_fetcher(&pdp_fetcher_event_loop);
+ AddLoop(&pdp_fetcher_event_loop);
+
+ std::shared_ptr<frc::DigitalOutput> superstructure_reading =
+ make_unique<frc::DigitalOutput>(25);
+
+ std::vector<ctre::phoenix6::BaseStatusSignal *> signals_registry;
+ std::shared_ptr<Falcon> right_front =
+ std::make_shared<Falcon>(1, "Drivetrain Bus", &signals_registry);
+ std::shared_ptr<Falcon> right_back =
+ std::make_shared<Falcon>(2, "Drivetrain Bus", &signals_registry);
+ std::shared_ptr<Falcon> left_front =
+ std::make_shared<Falcon>(4, "Drivetrain Bus", &signals_registry);
+ std::shared_ptr<Falcon> left_back =
+ std::make_shared<Falcon>(5, "Drivetrain Bus", &signals_registry);
+ std::shared_ptr<Falcon> roller_falcon =
+ std::make_shared<Falcon>(13, "Drivetrain Bus", &signals_registry);
+
+ // Thread 3.
+ ::aos::ShmEventLoop can_sensor_reader_event_loop(&config.message());
+ can_sensor_reader_event_loop.set_name("CANSensorReader");
+ CANSensorReader can_sensor_reader(&can_sensor_reader_event_loop,
+ std::move(signals_registry));
+
+ can_sensor_reader.set_falcons(right_front, right_back, left_front,
+ left_back, roller_falcon);
+
+ AddLoop(&can_sensor_reader_event_loop);
+
+ // Thread 4.
+ ::aos::ShmEventLoop sensor_reader_event_loop(&config.message());
+ SensorReader sensor_reader(&sensor_reader_event_loop, values,
+ &can_sensor_reader);
+ sensor_reader.set_pwm_trigger(true);
+ sensor_reader.set_drivetrain_left_encoder(make_encoder(1));
+ sensor_reader.set_drivetrain_right_encoder(make_encoder(0));
+ sensor_reader.set_superstructure_reading(superstructure_reading);
+ sensor_reader.set_yaw_rate_input(make_unique<frc::DigitalInput>(0));
+
+ AddLoop(&sensor_reader_event_loop);
+
+ // Thread 5.
+ // Set up CAN.
+ if (!FLAGS_ctre_diag_server) {
+ c_Phoenix_Diagnostics_SetSecondsToStart(-1);
+ c_Phoenix_Diagnostics_Dispose();
+ }
+
+ ctre::phoenix::platform::can::CANComm_SetRxSchedPriority(
+ constants::Values::kDrivetrainRxPriority, true, "Drivetrain Bus");
+ ctre::phoenix::platform::can::CANComm_SetTxSchedPriority(
+ constants::Values::kDrivetrainTxPriority, true, "Drivetrain Bus");
+
+ ::aos::ShmEventLoop can_output_event_loop(&config.message());
+ can_output_event_loop.set_name("CANOutputWriter");
+ DrivetrainWriter drivetrain_writer(&can_output_event_loop);
+
+ drivetrain_writer.set_falcons(right_front, right_back, left_front,
+ left_back);
+ drivetrain_writer.set_right_inverted(
+ ctre::phoenix6::signals::InvertedValue::Clockwise_Positive);
+ drivetrain_writer.set_left_inverted(
+ ctre::phoenix6::signals::InvertedValue::CounterClockwise_Positive);
+
+ can_output_event_loop.MakeWatcher(
+ "/roborio",
+ [&drivetrain_writer](const frc971::CANConfiguration &configuration) {
+ drivetrain_writer.HandleCANConfiguration(configuration);
+ });
+
+ AddLoop(&can_output_event_loop);
+
+ // Thread 6
+ // Set up superstructure output.
+ ::aos::ShmEventLoop output_event_loop(&config.message());
+ output_event_loop.set_name("PWMOutputWriter");
+ SuperstructureWriter superstructure_writer(&output_event_loop);
+
+ superstructure_writer.set_superstructure_reading(superstructure_reading);
+
+ AddLoop(&output_event_loop);
+
+ // Thread 7
+ // Set up led_indicator.
+ ::aos::ShmEventLoop led_indicator_event_loop(&config.message());
+ led_indicator_event_loop.set_name("LedIndicator");
+ control_loops::superstructure::LedIndicator led_indicator(
+ &led_indicator_event_loop);
+ AddLoop(&led_indicator_event_loop);
+
+ RunLoops();
+ }
+};
+
+} // namespace wpilib
+} // namespace y2023_bot3
+
+AOS_ROBOT_CLASS(::y2023_bot3::wpilib::WPILibRobot);
diff --git a/y2023_bot3/www/BUILD b/y2023_bot3/www/BUILD
new file mode 100644
index 0000000..50367ba
--- /dev/null
+++ b/y2023_bot3/www/BUILD
@@ -0,0 +1,22 @@
+load("//frc971/downloader:downloader.bzl", "aos_downloader_dir")
+
+filegroup(
+ name = "files",
+ srcs = glob([
+ "**/*.html",
+ "**/*.css",
+ "**/*.png",
+ ]),
+ visibility = ["//visibility:public"],
+)
+
+aos_downloader_dir(
+ name = "www_files",
+ srcs = [
+ ":files",
+ "//frc971/analysis:plot_index_bundle.min.js",
+ ],
+ dir = "www",
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+)
diff --git a/y2023_bot3/www/constants.ts b/y2023_bot3/www/constants.ts
new file mode 100644
index 0000000..d6ecfaf
--- /dev/null
+++ b/y2023_bot3/www/constants.ts
@@ -0,0 +1,8 @@
+// Conversion constants to meters
+export const IN_TO_M = 0.0254;
+export const FT_TO_M = 0.3048;
+// Dimensions of the field in meters
+// Numbers are slightly hand-tuned to match the PNG that we are using.
+export const FIELD_WIDTH = 26 * FT_TO_M + 7.25 * IN_TO_M;
+export const FIELD_LENGTH = 54 * FT_TO_M + 5.25 * IN_TO_M;
+
diff --git a/y2023_bot3/www/field.html b/y2023_bot3/www/field.html
new file mode 100644
index 0000000..ee512d3
--- /dev/null
+++ b/y2023_bot3/www/field.html
@@ -0,0 +1,63 @@
+<html>
+ <head>
+ <script src="field_main_bundle.min.js" defer></script>
+ <link rel="stylesheet" href="styles.css">
+ </head>
+ <body>
+ <div id="field"> </div>
+ <div id="legend"> </div>
+ <div id="readouts">
+ <table>
+ <tr>
+ <th colspan="2">Robot State</th>
+ </tr>
+ <tr>
+ <td>X</td>
+ <td id="x"> NA </td>
+ </tr>
+ <tr>
+ <td>Y</td>
+ <td id="y"> NA </td>
+ </tr>
+ <tr>
+ <td>Theta</td>
+ <td id="theta"> NA </td>
+ </tr>
+ </table>
+
+ <table>
+ <tr>
+ <th colspan="2">Superstructure</th>
+ </tr>
+ </table>
+ <table>
+ <tr>
+ <th colspan="2">Game Piece</th>
+ </tr>
+ <tr>
+ <td>Game Piece Held</td>
+ <td id="game_piece"> NA </td>
+ </tr>
+ <tr>
+ <td>Game Piece Position (+ = left, 0 = empty)</td>
+ <td id="game_piece_position"> NA </td>
+ </tr>
+ </table>
+
+ <h3>Zeroing Faults:</h3>
+ <p id="zeroing_faults"> NA </p>
+ </div>
+ <div id="middle_readouts">
+ <div id="vision_readouts">
+ </div>
+ <div id="message_bridge_status">
+ <div>
+ <div>Node</div>
+ <div>Client</div>
+ <div>Server</div>
+ </div>
+ </div>
+ </div>
+ </body>
+</html>
+
diff --git a/y2023_bot3/www/field_handler.ts b/y2023_bot3/www/field_handler.ts
new file mode 100644
index 0000000..809bc5d
--- /dev/null
+++ b/y2023_bot3/www/field_handler.ts
@@ -0,0 +1,185 @@
+import {ByteBuffer} from 'flatbuffers'
+import {ClientStatistics} from '../../aos/network/message_bridge_client_generated'
+import {ServerStatistics, State as ConnectionState} from '../../aos/network/message_bridge_server_generated'
+import {Connection} from '../../aos/network/www/proxy'
+import {ZeroingError} from '../../frc971/control_loops/control_loops_generated'
+import {Status as DrivetrainStatus} from '../../frc971/control_loops/drivetrain/drivetrain_status_generated'
+import {LocalizerOutput} from '../../frc971/control_loops/drivetrain/localization/localizer_output_generated'
+
+import {FIELD_LENGTH, FIELD_WIDTH, FT_TO_M, IN_TO_M} from './constants';
+
+// (0,0) is field center, +X is toward red DS
+const FIELD_SIDE_Y = FIELD_WIDTH / 2;
+const FIELD_EDGE_X = FIELD_LENGTH / 2;
+
+const ROBOT_WIDTH = 25 * IN_TO_M;
+const ROBOT_LENGTH = 32 * IN_TO_M;
+
+export class FieldHandler {
+ private canvas = document.createElement('canvas');
+ private localizerOutput: LocalizerOutput|null = null;
+ private drivetrainStatus: DrivetrainStatus|null = null;
+
+ private handleDrivetrainStatus(data: Uint8Array): void {
+ const fbBuffer = new ByteBuffer(data);
+ this.drivetrainStatus = DrivetrainStatus.getRootAsStatus(fbBuffer);
+ }
+
+ private setCurrentNodeState(element: HTMLElement, state: ConnectionState):
+ void {
+ if (state === ConnectionState.CONNECTED) {
+ element.innerHTML = ConnectionState[state];
+ element.classList.remove('faulted');
+ element.classList.add('connected');
+ } else {
+ element.innerHTML = ConnectionState[state];
+ element.classList.remove('connected');
+ element.classList.add('faulted');
+ }
+ }
+
+ private handleServerStatistics(data: Uint8Array): void {
+ const fbBuffer = new ByteBuffer(data);
+ const serverStatistics =
+ ServerStatistics.getRootAsServerStatistics(fbBuffer);
+
+ for (let ii = 0; ii < serverStatistics.connectionsLength(); ++ii) {
+ const connection = serverStatistics.connections(ii);
+ const nodeName = connection.node().name();
+ if (!this.serverStatuses.has(nodeName)) {
+ this.populateNodeConnections(nodeName);
+ }
+ this.setCurrentNodeState(
+ this.serverStatuses.get(nodeName), connection.state());
+ }
+ }
+
+ private handleClientStatistics(data: Uint8Array): void {
+ const fbBuffer = new ByteBuffer(data);
+ const clientStatistics =
+ ClientStatistics.getRootAsClientStatistics(fbBuffer);
+
+ for (let ii = 0; ii < clientStatistics.connectionsLength(); ++ii) {
+ const connection = clientStatistics.connections(ii);
+ const nodeName = connection.node().name();
+ if (!this.clientStatuses.has(nodeName)) {
+ this.populateNodeConnections(nodeName);
+ }
+ this.setCurrentNodeState(
+ this.clientStatuses.get(nodeName), connection.state());
+ }
+ }
+
+ drawField(): void {
+ const ctx = this.canvas.getContext('2d');
+ ctx.save();
+ ctx.scale(1.0, -1.0);
+ ctx.restore();
+ }
+
+ drawCamera(x: number, y: number, theta: number, color: string = 'blue'):
+ void {
+ const ctx = this.canvas.getContext('2d');
+ ctx.save();
+ ctx.translate(x, y);
+ ctx.rotate(theta);
+ ctx.strokeStyle = color;
+ ctx.beginPath();
+ ctx.moveTo(0.5, 0.5);
+ ctx.lineTo(0, 0);
+ ctx.lineTo(0.5, -0.5);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(0, 0, 0.25, -Math.PI / 4, Math.PI / 4);
+ ctx.stroke();
+ ctx.restore();
+ }
+
+ drawRobot(
+ x: number, y: number, theta: number, color: string = 'blue',
+ dashed: boolean = false): void {
+ const ctx = this.canvas.getContext('2d');
+ ctx.save();
+ ctx.translate(x, y);
+ ctx.rotate(theta);
+ ctx.strokeStyle = color;
+ ctx.lineWidth = ROBOT_WIDTH / 10.0;
+ if (dashed) {
+ ctx.setLineDash([0.05, 0.05]);
+ } else {
+ // Empty array = solid line.
+ ctx.setLineDash([]);
+ }
+ ctx.rect(-ROBOT_LENGTH / 2, -ROBOT_WIDTH / 2, ROBOT_LENGTH, ROBOT_WIDTH);
+ ctx.stroke();
+
+ // Draw line indicating which direction is forwards on the robot.
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(ROBOT_LENGTH / 2.0, 0);
+ ctx.stroke();
+
+ ctx.restore();
+ }
+
+ setZeroing(div: HTMLElement): void {
+ div.innerHTML = 'zeroing';
+ div.classList.remove('faulted');
+ div.classList.add('zeroing');
+ div.classList.remove('near');
+ }
+
+ setEstopped(div: HTMLElement): void {
+ div.innerHTML = 'estopped';
+ div.classList.add('faulted');
+ div.classList.remove('zeroing');
+ div.classList.remove('near');
+ }
+
+ setValue(div: HTMLElement, val: number): void {
+ div.innerHTML = val.toFixed(4);
+ div.classList.remove('faulted');
+ div.classList.remove('zeroing');
+ div.classList.remove('near');
+ }
+
+ draw(): void {
+ this.reset();
+ this.drawField();
+
+ // Draw the matches with debugging information from the localizer.
+ const now = Date.now() / 1000.0;
+
+ if (this.drivetrainStatus && this.drivetrainStatus.trajectoryLogging()) {
+ this.drawRobot(
+ this.drivetrainStatus.trajectoryLogging().x(),
+ this.drivetrainStatus.trajectoryLogging().y(),
+ this.drivetrainStatus.trajectoryLogging().theta(), '#000000FF',
+ false);
+ }
+
+ window.requestAnimationFrame(() => this.draw());
+ }
+
+ reset(): void {
+ const ctx = this.canvas.getContext('2d');
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ const size = window.innerHeight * 0.9;
+ ctx.canvas.height = size;
+ const width = size / 2 + 20;
+ ctx.canvas.width = width;
+ ctx.clearRect(0, 0, size, width);
+
+ // Translate to center of display.
+ ctx.translate(width / 2, size / 2);
+ // Coordinate system is:
+ // x -> forward.
+ // y -> to the left.
+ ctx.rotate(-Math.PI / 2);
+ ctx.scale(1, -1);
+
+ const M_TO_PX = (size - 10) / FIELD_LENGTH;
+ ctx.scale(M_TO_PX, M_TO_PX);
+ ctx.lineWidth = 1 / M_TO_PX;
+ }
+}
diff --git a/y2023_bot3/www/field_main.ts b/y2023_bot3/www/field_main.ts
new file mode 100644
index 0000000..d71a45e
--- /dev/null
+++ b/y2023_bot3/www/field_main.ts
@@ -0,0 +1,12 @@
+import {Connection} from '../../aos/network/www/proxy';
+
+import {FieldHandler} from './field_handler';
+
+const conn = new Connection();
+
+conn.connect();
+
+const fieldHandler = new FieldHandler(conn);
+
+fieldHandler.draw();
+
diff --git a/y2023_bot3/www/index.html b/y2023_bot3/www/index.html
new file mode 100644
index 0000000..e4e185e
--- /dev/null
+++ b/y2023_bot3/www/index.html
@@ -0,0 +1,6 @@
+<html>
+ <body>
+ <a href="field.html">Field Visualization</a><br>
+ <a href="plotter.html">Plots</a>
+ </body>
+</html>
diff --git a/y2023_bot3/www/plotter.html b/y2023_bot3/www/plotter.html
new file mode 100644
index 0000000..629ceaa
--- /dev/null
+++ b/y2023_bot3/www/plotter.html
@@ -0,0 +1,7 @@
+<html>
+ <head>
+ <script src="plot_index_bundle.min.js" defer></script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/y2023_bot3/www/styles.css b/y2023_bot3/www/styles.css
new file mode 100644
index 0000000..c2c44d2
--- /dev/null
+++ b/y2023_bot3/www/styles.css
@@ -0,0 +1,74 @@
+.channel {
+ display: flex;
+ border-bottom: 1px solid;
+ font-size: 24px;
+}
+#field {
+ display: inline-block
+}
+
+#readouts,
+#middle_readouts
+{
+ display: inline-block;
+ vertical-align: top;
+ float: right;
+}
+
+
+#legend {
+ display: inline-block;
+}
+
+table, th, td {
+ border: 1px solid black;
+ border-collapse: collapse;
+ padding: 5px;
+ margin: 10px;
+}
+
+th, td {
+ text-align: right;
+ width: 70px;
+}
+
+td:first-child {
+ width: 150px;
+}
+
+.connected, .near {
+ background-color: LightGreen;
+ border-radius: 10px;
+}
+
+.zeroing {
+ background-color: yellow;
+ border-radius: 10px;
+}
+
+.faulted {
+ background-color: red;
+ border-radius: 10px;
+}
+
+#vision_readouts > div {
+ display: table-row;
+ padding: 5px;
+}
+
+#vision_readouts > div > div {
+ display: table-cell;
+ padding: 5px;
+ text-align: right;
+}
+
+#message_bridge_status > div {
+ display: table-row;
+ padding: 5px;
+}
+
+#message_bridge_status > div > div {
+ display: table-cell;
+ padding: 5px;
+ text-align: right;
+}
diff --git a/y2023_bot3/y2023_bot3.json b/y2023_bot3/y2023_bot3.json
new file mode 100644
index 0000000..36085de
--- /dev/null
+++ b/y2023_bot3/y2023_bot3.json
@@ -0,0 +1,18 @@
+{
+ "channel_storage_duration": 10000000000,
+ "maps": [
+ {
+ "match": {
+ "name": "/aos",
+ "type": "aos.RobotState"
+ },
+ "rename": {
+ "name": "/roborio/aos"
+ }
+ }
+ ],
+ "imports": [
+ "y2023_bot3_roborio.json",
+ "y2023_bot3_imu.json"
+ ]
+}
diff --git a/y2023_bot3/y2023_bot3_imu.json b/y2023_bot3/y2023_bot3_imu.json
new file mode 100644
index 0000000..5e744a7
--- /dev/null
+++ b/y2023_bot3/y2023_bot3_imu.json
@@ -0,0 +1,270 @@
+{
+ "channels": [
+ {
+ "name": "/imu/aos",
+ "type": "aos.timing.Report",
+ "source_node": "imu",
+ "frequency": 50,
+ "num_senders": 20,
+ "max_size": 4096
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.logging.LogMessageFbs",
+ "source_node": "imu",
+ "frequency": 200,
+ "num_senders": 20
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.starter.Status",
+ "source_node": "imu",
+ "frequency": 50,
+ "num_senders": 20,
+ "max_size": 2048
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.starter.StarterRpc",
+ "source_node": "imu",
+ "frequency": 10,
+ "num_senders": 2
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.message_bridge.ServerStatistics",
+ "source_node": "imu",
+ "frequency": 10,
+ "num_senders": 2,
+ "max_size": 1504
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.message_bridge.ClientStatistics",
+ "source_node": "imu",
+ "frequency": 20,
+ "num_senders": 2
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.logging.DynamicLogCommand",
+ "source_node": "imu",
+ "frequency": 10,
+ "num_senders": 2
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.message_bridge.Timestamp",
+ "source_node": "imu",
+ "frequency": 15,
+ "num_senders": 2,
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "roborio",
+ ],
+ "max_size": 400,
+ "destination_nodes": [
+ {
+ "name": "roborio",
+ "priority": 1,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "imu"
+ ],
+ "time_to_live": 5000000
+ },
+ ]
+ },
+ {
+ "name": "/imu/aos/remote_timestamps/roborio/imu/aos/aos-message_bridge-Timestamp",
+ "type": "aos.message_bridge.RemoteMessage",
+ "frequency": 20,
+ "source_node": "imu",
+ "max_size": 208
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.starter.StarterRpc",
+ "source_node": "roborio",
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "imu"
+ ],
+ "destination_nodes": [
+ {
+ "name": "imu",
+ "priority": 5,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "roborio"
+ ],
+ "time_to_live": 5000000
+ }
+ ]
+ },
+ {
+ "name": "/roborio/aos/remote_timestamps/imu/roborio/aos/aos-starter-StarterRpc",
+ "type": "aos.message_bridge.RemoteMessage",
+ "source_node": "roborio",
+ "logger": "NOT_LOGGED",
+ "frequency": 20,
+ "num_senders": 2,
+ "max_size": 200
+ },
+ {
+ "name": "/localizer",
+ "type": "frc971.IMUValuesBatch",
+ "source_node": "imu",
+ "frequency": 2200,
+ "max_size": 1600,
+ "num_senders": 2
+ },
+ {
+ "name": "/localizer",
+ "type": "frc971.controls.LocalizerOutput",
+ "source_node": "imu",
+ "frequency": 52,
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "roborio"
+ ],
+ "destination_nodes": [
+ {
+ "name": "roborio",
+ "priority": 5,
+ "time_to_live": 5000000,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "imu"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "/imu/aos/remote_timestamps/roborio/localizer/frc971-controls-LocalizerOutput",
+ "type": "aos.message_bridge.RemoteMessage",
+ "source_node": "imu",
+ "logger": "NOT_LOGGED",
+ "frequency": 52,
+ "num_senders": 2,
+ "max_size": 200
+ },
+ {
+ "name": "/imu/constants",
+ "type": "y2023_bot3.Constants",
+ "source_node": "imu",
+ "frequency": 1,
+ "num_senders": 2,
+ "max_size": 65536
+ }
+ ],
+ "applications": [
+ {
+ "name": "message_bridge_client",
+ "nodes": [
+ "imu"
+ ]
+ },
+ {
+ "name": "imu",
+ "executable_name": "imu_main",
+ "user": "pi",
+ "nodes": [
+ "imu"
+ ]
+ },
+ {
+ "name": "joystick_republish",
+ "executable_name": "joystick_republish",
+ "user": "pi",
+ "nodes": [
+ "imu"
+ ]
+ },
+ {
+ "name": "message_bridge_server",
+ "executable_name": "message_bridge_server",
+ "user": "pi",
+ "nodes": [
+ "imu"
+ ]
+ },
+ {
+ "name": "localizer_logger",
+ "executable_name": "logger_main",
+ "args": [
+ "--logging_folder",
+ "",
+ "--snappy_compress",
+ "--rotate_every", "30.0"
+ ],
+ "user": "pi",
+ "nodes": [
+ "imu"
+ ]
+ },
+ {
+ "name": "web_proxy",
+ "executable_name": "web_proxy_main",
+ "args": [
+ "--min_ice_port=5800",
+ "--max_ice_port=5810"
+ ],
+ "user": "pi",
+ "nodes": [
+ "imu"
+ ]
+ },
+ {
+ "name": "foxglove_websocket",
+ "user": "pi",
+ "nodes": [
+ "imu"
+ ]
+ },
+ {
+ "name": "constants_sender",
+ "autorestart": false,
+ "user": "pi",
+ "nodes": [
+ "imu"
+ ]
+ }
+ ],
+ "maps": [
+ {
+ "match": {
+ "name": "/constants*",
+ "source_node": "imu"
+ },
+ "rename": {
+ "name": "/imu/constants"
+ }
+ },
+ {
+ "match": {
+ "name": "/aos*",
+ "source_node": "imu"
+ },
+ "rename": {
+ "name": "/imu/aos"
+ }
+ }
+ ],
+ "nodes": [
+ {
+ "name": "imu",
+ "hostname": "pi6",
+ "hostnames": [
+ "pi-971-6",
+ "pi-7971-6",
+ "pi-8971-6",
+ "pi-9971-6"
+ ],
+ "port": 9971
+ },
+ {
+ "name": "roborio"
+ }
+ ]
+}
diff --git a/y2023_bot3/y2023_bot3_roborio.json b/y2023_bot3/y2023_bot3_roborio.json
new file mode 100644
index 0000000..4ae02d6
--- /dev/null
+++ b/y2023_bot3/y2023_bot3_roborio.json
@@ -0,0 +1,465 @@
+{
+ "channels": [
+ {
+ "name": "/roborio/aos",
+ "type": "aos.JoystickState",
+ "source_node": "roborio",
+ "frequency": 100,
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "imu"
+ ],
+ "destination_nodes": [
+ {
+ "name": "imu",
+ "priority": 5,
+ "time_to_live": 50000000
+ }
+ ]
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.RobotState",
+ "source_node": "roborio",
+ "frequency": 250
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.timing.Report",
+ "source_node": "roborio",
+ "frequency": 50,
+ "num_senders": 20,
+ "max_size": 8192
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.logging.LogMessageFbs",
+ "source_node": "roborio",
+ "frequency": 500,
+ "max_size": 1504,
+ "num_senders": 20
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.starter.Status",
+ "source_node": "roborio",
+ "frequency": 50,
+ "num_senders": 20,
+ "max_size": 2000
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.starter.StarterRpc",
+ "source_node": "roborio",
+ "frequency": 10,
+ "max_size": 400,
+ "num_senders": 2
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.message_bridge.ServerStatistics",
+ "source_node": "roborio",
+ "frequency": 10,
+ "num_senders": 2,
+ "max_size": 1504
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.message_bridge.ClientStatistics",
+ "source_node": "roborio",
+ "frequency": 20,
+ "max_size": 2000,
+ "num_senders": 2
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.logging.DynamicLogCommand",
+ "source_node": "roborio",
+ "frequency": 10,
+ "num_senders": 2
+ },
+ {
+ "name": "/roborio/aos/remote_timestamps/imu/roborio/aos/aos-message_bridge-Timestamp",
+ "type": "aos.message_bridge.RemoteMessage",
+ "frequency": 20,
+ "source_node": "roborio",
+ "max_size": 208
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.message_bridge.Timestamp",
+ "source_node": "roborio",
+ "frequency": 15,
+ "num_senders": 2,
+ "max_size": 512,
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "imu"
+ ],
+ "destination_nodes": [
+ {
+ "name": "imu",
+ "priority": 1,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "roborio"
+ ],
+ "time_to_live": 5000000
+ }
+ ]
+ },
+ {
+ "name": "/superstructure",
+ "type": "y2023_bot3.control_loops.superstructure.Goal",
+ "source_node": "roborio",
+ "frequency": 250,
+ "max_size": 512
+ },
+ {
+ "name": "/superstructure",
+ "type": "y2023_bot3.control_loops.superstructure.Status",
+ "source_node": "roborio",
+ "frequency": 400,
+ "num_senders": 2
+ },
+ {
+ "name": "/superstructure",
+ "type": "y2023_bot3.control_loops.superstructure.Output",
+ "source_node": "roborio",
+ "frequency": 250,
+ "num_senders": 2,
+ "max_size": 224
+ },
+ {
+ "name": "/superstructure",
+ "type": "y2023_bot3.control_loops.superstructure.Position",
+ "source_node": "roborio",
+ "frequency": 250,
+ "num_senders": 2,
+ "max_size": 448
+ },
+ {
+ "name": "/can",
+ "type": "frc971.can_logger.CanFrame",
+ "source_node": "roborio",
+ "frequency": 6000,
+ "num_senders": 2,
+ "max_size": 200
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.CANPosition",
+ "source_node": "roborio",
+ "frequency": 220,
+ "num_senders": 2,
+ "max_size": 400
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.sensors.GyroReading",
+ "source_node": "roborio",
+ "frequency": 250,
+ "num_senders": 2
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.sensors.Uid",
+ "source_node": "roborio",
+ "frequency": 250,
+ "num_senders": 2
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.fb.Trajectory",
+ "source_node": "roborio",
+ "max_size": 600000,
+ "frequency": 10,
+ "logger": "NOT_LOGGED",
+ "num_senders": 2,
+ "read_method": "PIN",
+ "num_readers": 10
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.SplineGoal",
+ "source_node": "roborio",
+ "frequency": 10
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.Goal",
+ "source_node": "roborio",
+ "max_size": 224,
+ "frequency": 250
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.Position",
+ "source_node": "roborio",
+ "frequency": 400,
+ "max_size": 112,
+ "num_senders": 2
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.Output",
+ "source_node": "roborio",
+ "frequency": 400,
+ "max_size": 80,
+ "num_senders": 2,
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "imu"
+ ],
+ "destination_nodes": [
+ {
+ "name": "imu",
+ "priority": 5,
+ "time_to_live": 5000000
+ }
+ ]
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.Status",
+ "source_node": "roborio",
+ "frequency": 400,
+ "max_size": 1616,
+ "num_senders": 2
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.LocalizerControl",
+ "source_node": "roborio",
+ "frequency": 250,
+ "max_size": 96,
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "imu"
+ ],
+ "destination_nodes": [
+ {
+ "name": "imu",
+ "priority": 5,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "roborio"
+ ],
+ "time_to_live": 0
+ }
+ ]
+ },
+ {
+ "name": "/roborio/aos/remote_timestamps/imu/drivetrain/frc971-control_loops-drivetrain-LocalizerControl",
+ "type": "aos.message_bridge.RemoteMessage",
+ "source_node": "roborio",
+ "logger": "NOT_LOGGED",
+ "frequency": 400,
+ "num_senders": 2,
+ "max_size": 200
+ },
+ {
+ "name": "/autonomous",
+ "type": "aos.common.actions.Status",
+ "source_node": "roborio"
+ },
+ {
+ "name": "/autonomous",
+ "type": "frc971.autonomous.Goal",
+ "source_node": "roborio"
+ },
+ {
+ "name": "/autonomous",
+ "type": "frc971.autonomous.AutonomousMode",
+ "source_node": "roborio",
+ "frequency": 250
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "frc971.PDPValues",
+ "source_node": "roborio",
+ "frequency": 55,
+ "max_size": 368
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "frc971.wpilib.PneumaticsToLog",
+ "source_node": "roborio",
+ "frequency": 50
+ },
+ {
+ "name": "/roborio",
+ "type": "frc971.CANConfiguration",
+ "source_node": "roborio",
+ "frequency": 2
+ },
+ {
+ "name": "/roborio/constants",
+ "type": "y2023_bot3.Constants",
+ "source_node": "roborio",
+ "frequency": 1,
+ "num_senders": 2,
+ "max_size": 65536
+ }
+ ],
+ "applications": [
+ {
+ "name": "drivetrain",
+ "executable_name": "drivetrain",
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "trajectory_generator",
+ "executable_name": "trajectory_generator",
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "superstructure",
+ "executable_name": "superstructure",
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "roborio_irq_affinity",
+ "executable_name": "irq_affinity",
+ "args": [
+ "--irq_config=/home/admin/bin/roborio_irq_config.json"
+ ],
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "joystick_reader",
+ "executable_name": "joystick_reader",
+ "args": [
+ "--nodie_on_malloc"
+ ],
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "wpilib_interface",
+ "executable_name": "wpilib_interface",
+ "args": [
+ "--nodie_on_malloc"
+ ],
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "autonomous_action",
+ "executable_name": "autonomous_action",
+ "args": [
+ "--nodie_on_malloc"
+ ],
+ "autostart": true,
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "roborio_web_proxy",
+ "executable_name": "web_proxy_main",
+ "args": [
+ "--min_ice_port=5800",
+ "--max_ice_port=5810"
+ ],
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "roborio_message_bridge_client",
+ "executable_name": "message_bridge_client",
+ "args": [
+ "--rt_priority=16",
+ "--sinit_max_init_timeout=5000"
+ ],
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "roborio_message_bridge_server",
+ "executable_name": "message_bridge_server",
+ "args": [
+ "--rt_priority=16"
+ ],
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "logger",
+ "executable_name": "logger_main",
+ "args": [
+ "--snappy_compress",
+ "--logging_folder=/home/admin/logs/",
+ "--rotate_every", "30.0"
+ ],
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "constants_sender_roborio",
+ "executable_name": "constants_sender",
+ "autorestart": false,
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "can_logger",
+ "executable_name": "can_logger",
+ "nodes": [
+ "roborio"
+ ]
+ }
+ ],
+ "maps": [
+ {
+ "match": {
+ "name": "/constants*",
+ "source_node": "roborio"
+ },
+ "rename": {
+ "name": "/roborio/constants"
+ }
+ },
+ {
+ "match": {
+ "name": "/aos*",
+ "source_node": "roborio"
+ },
+ "rename": {
+ "name": "/roborio/aos"
+ }
+ }
+ ],
+ "nodes": [
+ {
+ "name": "roborio",
+ "hostname": "roborio",
+ "hostnames": [
+ "roboRIO-971-FRC",
+ "roboRIO-6971-FRC",
+ "roboRIO-7971-FRC",
+ "roboRIO-8971-FRC",
+ "roboRIO-9971-FRC"
+ ],
+ "port": 9971
+ },
+ {
+ "name": "imu"
+ },
+ ]
+}
diff --git a/y2023_bot4/BUILD b/y2023_bot4/BUILD
new file mode 100644
index 0000000..1a4ed64
--- /dev/null
+++ b/y2023_bot4/BUILD
@@ -0,0 +1,234 @@
+load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_cc_library")
+load("//frc971:downloader.bzl", "robot_downloader")
+load("//aos:config.bzl", "aos_config")
+load("//aos/util:config_validator_macro.bzl", "config_validator_test")
+
+config_validator_test(
+ name = "config_validator_test",
+ config = "//y2023_bot4:aos_config",
+)
+
+robot_downloader(
+ binaries = [
+ "//aos/network:web_proxy_main",
+ "//aos/events/logging:log_cat",
+ "//aos/events:aos_timing_report_streamer",
+ ],
+ data = [
+ ":aos_config",
+ ":swerve_publisher_output_json",
+ "@ctre_phoenix6_api_cpp_athena//:shared_libraries",
+ "@ctre_phoenix6_tools_athena//:shared_libraries",
+ "@ctre_phoenix_api_cpp_athena//:shared_libraries",
+ "@ctre_phoenix_cci_athena//:shared_libraries",
+ ],
+ start_binaries = [
+ "//aos/events/logging:logger_main",
+ "//aos/network:web_proxy_main",
+ "//aos/starter:irq_affinity",
+ ":wpilib_interface",
+ ":swerve_publisher",
+ "//frc971/can_logger",
+ "//aos/network:message_bridge_client",
+ "//aos/network:message_bridge_server",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+)
+
+robot_downloader(
+ name = "pi_download",
+ binaries = [
+ "//aos/util:foxglove_websocket",
+ "//aos/events:aos_timing_report_streamer",
+ "//aos/events/logging:log_cat",
+ "//y2023/rockpi:imu_main",
+ "//frc971/image_streamer:image_streamer",
+ "//aos/network:message_bridge_client",
+ "//aos/network:message_bridge_server",
+ "//aos/network:web_proxy_main",
+ "//aos/starter:irq_affinity",
+ "//aos/events/logging:logger_main",
+ ],
+ data = [
+ ":aos_config",
+ "//frc971/rockpi:rockpi_config.json",
+ ],
+ start_binaries = [
+ ],
+ target_compatible_with = ["//tools/platforms/hardware:raspberry_pi"],
+ target_type = "pi",
+)
+
+filegroup(
+ name = "swerve_publisher_output_json",
+ srcs = [
+ "swerve_drivetrain_output.json",
+ ],
+ visibility = ["//y2023_bot4:__subpackages__"],
+)
+
+cc_library(
+ name = "constants",
+ srcs = ["constants.cc"],
+ hdrs = [
+ "constants.h",
+ ],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//aos/network:team_number",
+ "//frc971:constants",
+ ],
+)
+
+flatbuffer_cc_library(
+ name = "drivetrain_position_fbs",
+ srcs = ["drivetrain_position.fbs"],
+ gen_reflections = 1,
+ deps = ["//frc971/control_loops:control_loops_fbs"],
+)
+
+flatbuffer_cc_library(
+ name = "drivetrain_can_position_fbs",
+ srcs = ["drivetrain_can_position.fbs"],
+ gen_reflections = 1,
+ deps = ["//frc971/control_loops:can_falcon_fbs"],
+)
+
+cc_binary(
+ name = "swerve_publisher",
+ srcs = ["swerve_publisher_main.cc"],
+ deps = [
+ ":swerve_publisher_lib",
+ "//aos/events:shm_event_loop",
+ "@com_github_gflags_gflags//:gflags",
+ ],
+)
+
+cc_library(
+ name = "swerve_publisher_lib",
+ srcs = ["swerve_publisher_lib.cc"],
+ hdrs = ["swerve_publisher_lib.h"],
+ deps = [
+ "//aos:init",
+ "//aos/events:event_loop",
+ "//frc971/control_loops/drivetrain/swerve:swerve_drivetrain_output_fbs",
+ "@com_github_google_glog//:glog",
+ ],
+)
+
+cc_test(
+ name = "swerve_publisher_lib_test",
+ srcs = [
+ "swerve_publisher_lib_test.cc",
+ ],
+ data = [
+ ":aos_config",
+ ":swerve_publisher_output_json",
+ ],
+ deps = [
+ ":swerve_publisher_lib",
+ "//aos/events:simulated_event_loop",
+ "//aos/testing:googletest",
+ ],
+)
+
+cc_binary(
+ name = "wpilib_interface",
+ srcs = ["wpilib_interface.cc"],
+ target_compatible_with = ["//tools/platforms/hardware:roborio"],
+ deps = [
+ ":constants",
+ ":drivetrain_can_position_fbs",
+ ":drivetrain_position_fbs",
+ "//aos:init",
+ "//aos/events:shm_event_loop",
+ "//frc971/control_loops:control_loops_fbs",
+ "//frc971/wpilib:can_sensor_reader",
+ "//frc971/wpilib:falcon",
+ "//frc971/wpilib:sensor_reader",
+ "//frc971/wpilib:wpilib_robot_base",
+ "//frc971/wpilib/swerve:swerve_drivetrain_writer",
+ ],
+)
+
+aos_config(
+ name = "aos_config",
+ src = "y2023_bot4.json",
+ flatbuffers = [
+ "//aos/network:message_bridge_client_fbs",
+ "//aos/network:message_bridge_server_fbs",
+ "//aos/network:timestamp_fbs",
+ "//frc971/input:robot_state_fbs",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":config_imu",
+ ":config_logger",
+ ":config_roborio",
+ ],
+)
+
+aos_config(
+ name = "config_roborio",
+ src = "y2023_bot4_roborio.json",
+ flatbuffers = [
+ ":drivetrain_position_fbs",
+ ":drivetrain_can_position_fbs",
+ "//frc971:can_configuration_fbs",
+ "//aos/network:remote_message_fbs",
+ "//aos/network:message_bridge_client_fbs",
+ "//aos/network:message_bridge_server_fbs",
+ "//aos/network:timestamp_fbs",
+ "//frc971/control_loops/drivetrain/swerve:swerve_drivetrain_output_fbs",
+ "//frc971/control_loops/drivetrain/swerve:swerve_drivetrain_position_fbs",
+ "//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
+ "//frc971/can_logger:can_logging_fbs",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ deps = [
+ "//aos/events:aos_config",
+ "//frc971/autonomous:aos_config",
+ "//frc971/control_loops/drivetrain:aos_config",
+ "//frc971/input:aos_config",
+ "//frc971/wpilib:aos_config",
+ ],
+)
+
+aos_config(
+ name = "config_imu",
+ src = "y2023_bot4_imu.json",
+ flatbuffers = [
+ "//aos/network:message_bridge_client_fbs",
+ "//aos/network:message_bridge_server_fbs",
+ "//aos/network:timestamp_fbs",
+ "//aos/network:remote_message_fbs",
+ "//frc971/vision:target_map_fbs",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//aos/events:aos_config",
+ "//frc971/control_loops/drivetrain:aos_config",
+ ],
+)
+
+aos_config(
+ name = "config_logger",
+ src = "y2023_bot4_logger.json",
+ flatbuffers = [
+ "//aos/network:message_bridge_client_fbs",
+ "//aos/network:message_bridge_server_fbs",
+ "//aos/network:timestamp_fbs",
+ "//aos/network:remote_message_fbs",
+ "//frc971/vision:calibration_fbs",
+ "//frc971/vision:target_map_fbs",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//aos/events:aos_config",
+ "//frc971/control_loops/drivetrain:aos_config",
+ "//frc971/input:aos_config",
+ ],
+)
diff --git a/y2023_bot4/constants.cc b/y2023_bot4/constants.cc
new file mode 100644
index 0000000..aab1935
--- /dev/null
+++ b/y2023_bot4/constants.cc
@@ -0,0 +1,52 @@
+#include "y2023_bot4/constants.h"
+
+#include <cstdint>
+
+#include "glog/logging.h"
+
+#include "aos/network/team_number.h"
+
+namespace y2023_bot4 {
+namespace constants {
+Values MakeValues(uint16_t team) {
+ LOG(INFO) << "creating a Constants for team: " << team;
+ Values r;
+ auto *const front_left_zeroing_constants = &r.front_left_zeroing_constants;
+ auto *const front_right_zeroing_constants = &r.front_right_zeroing_constants;
+ auto *const back_left_zeroing_constants = &r.back_left_zeroing_constants;
+ auto *const back_right_zeroing_constants = &r.back_right_zeroing_constants;
+
+ front_left_zeroing_constants->average_filter_size = 0;
+ front_left_zeroing_constants->one_revolution_distance = 2 * M_PI;
+ front_left_zeroing_constants->measured_absolute_position = 0.76761395509829;
+ front_left_zeroing_constants->zeroing_threshold = 0.0;
+ front_left_zeroing_constants->moving_buffer_size = 0.0;
+ front_left_zeroing_constants->allowable_encoder_error = 0.0;
+
+ front_right_zeroing_constants->average_filter_size = 0;
+ front_right_zeroing_constants->one_revolution_distance = 2 * M_PI;
+ front_right_zeroing_constants->measured_absolute_position = 0.779403958443922;
+ front_right_zeroing_constants->zeroing_threshold = 0.0;
+ front_right_zeroing_constants->moving_buffer_size = 0.0;
+ front_right_zeroing_constants->allowable_encoder_error = 0.0;
+
+ back_left_zeroing_constants->average_filter_size = 0;
+ back_left_zeroing_constants->one_revolution_distance = 2 * M_PI;
+ back_left_zeroing_constants->measured_absolute_position = 0.053439698061417;
+ back_left_zeroing_constants->zeroing_threshold = 0.0;
+ back_left_zeroing_constants->moving_buffer_size = 0.0;
+ back_left_zeroing_constants->allowable_encoder_error = 0.0;
+
+ back_right_zeroing_constants->average_filter_size = 0;
+ back_right_zeroing_constants->one_revolution_distance = 2 * M_PI;
+ back_right_zeroing_constants->measured_absolute_position = 0.719329333121509;
+ back_right_zeroing_constants->zeroing_threshold = 0.0;
+ back_right_zeroing_constants->moving_buffer_size = 0.0;
+ back_right_zeroing_constants->allowable_encoder_error = 0.0;
+
+ return r;
+}
+
+Values MakeValues() { return MakeValues(aos::network::GetTeamNumber()); }
+} // namespace constants
+} // namespace y2023_bot4
diff --git a/y2023_bot4/constants.h b/y2023_bot4/constants.h
new file mode 100644
index 0000000..676ae06
--- /dev/null
+++ b/y2023_bot4/constants.h
@@ -0,0 +1,55 @@
+#ifndef Y2023_BOT4_CONSTANTS_H
+#define Y2023_BOT4_CONSTANTS_H
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include <cstdint>
+
+#include "frc971/constants.h"
+
+namespace y2023_bot4 {
+namespace constants {
+struct Values {
+ static const int kZeroingSampleSize = 200;
+
+ static const int kDrivetrainWriterPriority = 35;
+ static const int kDrivetrainTxPriority = 36;
+ static const int kDrivetrainRxPriority = 36;
+
+ // TODO (maxwell): Make this the real value;
+ static constexpr double kDrivetrainCyclesPerRevolution() { return 512.0; }
+ static constexpr double kDrivetrainEncoderRatio() { return 1.0; }
+
+ static constexpr double kDrivetrainStatorCurrentLimit() { return 35.0; }
+ static constexpr double kDrivetrainSupplyCurrentLimit() { return 60.0; }
+
+ // TODO (maxwell): Make this the real value
+ static constexpr double kFollowerWheelCountsPerRevolution() { return 512.0; }
+ static constexpr double kFollowerWheelEncoderRatio() { return 1.0; }
+ static constexpr double kFollowerWheelRadius() { return 3.25 / 2 * 0.0254; }
+ static constexpr double kDrivetrainEncoderCountsPerRevolution() {
+ return 2048.0;
+ }
+
+ static constexpr double kMaxDrivetrainEncoderPulsesPerSecond() {
+ return 1200000;
+ }
+
+ frc971::constants::ContinuousAbsoluteEncoderZeroingConstants
+ front_left_zeroing_constants,
+ front_right_zeroing_constants, back_left_zeroing_constants,
+ back_right_zeroing_constants;
+};
+// Creates and returns a Values instance for the constants.
+// Should be called before realtime because this allocates memory.
+// Only the first call to either of these will be used.
+Values MakeValues(uint16_t team);
+
+// Calls MakeValues with aos::network::GetTeamNumber()
+Values MakeValues();
+} // namespace constants
+} // namespace y2023_bot4
+
+#endif // Y2023_BOT4_CONSTANTS_H
diff --git a/y2023_bot4/drivetrain_can_position.fbs b/y2023_bot4/drivetrain_can_position.fbs
new file mode 100644
index 0000000..e8c1235
--- /dev/null
+++ b/y2023_bot4/drivetrain_can_position.fbs
@@ -0,0 +1,17 @@
+include "frc971/control_loops/can_falcon.fbs";
+namespace y2023_bot4;
+
+table SwerveModuleCANPosition {
+ rotation: frc971.control_loops.CANFalcon (id: 0);
+ translation: frc971.control_loops.CANFalcon (id: 1);
+}
+
+// CAN Readings from the CAN sensor reader loop for each swerve module
+table AbsoluteCANPosition {
+ front_left: SwerveModuleCANPosition (id: 0);
+ front_right: SwerveModuleCANPosition (id: 1);
+ back_left: SwerveModuleCANPosition (id: 2);
+ back_right: SwerveModuleCANPosition (id: 3);
+}
+
+root_type AbsoluteCANPosition;
diff --git a/y2023_bot4/drivetrain_position.fbs b/y2023_bot4/drivetrain_position.fbs
new file mode 100644
index 0000000..e5d0fc3
--- /dev/null
+++ b/y2023_bot4/drivetrain_position.fbs
@@ -0,0 +1,16 @@
+include "frc971/control_loops/control_loops.fbs";
+namespace y2023_bot4;
+
+table AbsoluteDrivetrainPosition {
+ // Position of the follower wheels from the encoders
+ follower_wheel_one_position:double (id: 0);
+ follower_wheel_two_position:double (id: 1);
+
+ // Position from the mag encoder on each module.
+ front_left_position: frc971.AbsolutePosition (id: 2);
+ front_right_position: frc971.AbsolutePosition (id: 3);
+ back_left_position: frc971.AbsolutePosition (id: 4);
+ back_right_position: frc971.AbsolutePosition (id: 5);
+}
+
+root_type AbsoluteDrivetrainPosition;
diff --git a/y2023_bot4/swerve_drivetrain_output.json b/y2023_bot4/swerve_drivetrain_output.json
new file mode 100644
index 0000000..bc152e2
--- /dev/null
+++ b/y2023_bot4/swerve_drivetrain_output.json
@@ -0,0 +1,18 @@
+{
+ "front_left_output": {
+ "rotation_current": 0.0,
+ "translation_current": 0.0
+ },
+ "front_right_output": {
+ "rotation_current": 0.0,
+ "translation_current": 0.0
+ },
+ "back_left_output": {
+ "rotation_current": 0.0,
+ "translation_current": 0.0
+ },
+ "back_right_output": {
+ "rotation_current": 0.0,
+ "translation_current": 0.0
+ }
+}
diff --git a/y2023_bot4/swerve_publisher_lib.cc b/y2023_bot4/swerve_publisher_lib.cc
new file mode 100644
index 0000000..78a778e
--- /dev/null
+++ b/y2023_bot4/swerve_publisher_lib.cc
@@ -0,0 +1,51 @@
+#include "y2023_bot4/swerve_publisher_lib.h"
+
+y2023_bot4::SwervePublisher::SwervePublisher(aos::EventLoop *event_loop,
+ aos::ExitHandle *exit_handle,
+ const std::string &filename,
+ double duration)
+ : drivetrain_output_sender_(
+ event_loop->MakeSender<drivetrain::swerve::Output>("/drivetrain")) {
+ event_loop
+ ->AddTimer([this, filename]() {
+ auto output_builder = drivetrain_output_sender_.MakeBuilder();
+
+ auto drivetrain_output =
+ aos::JsonFileToFlatbuffer<drivetrain::swerve::Output>(filename);
+
+ auto copied_flatbuffer =
+ aos::CopyFlatBuffer<drivetrain::swerve::Output>(
+ drivetrain_output, output_builder.fbb());
+ CHECK(drivetrain_output.Verify());
+
+ output_builder.CheckOk(output_builder.Send(copied_flatbuffer));
+ })
+ ->Schedule(event_loop->monotonic_now(),
+ std::chrono::duration_cast<aos::monotonic_clock::duration>(
+ std::chrono::milliseconds(5)));
+ event_loop
+ ->AddTimer([this, exit_handle]() {
+ auto builder = drivetrain_output_sender_.MakeBuilder();
+ drivetrain::swerve::SwerveModuleOutput::Builder swerve_module_builder =
+ builder.MakeBuilder<drivetrain::swerve::SwerveModuleOutput>();
+
+ swerve_module_builder.add_rotation_current(0.0);
+ swerve_module_builder.add_translation_current(0.0);
+
+ auto swerve_module_offset = swerve_module_builder.Finish();
+
+ drivetrain::swerve::Output::Builder drivetrain_output_builder =
+ builder.MakeBuilder<drivetrain::swerve::Output>();
+
+ drivetrain_output_builder.add_front_left_output(swerve_module_offset);
+ drivetrain_output_builder.add_front_right_output(swerve_module_offset);
+ drivetrain_output_builder.add_back_left_output(swerve_module_offset);
+ drivetrain_output_builder.add_back_right_output(swerve_module_offset);
+
+ builder.CheckOk(builder.Send(drivetrain_output_builder.Finish()));
+
+ exit_handle->Exit();
+ })
+ ->Schedule(event_loop->monotonic_now() +
+ std::chrono::milliseconds((int)duration));
+}
diff --git a/y2023_bot4/swerve_publisher_lib.h b/y2023_bot4/swerve_publisher_lib.h
new file mode 100644
index 0000000..5969b7b
--- /dev/null
+++ b/y2023_bot4/swerve_publisher_lib.h
@@ -0,0 +1,29 @@
+#ifndef Y2023_BOT4_SWERVE_PUBLISHER_H_
+#define Y2023_BOT4_SWERVE_PUBLISHER_H_
+
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+
+#include "aos/events/event_loop.h"
+#include "aos/flatbuffer_merge.h"
+#include "aos/init.h"
+#include "aos/json_to_flatbuffer.h"
+#include "frc971/control_loops/drivetrain/swerve/swerve_drivetrain_output_generated.h"
+
+namespace y2023_bot4 {
+
+namespace drivetrain = frc971::control_loops::drivetrain;
+
+class SwervePublisher {
+ public:
+ SwervePublisher(aos::EventLoop *event_loop, aos::ExitHandle *exit_handle,
+ const std::string &filename, double duration);
+
+ private:
+ aos::Sender<frc971::control_loops::drivetrain::swerve::Output>
+ drivetrain_output_sender_;
+};
+
+} // namespace y2023_bot4
+
+#endif // Y2023_BOT4_SWERVE_PUBLISHER_H_
diff --git a/y2023_bot4/swerve_publisher_lib_test.cc b/y2023_bot4/swerve_publisher_lib_test.cc
new file mode 100644
index 0000000..817f295
--- /dev/null
+++ b/y2023_bot4/swerve_publisher_lib_test.cc
@@ -0,0 +1,54 @@
+#include "y2023_bot4/swerve_publisher_lib.h"
+
+#include "gtest/gtest.h"
+
+#include "aos/events/simulated_event_loop.h"
+
+namespace y2023_bot4 {
+namespace testing {
+class SwervePublisherTest : public ::testing::Test {
+ public:
+ SwervePublisherTest()
+ : config_(aos::configuration::ReadConfig("y2023_bot4/aos_config.json")),
+ event_loop_factory_(&config_.message()),
+ roborio_(aos::configuration::GetNode(
+ event_loop_factory_.configuration(), "roborio")),
+ event_loop_(
+ event_loop_factory_.MakeEventLoop("swerve_publisher", roborio_)),
+ exit_handle_(event_loop_factory_.MakeExitHandle()),
+ drivetrain_swerve_output_fetcher_(
+ event_loop_->MakeFetcher<
+ frc971::control_loops::drivetrain::swerve::Output>(
+ "/drivetrain")),
+ swerve_publisher_(event_loop_.get(), exit_handle_.get(),
+ "y2023_bot4/swerve_drivetrain_output.json", 100) {}
+
+ void SendOutput() { event_loop_factory_.Run(); }
+
+ void CheckOutput() {
+ drivetrain_swerve_output_fetcher_.Fetch();
+
+ ASSERT_TRUE(drivetrain_swerve_output_fetcher_.get() != nullptr)
+ << ": No drivetrain output";
+ }
+
+ private:
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
+ aos::SimulatedEventLoopFactory event_loop_factory_;
+ const aos::Node *const roborio_;
+
+ std::unique_ptr<aos::EventLoop> event_loop_;
+ std::unique_ptr<aos::ExitHandle> exit_handle_;
+
+ aos::Fetcher<frc971::control_loops::drivetrain::swerve::Output>
+ drivetrain_swerve_output_fetcher_;
+
+ y2023_bot4::SwervePublisher swerve_publisher_;
+};
+
+TEST_F(SwervePublisherTest, CheckSentFb) {
+ SendOutput();
+ CheckOutput();
+}
+} // namespace testing
+} // namespace y2023_bot4
diff --git a/y2023_bot4/swerve_publisher_main.cc b/y2023_bot4/swerve_publisher_main.cc
new file mode 100644
index 0000000..87470d7
--- /dev/null
+++ b/y2023_bot4/swerve_publisher_main.cc
@@ -0,0 +1,24 @@
+#include "aos/events/shm_event_loop.h"
+#include "y2023_bot4/swerve_publisher_lib.h"
+
+DEFINE_double(duration, 100.0, "Length of time in Ms to apply current for");
+DEFINE_string(drivetrain_position, "swerve_drivetrain_output.json",
+ "The path to the json drivetrain position to apply");
+DEFINE_string(config, "aos_config.json", "The path to aos_config.json");
+
+int main(int argc, char **argv) {
+ aos::InitGoogle(&argc, &argv);
+
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig(FLAGS_config);
+
+ aos::ShmEventLoop event_loop(&config.message());
+
+ std::unique_ptr<aos::ExitHandle> exit_handle = event_loop.MakeExitHandle();
+
+ y2023_bot4::SwervePublisher publisher(&event_loop, exit_handle.get(),
+ FLAGS_drivetrain_position,
+ FLAGS_duration);
+
+ event_loop.Run();
+}
diff --git a/y2023_bot4/wpilib_interface.cc b/y2023_bot4/wpilib_interface.cc
new file mode 100644
index 0000000..a744ae0
--- /dev/null
+++ b/y2023_bot4/wpilib_interface.cc
@@ -0,0 +1,325 @@
+#include "ctre/phoenix/cci/Diagnostics_CCI.h"
+#include "ctre/phoenix6/TalonFX.hpp"
+
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "frc971/control_loops/control_loops_generated.h"
+#include "frc971/wpilib/can_sensor_reader.h"
+#include "frc971/wpilib/falcon.h"
+#include "frc971/wpilib/sensor_reader.h"
+#include "frc971/wpilib/swerve/swerve_drivetrain_writer.h"
+#include "frc971/wpilib/wpilib_robot_base.h"
+#include "y2023_bot4/constants.h"
+#include "y2023_bot4/drivetrain_can_position_generated.h"
+#include "y2023_bot4/drivetrain_position_generated.h"
+
+DEFINE_bool(ctre_diag_server, false,
+ "If true, enable the diagnostics server for interacting with "
+ "devices on the CAN bus using Phoenix Tuner");
+
+using frc971::wpilib::CANSensorReader;
+using frc971::wpilib::Falcon;
+using frc971::wpilib::swerve::DrivetrainWriter;
+using frc971::wpilib::swerve::SwerveModule;
+
+namespace drivetrain = frc971::control_loops::drivetrain;
+
+namespace y2023_bot4 {
+namespace wpilib {
+namespace {
+
+template <class T>
+T value_or_exit(std::optional<T> optional) {
+ CHECK(optional.has_value());
+ return optional.value();
+}
+
+flatbuffers::Offset<frc971::AbsolutePosition> module_offset(
+ frc971::AbsolutePosition::Builder builder,
+ frc971::wpilib::AbsoluteEncoder *module) {
+ builder.add_encoder(module->ReadRelativeEncoder());
+ builder.add_absolute_encoder(module->ReadAbsoluteEncoder());
+
+ return builder.Finish();
+}
+
+flatbuffers::Offset<SwerveModuleCANPosition> can_module_offset(
+ SwerveModuleCANPosition::Builder builder,
+ std::shared_ptr<SwerveModule> module) {
+ std::optional<flatbuffers::Offset<control_loops::CANFalcon>> rotation_offset =
+ module->rotation->TakeOffset();
+ std::optional<flatbuffers::Offset<control_loops::CANFalcon>>
+ translation_offset = module->translation->TakeOffset();
+
+ CHECK(rotation_offset.has_value());
+ CHECK(translation_offset.has_value());
+
+ builder.add_rotation(rotation_offset.value());
+ builder.add_translation(translation_offset.value());
+
+ return builder.Finish();
+}
+
+constexpr double kMaxFastEncoderPulsesPerSecond = std::max({
+ constants::Values::kMaxDrivetrainEncoderPulsesPerSecond(),
+});
+static_assert(kMaxFastEncoderPulsesPerSecond <= 1300000,
+ "fast encoders are too fast");
+} // namespace
+
+class SensorReader : public ::frc971::wpilib::SensorReader {
+ public:
+ SensorReader(aos::ShmEventLoop *event_loop,
+ std::shared_ptr<const constants::Values> values)
+ : ::frc971::wpilib::SensorReader(event_loop),
+ values_(values),
+ drivetrain_position_sender_(
+ event_loop->MakeSender<AbsoluteDrivetrainPosition>("/drivetrain")) {
+ UpdateFastEncoderFilterHz(kMaxFastEncoderPulsesPerSecond);
+ event_loop->SetRuntimeAffinity(aos::MakeCpusetFromCpus({0}));
+ }
+
+ void RunIteration() override {
+ {
+ auto builder = drivetrain_position_sender_.MakeBuilder();
+
+ auto front_left_offset =
+ module_offset(builder.MakeBuilder<frc971::AbsolutePosition>(),
+ &front_left_encoder_);
+ auto front_right_offset =
+ module_offset(builder.MakeBuilder<frc971::AbsolutePosition>(),
+ &front_right_encoder_);
+ auto back_left_offset = module_offset(
+ builder.MakeBuilder<frc971::AbsolutePosition>(), &back_left_encoder_);
+ auto back_right_offset =
+ module_offset(builder.MakeBuilder<frc971::AbsolutePosition>(),
+ &back_right_encoder_);
+
+ AbsoluteDrivetrainPosition::Builder drivetrain_position_builder =
+ builder.MakeBuilder<AbsoluteDrivetrainPosition>();
+
+ drivetrain_position_builder.add_follower_wheel_one_position(
+ follower_wheel_one_encoder_->GetRaw());
+ drivetrain_position_builder.add_follower_wheel_two_position(
+ follower_wheel_two_encoder_->GetRaw());
+
+ drivetrain_position_builder.add_front_left_position(front_left_offset);
+ drivetrain_position_builder.add_front_right_position(front_right_offset);
+ drivetrain_position_builder.add_back_left_position(back_left_offset);
+ drivetrain_position_builder.add_back_right_position(back_right_offset);
+
+ builder.CheckOk(builder.Send(drivetrain_position_builder.Finish()));
+ }
+ }
+
+ void set_follower_wheel_one_encoder(std::unique_ptr<frc::Encoder> encoder) {
+ fast_encoder_filter_.Add(encoder.get());
+ follower_wheel_one_encoder_ = std::move(encoder);
+ follower_wheel_one_encoder_->SetMaxPeriod(0.005);
+ }
+ void set_follower_wheel_two_encoder(std::unique_ptr<frc::Encoder> encoder) {
+ fast_encoder_filter_.Add(encoder.get());
+ follower_wheel_two_encoder_ = std::move(encoder);
+ follower_wheel_two_encoder_->SetMaxPeriod(0.005);
+ }
+
+ void set_front_left_encoder(std::unique_ptr<frc::Encoder> encoder) {
+ fast_encoder_filter_.Add(encoder.get());
+ front_left_encoder_.set_encoder(std::move(encoder));
+ }
+ void set_front_left_absolute_pwm(
+ std::unique_ptr<frc::DigitalInput> absolute_pwm) {
+ front_left_encoder_.set_absolute_pwm(std::move(absolute_pwm));
+ }
+
+ void set_front_right_encoder(std::unique_ptr<frc::Encoder> encoder) {
+ fast_encoder_filter_.Add(encoder.get());
+ front_right_encoder_.set_encoder(std::move(encoder));
+ }
+ void set_front_right_absolute_pwm(
+ std::unique_ptr<frc::DigitalInput> absolute_pwm) {
+ front_right_encoder_.set_absolute_pwm(std::move(absolute_pwm));
+ }
+
+ void set_back_left_encoder(std::unique_ptr<frc::Encoder> encoder) {
+ fast_encoder_filter_.Add(encoder.get());
+ back_left_encoder_.set_encoder(std::move(encoder));
+ }
+ void set_back_left_absolute_pwm(
+ std::unique_ptr<frc::DigitalInput> absolute_pwm) {
+ back_left_encoder_.set_absolute_pwm(std::move(absolute_pwm));
+ }
+
+ void set_back_right_encoder(std::unique_ptr<frc::Encoder> encoder) {
+ fast_encoder_filter_.Add(encoder.get());
+ back_right_encoder_.set_encoder(std::move(encoder));
+ }
+ void set_back_right_absolute_pwm(
+ std::unique_ptr<frc::DigitalInput> absolute_pwm) {
+ back_right_encoder_.set_absolute_pwm(std::move(absolute_pwm));
+ }
+
+ private:
+ std::shared_ptr<const constants::Values> values_;
+
+ aos::Sender<AbsoluteDrivetrainPosition> drivetrain_position_sender_;
+
+ std::unique_ptr<frc::Encoder> follower_wheel_one_encoder_,
+ follower_wheel_two_encoder_;
+
+ frc971::wpilib::AbsoluteEncoder front_left_encoder_, front_right_encoder_,
+ back_left_encoder_, back_right_encoder_;
+};
+
+class WPILibRobot : public ::frc971::wpilib::WPILibRobotBase {
+ public:
+ ::std::unique_ptr<frc::Encoder> make_encoder(int index) {
+ return std::make_unique<frc::Encoder>(10 + index * 2, 11 + index * 2, false,
+ frc::Encoder::k4X);
+ }
+ void Run() override {
+ std::shared_ptr<const constants::Values> values =
+ std::make_shared<const constants::Values>(constants::MakeValues());
+
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig("aos_config.json");
+
+ std::vector<ctre::phoenix6::BaseStatusSignal *> signals_registry;
+ std::vector<std::shared_ptr<Falcon>> falcons;
+
+ // TODO(max): Change the CanBus names with TalonFX software.
+ std::shared_ptr<SwerveModule> front_left = std::make_shared<SwerveModule>(
+ frc971::wpilib::FalconParams{6, false},
+ frc971::wpilib::FalconParams{5, false}, "Drivetrain Bus",
+ &signals_registry, constants::Values::kDrivetrainStatorCurrentLimit(),
+ constants::Values::kDrivetrainSupplyCurrentLimit());
+ std::shared_ptr<SwerveModule> front_right = std::make_shared<SwerveModule>(
+ frc971::wpilib::FalconParams{3, false},
+ frc971::wpilib::FalconParams{4, false}, "Drivetrain Bus",
+ &signals_registry, constants::Values::kDrivetrainStatorCurrentLimit(),
+ constants::Values::kDrivetrainSupplyCurrentLimit());
+ std::shared_ptr<SwerveModule> back_left = std::make_shared<SwerveModule>(
+ frc971::wpilib::FalconParams{8, false},
+ frc971::wpilib::FalconParams{7, false}, "Drivetrain Bus",
+ &signals_registry, constants::Values::kDrivetrainStatorCurrentLimit(),
+ constants::Values::kDrivetrainSupplyCurrentLimit());
+ std::shared_ptr<SwerveModule> back_right = std::make_shared<SwerveModule>(
+ frc971::wpilib::FalconParams{2, false},
+ frc971::wpilib::FalconParams{1, false}, "Drivetrain Bus",
+ &signals_registry, constants::Values::kDrivetrainStatorCurrentLimit(),
+ constants::Values::kDrivetrainSupplyCurrentLimit());
+
+ // Thread 1
+ aos::ShmEventLoop can_sensor_reader_event_loop(&config.message());
+ can_sensor_reader_event_loop.set_name("CANSensorReader");
+
+ falcons.push_back(front_left->rotation);
+ falcons.push_back(front_left->translation);
+
+ falcons.push_back(front_right->rotation);
+ falcons.push_back(front_right->translation);
+
+ falcons.push_back(back_left->rotation);
+ falcons.push_back(back_left->translation);
+
+ falcons.push_back(back_right->rotation);
+ falcons.push_back(back_right->translation);
+
+ aos::Sender<AbsoluteCANPosition> can_position_sender =
+ can_sensor_reader_event_loop.MakeSender<AbsoluteCANPosition>(
+ "/drivetrain");
+
+ CANSensorReader can_sensor_reader(
+ &can_sensor_reader_event_loop, std::move(signals_registry), falcons,
+ [this, falcons, front_left, front_right, back_left, back_right,
+ &can_position_sender](ctre::phoenix::StatusCode status) {
+ // TODO(max): use status properly in the flatbuffer.
+ (void)status;
+
+ auto builder = can_position_sender.MakeBuilder();
+
+ for (auto falcon : falcons) {
+ falcon->RefreshNontimesyncedSignals();
+ falcon->SerializePosition(builder.fbb(), 1.0);
+ }
+
+ auto front_left_offset = can_module_offset(
+ builder.MakeBuilder<SwerveModuleCANPosition>(), front_left);
+ auto front_right_offset = can_module_offset(
+ builder.MakeBuilder<SwerveModuleCANPosition>(), front_right);
+ auto back_left_offset = can_module_offset(
+ builder.MakeBuilder<SwerveModuleCANPosition>(), back_left);
+ auto back_right_offset = can_module_offset(
+ builder.MakeBuilder<SwerveModuleCANPosition>(), back_right);
+
+ AbsoluteCANPosition::Builder can_position_builder =
+ builder.MakeBuilder<AbsoluteCANPosition>();
+
+ can_position_builder.add_front_left(front_left_offset);
+ can_position_builder.add_front_right(front_right_offset);
+ can_position_builder.add_back_left(back_left_offset);
+ can_position_builder.add_back_right(back_right_offset);
+
+ builder.CheckOk(builder.Send(can_position_builder.Finish()));
+ });
+
+ AddLoop(&can_sensor_reader_event_loop);
+
+ // Thread 2
+ // Setup CAN
+ if (!FLAGS_ctre_diag_server) {
+ c_Phoenix_Diagnostics_SetSecondsToStart(-1);
+ c_Phoenix_Diagnostics_Dispose();
+ }
+
+ ctre::phoenix::platform::can::CANComm_SetRxSchedPriority(
+ constants::Values::kDrivetrainRxPriority, true, "Drivetrain Bus");
+ ctre::phoenix::platform::can::CANComm_SetTxSchedPriority(
+ constants::Values::kDrivetrainTxPriority, true, "Drivetrain Bus");
+
+ aos::ShmEventLoop drivetrain_writer_event_loop(&config.message());
+ drivetrain_writer_event_loop.set_name("DrivetrainWriter");
+
+ DrivetrainWriter drivetrain_writer(
+ &drivetrain_writer_event_loop,
+ constants::Values::kDrivetrainWriterPriority, 12);
+
+ drivetrain_writer.set_falcons(front_left, front_right, back_left,
+ back_right);
+
+ AddLoop(&drivetrain_writer_event_loop);
+
+ // Thread 3
+ aos::ShmEventLoop sensor_reader_event_loop(&config.message());
+ sensor_reader_event_loop.set_name("SensorReader");
+ SensorReader sensor_reader(&sensor_reader_event_loop, values);
+
+ sensor_reader.set_follower_wheel_one_encoder(make_encoder(4));
+ sensor_reader.set_follower_wheel_two_encoder(make_encoder(5));
+
+ sensor_reader.set_front_left_encoder(make_encoder(1));
+ sensor_reader.set_front_left_absolute_pwm(
+ std::make_unique<frc::DigitalInput>(1));
+
+ sensor_reader.set_front_right_encoder(make_encoder(0));
+ sensor_reader.set_front_right_absolute_pwm(
+ std::make_unique<frc::DigitalInput>(0));
+
+ sensor_reader.set_back_left_encoder(make_encoder(2));
+ sensor_reader.set_back_left_absolute_pwm(
+ std::make_unique<frc::DigitalInput>(2));
+
+ sensor_reader.set_back_right_encoder(make_encoder(3));
+ sensor_reader.set_back_right_absolute_pwm(
+ std::make_unique<frc::DigitalInput>(3));
+
+ AddLoop(&sensor_reader_event_loop);
+
+ RunLoops();
+ }
+};
+
+} // namespace wpilib
+} // namespace y2023_bot4
+
+AOS_ROBOT_CLASS(::y2023_bot4::wpilib::WPILibRobot)
diff --git a/y2023_bot4/y2023_bot4.json b/y2023_bot4/y2023_bot4.json
new file mode 100644
index 0000000..49db6fc
--- /dev/null
+++ b/y2023_bot4/y2023_bot4.json
@@ -0,0 +1,19 @@
+{
+ "channel_storage_duration": 10000000000,
+ "maps": [
+ {
+ "match": {
+ "name": "/aos",
+ "type": "aos.RobotState"
+ },
+ "rename": {
+ "name": "/roborio/aos"
+ }
+ }
+ ],
+ "imports": [
+ "y2023_bot4_roborio.json",
+ "y2023_bot4_imu.json",
+ "y2023_bot4_logger.json"
+ ]
+}
diff --git a/y2023_bot4/y2023_bot4_imu.json b/y2023_bot4/y2023_bot4_imu.json
new file mode 100644
index 0000000..274b158
--- /dev/null
+++ b/y2023_bot4/y2023_bot4_imu.json
@@ -0,0 +1,212 @@
+{
+ "channels": [
+ {
+ "name": "/imu/aos",
+ "type": "aos.timing.Report",
+ "source_node": "imu",
+ "frequency": 50,
+ "num_senders": 20,
+ "max_size": 4096
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.logging.LogMessageFbs",
+ "source_node": "imu",
+ "frequency": 200,
+ "num_senders": 20
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.starter.Status",
+ "source_node": "imu",
+ "frequency": 50,
+ "num_senders": 20,
+ "max_size": 2048
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.starter.StarterRpc",
+ "source_node": "imu",
+ "frequency": 10,
+ "num_senders": 2
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.message_bridge.ServerStatistics",
+ "source_node": "imu",
+ "frequency": 10,
+ "num_senders": 2
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.message_bridge.ClientStatistics",
+ "source_node": "imu",
+ "frequency": 20,
+ "num_senders": 2
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.logging.DynamicLogCommand",
+ "source_node": "imu",
+ "frequency": 10,
+ "num_senders": 2
+ },
+ {
+ "name": "/imu/aos",
+ "type": "aos.message_bridge.Timestamp",
+ "source_node": "imu",
+ "frequency": 15,
+ "num_senders": 2,
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "roborio",
+ "logger"
+ ],
+ "max_size": 400,
+ "destination_nodes": [
+ {
+ "name": "roborio",
+ "priority": 1,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "imu"
+ ],
+ "time_to_live": 5000000
+ },
+ {
+ "name": "logger",
+ "priority": 1,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "imu"
+ ],
+ "time_to_live": 5000000
+ }
+ ]
+ },
+ {
+ "name": "/imu/aos/remote_timestamps/roborio/imu/aos/aos-message_bridge-Timestamp",
+ "type": "aos.message_bridge.RemoteMessage",
+ "frequency": 20,
+ "source_node": "imu",
+ "max_size": 208
+ },
+ {
+ "name": "/imu/aos/remote_timestamps/logger/imu/aos/aos-message_bridge-Timestamp",
+ "type": "aos.message_bridge.RemoteMessage",
+ "frequency": 20,
+ "source_node": "imu",
+ "max_size": 208
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.starter.StarterRpc",
+ "source_node": "roborio",
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "imu"
+ ],
+ "destination_nodes": [
+ {
+ "name": "imu",
+ "priority": 5,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "roborio"
+ ],
+ "time_to_live": 5000000
+ }
+ ]
+ },
+ {
+ "name": "/roborio/aos/remote_timestamps/imu/roborio/aos/aos-starter-StarterRpc",
+ "type": "aos.message_bridge.RemoteMessage",
+ "source_node": "roborio",
+ "logger": "NOT_LOGGED",
+ "frequency": 20,
+ "num_senders": 2,
+ "max_size": 200
+ },
+ {
+ "name": "/localizer",
+ "type": "frc971.IMUValuesBatch",
+ "source_node": "imu",
+ "frequency": 2200,
+ "max_size": 1600,
+ "num_senders": 2
+ }
+ ],
+ "applications": [
+ {
+ "name": "message_bridge_client",
+ "nodes": [
+ "imu"
+ ]
+ },
+ {
+ "name": "imu",
+ "executable_name": "imu_main",
+ "user": "pi",
+ "nodes": [
+ "imu"
+ ]
+ },
+ {
+ "name": "message_bridge_server",
+ "executable_name": "message_bridge_server",
+ "user": "pi",
+ "nodes": [
+ "imu"
+ ]
+ },
+ {
+ "name": "web_proxy",
+ "executable_name": "web_proxy_main",
+ "args": [
+ "--min_ice_port=5800",
+ "--max_ice_port=5810"
+ ],
+ "user": "pi",
+ "nodes": [
+ "imu"
+ ]
+ },
+ {
+ "name": "foxglove_websocket",
+ "user": "pi",
+ "nodes": [
+ "imu"
+ ]
+ }
+ ],
+ "maps": [
+ {
+ "match": {
+ "name": "/aos*",
+ "source_node": "imu"
+ },
+ "rename": {
+ "name": "/imu/aos"
+ }
+ }
+ ],
+ "nodes": [
+ {
+ "name": "imu",
+ "hostname": "pi6",
+ "hostnames": [
+ "pi-971-6",
+ "pi-7971-6",
+ "pi-8971-6",
+ "pi-9971-6"
+ ],
+ "port": 9971
+ },
+ {
+ "name": "logger"
+ },
+ {
+ "name": "roborio"
+ }
+ ]
+}
diff --git a/y2023_bot4/y2023_bot4_logger.json b/y2023_bot4/y2023_bot4_logger.json
new file mode 100644
index 0000000..5cca31f
--- /dev/null
+++ b/y2023_bot4/y2023_bot4_logger.json
@@ -0,0 +1,190 @@
+{
+ "channels": [
+ {
+ "name": "/roborio/aos",
+ "type": "aos.message_bridge.Timestamp",
+ "source_node": "roborio",
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "logger"
+ ],
+ "destination_nodes": [
+ {
+ "name": "logger",
+ "priority": 1,
+ "time_to_live": 5000000,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "roborio"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "/logger/aos",
+ "type": "aos.timing.Report",
+ "source_node": "logger",
+ "frequency": 50,
+ "num_senders": 20,
+ "max_size": 4096
+ },
+ {
+ "name": "/logger/aos",
+ "type": "aos.logging.LogMessageFbs",
+ "source_node": "logger",
+ "frequency": 400,
+ "num_senders": 20
+ },
+ {
+ "name": "/logger/aos",
+ "type": "aos.message_bridge.ServerStatistics",
+ "source_node": "logger",
+ "frequency": 10,
+ "num_senders": 2
+ },
+ {
+ "name": "/logger/aos",
+ "type": "aos.message_bridge.ClientStatistics",
+ "source_node": "logger",
+ "frequency": 20,
+ "max_size": 2000,
+ "num_senders": 2
+ },
+ {
+ "name": "/logger/aos",
+ "type": "aos.logging.DynamicLogCommand",
+ "source_node": "logger",
+ "frequency": 10,
+ "num_senders": 2
+ },
+ {
+ "name": "/logger/aos",
+ "type": "aos.starter.Status",
+ "source_node": "logger",
+ "frequency": 50,
+ "num_senders": 20,
+ "max_size": 2000
+ },
+ {
+ "name": "/logger/aos",
+ "type": "aos.starter.StarterRpc",
+ "source_node": "logger",
+ "frequency": 10,
+ "num_senders": 2
+ },
+ {
+ "name": "/logger/aos",
+ "type": "aos.message_bridge.Timestamp",
+ "source_node": "logger",
+ "frequency": 15,
+ "num_senders": 2,
+ "max_size": 400,
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "imu",
+ "roborio"
+ ],
+ "destination_nodes": [
+ {
+ "name": "imu",
+ "priority": 1,
+ "time_to_live": 5000000,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "logger"
+ ]
+ },
+ {
+ "name": "roborio",
+ "priority": 1,
+ "time_to_live": 5000000,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "logger"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "/logger/aos/remote_timestamps/imu/logger/aos/aos-message_bridge-Timestamp",
+ "type": "aos.message_bridge.RemoteMessage",
+ "source_node": "logger",
+ "logger": "NOT_LOGGED",
+ "frequency": 20,
+ "num_senders": 2,
+ "max_size": 200
+ },
+ {
+ "name": "/logger/aos/remote_timestamps/roborio/logger/aos/aos-message_bridge-Timestamp",
+ "type": "aos.message_bridge.RemoteMessage",
+ "source_node": "logger",
+ "logger": "NOT_LOGGED",
+ "frequency": 20,
+ "num_senders": 2,
+ "max_size": 200
+ }
+ ],
+ "maps": [
+ {
+ "match": {
+ "name": "/aos*",
+ "source_node": "logger"
+ },
+ "rename": {
+ "name": "/logger/aos"
+ }
+ },
+ {
+ "match": {
+ "name": "/constants*",
+ "source_node": "logger"
+ },
+ "rename": {
+ "name": "/logger/constants"
+ }
+ },
+ {
+ "match": {
+ "name": "/camera*",
+ "source_node": "logger"
+ },
+ "rename": {
+ "name": "/logger/camera"
+ }
+ }
+ ],
+ "applications": [
+ {
+ "name": "message_bridge_client",
+ "nodes": [
+ "logger"
+ ]
+ },
+ {
+ "name": "message_bridge_server",
+ "executable_name": "message_bridge_server",
+ "user": "pi",
+ "nodes": [
+ "logger"
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "name": "logger",
+ "hostname": "pi5",
+ "hostnames": [
+ "pi-971-5",
+ "pi-9971-5",
+ "pi-7971-5"
+ ],
+ "port": 9971
+ },
+ {
+ "name": "imu"
+ },
+ {
+ "name": "roborio"
+ }
+ ]
+}
diff --git a/y2023_bot4/y2023_bot4_roborio.json b/y2023_bot4/y2023_bot4_roborio.json
new file mode 100644
index 0000000..7ff175c
--- /dev/null
+++ b/y2023_bot4/y2023_bot4_roborio.json
@@ -0,0 +1,350 @@
+{
+ "channels": [
+ {
+ "name": "/roborio/aos",
+ "type": "aos.RobotState",
+ "source_node": "roborio",
+ "frequency": 250
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.timing.Report",
+ "source_node": "roborio",
+ "frequency": 50,
+ "num_senders": 20,
+ "max_size": 8192
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.logging.LogMessageFbs",
+ "source_node": "roborio",
+ "frequency": 500,
+ "max_size": 1000,
+ "num_senders": 20
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.starter.Status",
+ "source_node": "roborio",
+ "frequency": 50,
+ "num_senders": 20,
+ "max_size": 2000
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.starter.StarterRpc",
+ "source_node": "roborio",
+ "frequency": 10,
+ "max_size": 400,
+ "num_senders": 2
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.message_bridge.ServerStatistics",
+ "source_node": "roborio",
+ "frequency": 10,
+ "num_senders": 2
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.message_bridge.ClientStatistics",
+ "source_node": "roborio",
+ "frequency": 20,
+ "max_size": 2000,
+ "num_senders": 2
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.logging.DynamicLogCommand",
+ "source_node": "roborio",
+ "frequency": 10,
+ "num_senders": 2
+ },
+ {
+ "name": "/roborio/aos/remote_timestamps/imu/roborio/aos/aos-message_bridge-Timestamp",
+ "type": "aos.message_bridge.RemoteMessage",
+ "frequency": 20,
+ "source_node": "roborio",
+ "max_size": 208
+ },
+ {
+ "name": "/roborio/aos/remote_timestamps/logger/roborio/aos/aos-message_bridge-Timestamp",
+ "type": "aos.message_bridge.RemoteMessage",
+ "frequency": 300,
+ "source_node": "roborio"
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "aos.message_bridge.Timestamp",
+ "source_node": "roborio",
+ "frequency": 15,
+ "num_senders": 2,
+ "max_size": 512,
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "imu"
+ ],
+ "destination_nodes": [
+ {
+ "name": "imu",
+ "priority": 1,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "roborio"
+ ],
+ "time_to_live": 5000000
+ }
+ ]
+ },
+ {
+ "name": "/drivetrain",
+ "type": "y2023_bot4.AbsoluteDrivetrainPosition",
+ "source_node": "roborio",
+ "frequency": 250,
+ "num_senders": 1,
+ "max_size": 480
+ },
+ {
+ "name": "/drivetrain",
+ "type": "y2023_bot4.AbsoluteCANPosition",
+ "source_node": "roborio",
+ "frequency": 250,
+ "num_senders": 1,
+ "max_size": 480
+ },
+ {
+ "name": "/can",
+ "type": "frc971.can_logger.CanFrame",
+ "source_node": "roborio",
+ "frequency": 6000,
+ "num_senders": 2,
+ "max_size": 200
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.CANPosition",
+ "source_node": "roborio",
+ "frequency": 220,
+ "num_senders": 2,
+ "max_size": 400
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.SplineGoal",
+ "source_node": "roborio",
+ "frequency": 10
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.Goal",
+ "source_node": "roborio",
+ "max_size": 224,
+ "frequency": 250
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.swerve.Position",
+ "source_node": "roborio",
+ "frequency": 400,
+ "max_size": 112,
+ "num_senders": 2
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.swerve.Output",
+ "source_node": "roborio",
+ "frequency": 400,
+ "max_size": 200,
+ "num_senders": 2,
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "imu"
+ ],
+ "destination_nodes": [
+ {
+ "name": "imu",
+ "priority": 5,
+ "time_to_live": 5000000
+ }
+ ]
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.Status",
+ "source_node": "roborio",
+ "frequency": 400,
+ "max_size": 1616,
+ "num_senders": 2
+ },
+ {
+ "name": "/drivetrain",
+ "type": "frc971.control_loops.drivetrain.LocalizerControl",
+ "source_node": "roborio",
+ "frequency": 250,
+ "max_size": 96,
+ "logger": "LOCAL_AND_REMOTE_LOGGER",
+ "logger_nodes": [
+ "imu"
+ ],
+ "destination_nodes": [
+ {
+ "name": "imu",
+ "priority": 5,
+ "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+ "timestamp_logger_nodes": [
+ "roborio"
+ ],
+ "time_to_live": 0
+ }
+ ]
+ },
+ {
+ "name": "/roborio/aos/remote_timestamps/imu/drivetrain/frc971-control_loops-drivetrain-LocalizerControl",
+ "type": "aos.message_bridge.RemoteMessage",
+ "source_node": "roborio",
+ "logger": "NOT_LOGGED",
+ "frequency": 400,
+ "num_senders": 2,
+ "max_size": 200
+ },
+ {
+ "name": "/autonomous",
+ "type": "aos.common.actions.Status",
+ "source_node": "roborio"
+ },
+ {
+ "name": "/autonomous",
+ "type": "frc971.autonomous.Goal",
+ "source_node": "roborio"
+ },
+ {
+ "name": "/autonomous",
+ "type": "frc971.autonomous.AutonomousMode",
+ "source_node": "roborio",
+ "frequency": 250
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "frc971.PDPValues",
+ "source_node": "roborio",
+ "frequency": 55,
+ "max_size": 368
+ },
+ {
+ "name": "/roborio/aos",
+ "type": "frc971.wpilib.PneumaticsToLog",
+ "source_node": "roborio",
+ "frequency": 50
+ },
+ {
+ "name": "/roborio",
+ "type": "frc971.CANConfiguration",
+ "source_node": "roborio",
+ "frequency": 2
+ }
+ ],
+ "applications": [
+ {
+ "name": "wpilib_interface",
+ "executable_name": "wpilib_interface",
+ "args": [
+ "--nodie_on_malloc",
+ "--ctre_diag_server"
+ ],
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "swerve_publisher",
+ "executable_name": "swerve_publisher",
+ "autostart": false,
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "roborio_web_proxy",
+ "executable_name": "web_proxy_main",
+ "args": [
+ "--min_ice_port=5800",
+ "--max_ice_port=5810"
+ ],
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "roborio_message_bridge_client",
+ "executable_name": "message_bridge_client",
+ "args": [
+ "--rt_priority=16",
+ "--sinit_max_init_timeout=5000"
+ ],
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "roborio_message_bridge_server",
+ "executable_name": "message_bridge_server",
+ "args": [
+ "--rt_priority=16"
+ ],
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "logger",
+ "executable_name": "logger_main",
+ "args": [
+ "--snappy_compress",
+ "--logging_folder=/home/admin/logs/",
+ "--rotate_every",
+ "30.0"
+ ],
+ "nodes": [
+ "roborio"
+ ]
+ },
+ {
+ "name": "can_logger",
+ "executable_name": "can_logger",
+ "nodes": [
+ "roborio"
+ ]
+ }
+ ],
+ "maps": [
+ {
+ "match": {
+ "name": "/aos*",
+ "source_node": "roborio"
+ },
+ "rename": {
+ "name": "/roborio/aos"
+ }
+ }
+ ],
+ "nodes": [
+ {
+ "name": "roborio",
+ "hostname": "roborio",
+ "hostnames": [
+ "roboRIO-971-FRC",
+ "roboRIO-6971-FRC",
+ "roboRIO-7971-FRC",
+ "roboRIO-8971-FRC",
+ "roboRIO-9971-FRC"
+ ],
+ "port": 9971
+ },
+ {
+ "name": "imu"
+ },
+ {
+ "name": "logger"
+ }
+ ]
+}