Skip to content

Commit 7c0738e

Browse files
authored
Add a service for talking to an ExpansionHub (#9)
* Initial ExpansionHub support * Tuning * Unroll loops so things update as fast as possible * Major cleanup * Add enablement support * Add motor currents, refactor how NT happens * Updates to enable reading before doing commands * Add encoder resetting, and java impl * Add PID modes * Only send not often updating commands on reset * 10ms loop time * Fix PID * Fix voltage * Major refactor to clean up how everything works * A bit more formatting * Add python * Fix pythong * Another python fix
1 parent 6687910 commit 7c0738e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+6115
-3
lines changed

.vscode/settings.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,20 @@
100100
"xtree": "cpp",
101101
"xutility": "cpp",
102102
"*.tcc": "cpp",
103-
"string_view": "cpp"
103+
"string_view": "cpp",
104+
"codecvt": "cpp",
105+
"module.h": "c",
106+
"serial.h": "c",
107+
"termios.h": "c",
108+
"__bit_reference": "cpp",
109+
"__config": "cpp",
110+
"__hash_table": "cpp",
111+
"__locale": "cpp",
112+
"__node_handle": "cpp",
113+
"__split_buffer": "cpp",
114+
"__threading_support": "cpp",
115+
"__tree": "cpp",
116+
"__verbose_abort": "cpp",
117+
"execution": "cpp"
104118
}
105119
}

CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
2929
option(WITH_NTCORE "Include ntcore" ON)
3030
option(WITH_JAVA "Include java and JNI in the build" OFF)
3131
option(WITH_CSCORE "Build cscore (needs OpenCV)" OFF)
32-
option(WITH_WPIMATH "Build wpimath" OFF)
32+
option(WITH_WPIMATH "Build wpimath" ON)
3333
option(WITH_WPILIB "Build hal, wpilibc/j, and myRobot (needs OpenCV)" OFF)
3434
option(WITH_OLD_COMMANDS "Build old commands" OFF)
3535
option(WITH_EXAMPLES "Build examples" OFF)
@@ -94,11 +94,12 @@ add_subdirectory(radio)
9494

9595
if (MRC_BUILD)
9696
add_subdirectory(powerdistribution)
97+
add_subdirectory(expansionhub)
9798
endif()
9899

