diff --git a/esp32/include/communication/comm_base.hpp b/esp32/include/communication/comm_base.hpp index b9464b4..001f513 100644 --- a/esp32/include/communication/comm_base.hpp +++ b/esp32/include/communication/comm_base.hpp @@ -6,8 +6,11 @@ #include #include #include +#include +#include #include #include +#include class CommAdapterBase { public: @@ -35,6 +38,26 @@ class CommAdapterBase { decoder_.on(handler); } + template + void onPublish(std::function handler = nullptr) { + decoder_.on([this, handler](const T& data, int clientId) { + EventBus::publish(data); + if (handler) handler(data, clientId); + }); + } + + template + void bridgeFromEventBus() { + eventBusHandles_.push_back( + std::make_unique>(EventBus::subscribe([this](const T& data) { emit(data); }))); + } + + template + void bridgeFromEventBus(uint32_t intervalMs) { + eventBusHandles_.push_back(std::make_unique>( + EventBus::subscribe(intervalMs, [this](const T& data) { emit(data); }))); + } + template void emit(const T& data, int clientId = -1) { constexpr pb_size_t tag = MessageTraits::tag; @@ -47,8 +70,7 @@ class CommAdapterBase { size_t out_size; pb_get_encoded_size(&out_size, socket_message_Message_fields, &msg_); uint8_t* buffer = pb_heap_enc_buf; - if (out_size > sizeof(pb_heap_enc_buf)) { // If the encoded size exceeds our buffer size, we needs to malloc a - // buffer of a proper size + if (out_size > sizeof(pb_heap_enc_buf)) { buffer = (uint8_t*)malloc(out_size); } @@ -116,6 +138,18 @@ class CommAdapterBase { socket_message_Message msg_ = socket_message_Message_init_zero; uint8_t pb_heap_enc_buf[PROTO_BUFFER_SIZE]; + struct EventBusHandleBase { + virtual ~EventBusHandleBase() = default; + }; + + template + struct EventBusHandleStorage : EventBusHandleBase { + EventBus::Handle handle; + EventBusHandleStorage(EventBus::Handle&& h) : handle(std::move(h)) {} + }; + + std::vector> eventBusHandles_; + private: void sendToSubscribers(int32_t tag, const uint8_t* data, size_t len) { xSemaphoreTake(mutex_, portMAX_DELAY); diff --git a/esp32/include/event_bus/event_registry.h b/esp32/include/event_bus/event_registry.h index 8d6ea90..f339988 100644 --- a/esp32/include/event_bus/event_registry.h +++ b/esp32/include/event_bus/event_registry.h @@ -39,3 +39,7 @@ REGISTER_SETTINGS_TYPE(api_CameraSettings, EventType::CAMERA_SETTINGS) REGISTER_EVENT_TYPE(socket_message_IMUData, EventType::IMU_DATA) REGISTER_EVENT_TYPE(socket_message_ControllerData, EventType::MOTION_COMMAND) REGISTER_EVENT_TYPE(socket_message_ModeData, EventType::MOTION_MODE) +REGISTER_EVENT_TYPE(socket_message_AnglesData, EventType::MOTION_ANGLES) +REGISTER_EVENT_TYPE(socket_message_WalkGaitData, EventType::MOTION_WALK_GAIT) +REGISTER_EVENT_TYPE(socket_message_ServoStateData, EventType::SERVO_STATE) +REGISTER_EVENT_TYPE(socket_message_ServoPWMData, EventType::SERVO_PWM) diff --git a/esp32/include/event_bus/event_types.h b/esp32/include/event_bus/event_types.h index 9253e40..58c170e 100644 --- a/esp32/include/event_bus/event_types.h +++ b/esp32/include/event_bus/event_types.h @@ -14,7 +14,10 @@ enum class EventType : uint16_t { IMU_DATA = 131, MOTION_COMMAND = 200, MOTION_MODE = 201, + MOTION_ANGLES = 202, + MOTION_WALK_GAIT = 203, SERVO_STATE = 141, + SERVO_PWM = 142, SYSTEM_BOOT = 300, STORAGE_HYDRATION_COMPLETE = 301, diff --git a/esp32/include/motion.h b/esp32/include/motion.h index 1b9c148..b6c68be 100644 --- a/esp32/include/motion.h +++ b/esp32/include/motion.h @@ -14,13 +14,18 @@ #include #include #include +#include enum class MOTION_STATE { DEACTIVATED, IDLE, CALIBRATION, REST, STAND, WALK }; class MotionService { public: + using ModeChangeCallback = std::function; + void begin(); + void setModeChangeCallback(ModeChangeCallback callback) { modeChangeCallback_ = callback; } + void handleAngles(const socket_message_AnglesData& data); void handleInput(const socket_message_ControllerData& data); @@ -42,6 +47,8 @@ class MotionService { inline bool isActive() { return state != nullptr; } private: + void subscribeToEvents(); + Kinematics kinematics; CommandMsg command = {0, 0, 0, 0, 0, 0, 0}; @@ -62,6 +69,13 @@ class MotionService { float dir[12] = {1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1}; int64_t lastUpdate = esp_timer_get_time(); + + ModeChangeCallback modeChangeCallback_; + + EventBus::Handle controllerHandle_; + EventBus::Handle modeHandle_; + EventBus::Handle anglesHandle_; + EventBus::Handle walkGaitHandle_; }; #endif diff --git a/esp32/include/peripherals/servo_controller.h b/esp32/include/peripherals/servo_controller.h index 8c01958..b909ce5 100644 --- a/esp32/include/peripherals/servo_controller.h +++ b/esp32/include/peripherals/servo_controller.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #ifndef FACTORY_SERVO_PWM_FREQUENCY @@ -41,6 +42,12 @@ class ServoController { _settingsHandle = EventBus::subscribe( [this](const api_ServoSettings &settings) { onSettingsChanged(settings); }); + _pwmHandle = EventBus::subscribe( + [this](const socket_message_ServoPWMData &data) { setServoPWM(data.servo_id, data.servo_pwm); }); + + _stateHandle = EventBus::subscribe( + [this](const socket_message_ServoStateData &data) { data.active ? activate() : deactivate(); }); + api_ServoSettings initialSettings; if (EventBus::peek(initialSettings)) { onSettingsChanged(initialSettings); @@ -125,6 +132,8 @@ class ServoController { api_ServoSettings _settings = ServoSettings_defaults(); EventBus::Handle _settingsHandle; + EventBus::Handle _pwmHandle; + EventBus::Handle _stateHandle; PCA9685Driver _pca; diff --git a/esp32/src/event_bus/event_bus.cpp b/esp32/src/event_bus/event_bus.cpp index 2eba39d..b2b01a6 100644 --- a/esp32/src/event_bus/event_bus.cpp +++ b/esp32/src/event_bus/event_bus.cpp @@ -52,3 +52,10 @@ template void EventBus::notifyGlobalListeners(const sock template void EventBus::notifyGlobalListeners(const socket_message_ControllerData&, const char*); template void EventBus::notifyGlobalListeners(const socket_message_ModeData&, const char*); +template void EventBus::notifyGlobalListeners(const socket_message_AnglesData&, const char*); +template void EventBus::notifyGlobalListeners(const socket_message_WalkGaitData&, + const char*); +template void EventBus::notifyGlobalListeners(const socket_message_ServoStateData&, + const char*); +template void EventBus::notifyGlobalListeners(const socket_message_ServoPWMData&, + const char*); diff --git a/esp32/src/event_bus/event_types.cpp b/esp32/src/event_bus/event_types.cpp index a5b8e33..d1f896b 100644 --- a/esp32/src/event_bus/event_types.cpp +++ b/esp32/src/event_bus/event_types.cpp @@ -13,7 +13,10 @@ const char* eventTypeName(EventType type) { case EventType::IMU_DATA: return "IMU_DATA"; case EventType::MOTION_COMMAND: return "MOTION_COMMAND"; case EventType::MOTION_MODE: return "MOTION_MODE"; + case EventType::MOTION_ANGLES: return "MOTION_ANGLES"; + case EventType::MOTION_WALK_GAIT: return "MOTION_WALK_GAIT"; case EventType::SERVO_STATE: return "SERVO_STATE"; + case EventType::SERVO_PWM: return "SERVO_PWM"; case EventType::SYSTEM_BOOT: return "SYSTEM_BOOT"; case EventType::STORAGE_HYDRATION_COMPLETE: return "STORAGE_HYDRATION_COMPLETE"; default: return "UNKNOWN"; diff --git a/esp32/src/main.cpp b/esp32/src/main.cpp index c4ea985..3c49be2 100644 --- a/esp32/src/main.cpp +++ b/esp32/src/main.cpp @@ -132,32 +132,18 @@ void setupEventSocket() { [](const socket_message_FSDownloadComplete &complete, int clientId) { wsSocket.emit(complete, clientId); }, [](const socket_message_FSUploadComplete &complete, int clientId) { wsSocket.emit(complete, clientId); }); - wsSocket.on( - [&](const socket_message_ControllerData &data, int clientId) { motionService.handleInput(data); }); - - wsSocket.on([&](const socket_message_ModeData &data, int clientId) { - servoController.setMode(SERVO_CONTROL_STATE::ANGLE); - motionService.handleMode(data); - motionService.isActive() ? servoController.activate() : servoController.deactivate(); - }); - - wsSocket.on( - [&](const socket_message_WalkGaitData &data, int clientId) { motionService.handleWalkGait(data); }); - - wsSocket.on( - [&](const socket_message_AnglesData &data, int clientId) { motionService.handleAngles(data); }); - - wsSocket.on([&](const socket_message_ServoPWMData &data, int clientId) { - servoController.setServoPWM(data.servo_id, data.servo_pwm); - }); - - wsSocket.on([&](const socket_message_ServoStateData &data, int clientId) { - data.active ? servoController.activate() : servoController.deactivate(); - }); + wsSocket.onPublish(); + wsSocket.onPublish(); + wsSocket.onPublish(); + wsSocket.onPublish(); + wsSocket.onPublish(); + wsSocket.onPublish(); wsSocket.on( [&](const socket_message_FSUploadData &data, int clientId) { FileSystemWS::fsHandler.handleUploadData(data); }); + wsSocket.bridgeFromEventBus(100); + using CorrelationHandler = std::function; static std::map correlationHandlers = { @@ -257,6 +243,10 @@ void IRAM_ATTR SpotControlLoopEntry(void *) { peripherals.begin(); servoController.begin(); motionService.begin(); + motionService.setModeChangeCallback([](bool active) { + servoController.setMode(SERVO_CONTROL_STATE::ANGLE); + active ? servoController.activate() : servoController.deactivate(); + }); #if FT_ENABLED(USE_WS2812) ledService.begin(); #endif @@ -310,11 +300,9 @@ void IRAM_ATTR serviceLoopEntry(void *) { }); EXECUTE_EVERY_N_MS(100, { - if (wsSocket.hasSubscribers(socket_message_Message_imu_tag)) { - socket_message_IMUData imu = socket_message_IMUData_init_zero; - peripherals.getIMUProto(imu); - wsSocket.emit(imu); - } + socket_message_IMUData imu = socket_message_IMUData_init_zero; + peripherals.getIMUProto(imu); + EventBus::publish(imu); if (wsSocket.hasSubscribers(socket_message_Message_rssi_tag)) { socket_message_RSSIData rssi = {.rssi = WiFi.RSSI()}; diff --git a/esp32/src/motion.cpp b/esp32/src/motion.cpp index dfab08f..60c3864 100644 --- a/esp32/src/motion.cpp +++ b/esp32/src/motion.cpp @@ -1,6 +1,23 @@ #include -void MotionService::begin() { body_state.updateFeet(KinConfig::default_feet_positions); } +void MotionService::begin() { + body_state.updateFeet(KinConfig::default_feet_positions); + subscribeToEvents(); +} + +void MotionService::subscribeToEvents() { + controllerHandle_ = EventBus::subscribe( + [this](const socket_message_ControllerData& data) { handleInput(data); }); + + modeHandle_ = + EventBus::subscribe([this](const socket_message_ModeData& data) { handleMode(data); }); + + anglesHandle_ = EventBus::subscribe( + [this](const socket_message_AnglesData& data) { handleAngles(data); }); + + walkGaitHandle_ = EventBus::subscribe( + [this](const socket_message_WalkGaitData& data) { handleWalkGait(data); }); +} void MotionService::handleAngles(const socket_message_AnglesData& data) { for (int i = 0; i < 12 && i < data.angles_count; i++) { @@ -41,6 +58,7 @@ void MotionService::handleMode(const socket_message_ModeData& data) { case MOTION_STATE::DEACTIVATED: setState(nullptr); break; default: setState(nullptr); break; } + if (modeChangeCallback_) modeChangeCallback_(isActive()); } void MotionService::handleGestures(const gesture_t ges) {