99100
if (MRC_BUILD)
100101
install(
101-
TARGETS RadioDaemon PowerDistributionDaemon
102+
TARGETS RadioDaemon PowerDistributionDaemon ExpansionHubDaemon
102103
RUNTIME DESTINATION bin
103104
LIBRARY DESTINATION lib
104105
ARCHIVE DESTINATION lib

expansionhub/CMakeLists.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
project(ExpansionHubDaemon)
2+
3+
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--allow-shlib-undefined")
4+
5+
add_executable(ExpansionHubDaemon
6+
main.cpp
7+
PidConstants.cpp
8+
SerialPort.cpp
9+
EnabledState.cpp
10+
MotorNtState.cpp
11+
ServoNtState.cpp
12+
ExpansionHubNtState.cpp
13+
ExpansionHubSerial.cpp
14+
SystemDUsbMonitor.cpp
15+
)
16+
target_compile_features(ExpansionHubDaemon PRIVATE cxx_std_20)
17+
target_compile_features(ExpansionHubDaemon PRIVATE c_std_17)
18+
wpilib_target_warnings(ExpansionHubDaemon)
19+
target_link_libraries(ExpansionHubDaemon PRIVATE Common wpimath ntcore wpinet wpiutil)
20+
target_link_libraries(ExpansionHubDaemon PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/libsystemd.so.0.37.0)
21+
target_include_directories(ExpansionHubDaemon PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/rhsp/include)
22+
23+
if (MRC_BUILD)
24+
target_compile_definitions(ExpansionHubDaemon PRIVATE MRC_DAEMON_BUILD)
25+
endif()

expansionhub/CachedCommand.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#pragma once
2+
3+
#include <optional>
4+
5+
namespace eh {
6+
7+
template <typename T>
8+
struct CachedCommand {
9+
T subscriber;
10+
std::optional<typename T::ValueType> lastAckedValue;
11+
T::ValueType lastAttemptedValue;
12+
13+
CachedCommand() = default;
14+
15+
CachedCommand(const CachedCommand&) = delete;
16+
CachedCommand& operator=(const CachedCommand&) = delete;
17+
CachedCommand(CachedCommand&&) = delete;
18+
CachedCommand& operator=(CachedCommand&&) = delete;
19+
20+
CachedCommand& operator=(T sub) {
21+
subscriber = std::move(sub);
22+
return *this;
23+
}
24+
25+
void ForceReset() { lastAckedValue.reset(); }
26+
27+
void Ack() { lastAckedValue = lastAttemptedValue; }
28+
29+
std::optional<typename T::ValueType> Get() {
30+
auto newValue = subscriber.Get();
31+
32+
if (newValue != lastAckedValue) {
33+
lastAckedValue.reset();
34+
lastAttemptedValue = newValue;
35+
return newValue;
36+
}
37+
38+
return std::nullopt;
39+
}
40+
41+
std::optional<typename T::ValueType> GetWithCanEnable(bool canEnable) {
42+
auto newValue = canEnable ? subscriber.Get() : false;
43+
44+
if (newValue != lastAckedValue) {
45+
lastAckedValue.reset();
46+
lastAttemptedValue = newValue;
47+
return newValue;
48+
}
49+
50+
return std::nullopt;
51+
}
52+
};
53+
} // namespace eh

expansionhub/EnabledState.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include "EnabledState.h"
2+
3+
#include <fcntl.h>
4+
#include <stdint.h>
5+
#include <thread>
6+
#include <chrono>
7+
#include <string.h>
8+
9+
#define CONTROL_DATA_PATH "/sys/kernel/can_heartbeat/controldataro"
10+
11+
namespace eh {
12+
13+
EnabledState::~EnabledState() {
14+
if (fd == -1) {
15+
return;
16+
}
17+
close(fd);
18+
}
19+
20+
bool EnabledState::Initialize() {
21+
int retries = 0;
22+
while (fd == -1 && retries < 50) {
23+
fd = open(CONTROL_DATA_PATH, O_RDONLY);
24+
if (fd == -1) {
25+
std::this_thread::sleep_for(std::chrono::milliseconds(250));
26+
retries++;
27+
}
28+
}
29+
30+
return fd != -1;
31+
}
32+
33+
bool EnabledState::IsEnabled() const {
34+
if (fd == -1) {
35+
return false;
36+
}
37+
38+
char buf[128];
39+
40+
ssize_t control_data_size = pread(fd, buf, sizeof(buf), 0);
41+
42+
buf[control_data_size] = '\0';
43+
44+
unsigned int control_data = strtol(buf, NULL, 16);
45+
46+
bool system_watchdog = (control_data & 0x1) != 0 ? true : false;
47+
48+
return system_watchdog;
49+
}
50+
} // namespace eh

expansionhub/EnabledState.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#pragma once
2+
3+
namespace eh {
4+
5+
class EnabledState {
6+
public:
7+
EnabledState() = default;
8+
~EnabledState() noexcept;
9+
10+
bool Initialize();
11+
12+
bool IsEnabled() const;
13+
14+
EnabledState(const EnabledState&) = delete;
15+
EnabledState(EnabledState&&) = delete;
16+
EnabledState& operator=(const EnabledState&) = delete;
17+
EnabledState& operator=(EnabledState&&) = delete;
18+
19+
private:
20+
int fd = -1;
21+
};
22+
} // namespace eh

expansionhub/ExpansionHub.service

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[Unit]
2+
Description=ExpansionHub
3+
After=network.target
4+
5+
[Service]
6+
Type=simple
7+
ExecStart=/usr/bin/ExpansionHubDaemon
8+
Restart=always
9+
RestartSec=3
10+
11+
[Install]
12+
WantedBy=multi-user.target
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include "ExpansionHubNtState.h"
2+
3+
#include "networktables/NetworkTableInstance.h"
4+
5+
using namespace eh;
6+
7+
void ExpansionHubNtState::Initialize(const nt::NetworkTableInstance& instance,
8+
int deviceNum) {
9+
if (isConnectedPublisher) {
10+
return;
11+
}
12+
13+
nt::PubSubOptions options;
14+
options.sendAll = true;
15+
options.keepDuplicates = true;
16+
options.periodic = 0.005;
17+
18+
auto busIdStr = std::to_string(deviceNum);
19+
20+
for (int i = 0; i < static_cast<int>(motors.size()); i++) {
21+
motors[i].Initialize(instance, i, busIdStr, options);
22+
}
23+
24+
for (int i = 0; i < static_cast<int>(servos.size()); i++) {
25+
servos[i].Initialize(instance, i, busIdStr, options);
26+
}
27+
28+
transactionTimePublisher =
29+
instance.GetIntegerTopic("/rhsp/" + busIdStr + "/transactionTime")
30+
.Publish(options);
31+
32+
batteryVoltagePublisher =
33+
instance.GetDoubleTopic("/rhsp/" + busIdStr + "/battery")
34+
.Publish(options);
35+
isConnectedPublisher =
36+
instance.GetBooleanTopic("/rhsp/" + busIdStr + "/connected")
37+
.Publish(options);
38+
39+
numCrcFailuresPublisher =
40+
instance.GetIntegerTopic("/rhsp/" + busIdStr + "/numCrcFailures")
41+
.Publish(options);
42+
43+
numMissedSendLoopsPublisher =
44+
instance.GetIntegerTopic("/rhsp/" + busIdStr + "/numMissedSendLoops")
45+
.Publish(options);
46+
47+
numNacksPublisher =
48+
instance.GetIntegerTopic("/rhsp/" + busIdStr + "/numNacks")
49+
.Publish(options);
50+
}

expansionhub/ExpansionHubNtState.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#pragma once
2+
3+
#include <array>
4+
#include "MotorNtState.h"
5+
#include "ServoNtState.h"
6+
7+
#define NUM_MOTORS_PER_HUB 4
8+
#define NUM_SERVOS_PER_HUB 6
9+
10+
namespace eh {
11+
12+
struct ExpansionHubNtState {
13+
std::array<MotorNtState, NUM_MOTORS_PER_HUB> motors;
14+
std::array<ServoNtState, NUM_SERVOS_PER_HUB> servos;
15+
16+
double lastBattery{0};
17+
18+
nt::DoublePublisher batteryVoltagePublisher;
19+
20+
nt::BooleanPublisher isConnectedPublisher;
21+
22+
nt::IntegerPublisher numNacksPublisher;
23+
nt::IntegerPublisher numCrcFailuresPublisher;
24+
nt::IntegerPublisher numMissedSendLoopsPublisher;
25+
26+
nt::IntegerPublisher transactionTimePublisher;
27+
28+
uint64_t numNacks{0};
29+
uint64_t numCrcFailures{0};
30+
uint64_t numMissedSendLoops{0};
31+
32+
void Initialize(const nt::NetworkTableInstance& instance, int deviceNum);
33+
};
34+
35+
} // namespace eh

0 commit comments

Comments
 (0)