From 69fc1f2addaa0da12de7cebb5509175a1c45be41 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 5 Oct 2026 01:02:43 +0800 Subject: [PATCH 01/17] =?UTF-8?q?fix:=20=E5=B0=86=20USART3=20=E5=AD=97?= =?UTF-8?q?=E9=95=BF=E6=94=B9=E4=B8=BA=209=20=E4=BD=8D=E4=BB=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20DBUS/SBUS=20=E5=8D=8F=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit USART3 使用 100000 波特率与偶校验,配合 9 位字长(8 数据位 + 校验位) --- boards/base/DJI_Board_TypeC_general/Core/Src/usart.c | 2 +- boards/base/DJI_Board_TypeC_general/DJI_Board_TypeC_general.ioc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/base/DJI_Board_TypeC_general/Core/Src/usart.c b/boards/base/DJI_Board_TypeC_general/Core/Src/usart.c index 2857c9fe..71611ce6 100644 --- a/boards/base/DJI_Board_TypeC_general/Core/Src/usart.c +++ b/boards/base/DJI_Board_TypeC_general/Core/Src/usart.c @@ -76,7 +76,7 @@ void MX_USART3_UART_Init(void) /* USER CODE END USART3_Init 1 */ huart3.Instance = USART3; huart3.Init.BaudRate = 100000; - huart3.Init.WordLength = UART_WORDLENGTH_8B; + huart3.Init.WordLength = UART_WORDLENGTH_9B; huart3.Init.StopBits = UART_STOPBITS_1; huart3.Init.Parity = UART_PARITY_EVEN; huart3.Init.Mode = UART_MODE_RX; diff --git a/boards/base/DJI_Board_TypeC_general/DJI_Board_TypeC_general.ioc b/boards/base/DJI_Board_TypeC_general/DJI_Board_TypeC_general.ioc index f6cde419..00c2d761 100644 --- a/boards/base/DJI_Board_TypeC_general/DJI_Board_TypeC_general.ioc +++ b/boards/base/DJI_Board_TypeC_general/DJI_Board_TypeC_general.ioc @@ -703,7 +703,7 @@ USART3.IPParameters=VirtualMode,Parity,BaudRate,WordLength,Mode USART3.Mode=MODE_RX USART3.Parity=PARITY_EVEN USART3.VirtualMode=VM_ASYNC -USART3.WordLength=WORDLENGTH_8B +USART3.WordLength=WORDLENGTH_9B USART6.IPParameters=VirtualMode USART6.VirtualMode=VM_ASYNC USB_DEVICE.CLASS_NAME_FS=CDC From a6deeaf3e1d479f089c4e6bd09e07cfa8d1016a5 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 5 Oct 2026 23:44:38 +0800 Subject: [PATCH 02/17] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E9=81=A5?= =?UTF-8?q?=E6=8E=A7=E6=8E=A5=E6=94=B6=E6=A1=86=E6=9E=B6=EF=BC=8C=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E7=BB=9F=E4=B8=80=E7=9A=84=20RemoteReceiver=20?= =?UTF-8?q?=E6=8A=BD=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 boards/remote 模块,为 DBUS、SBUS、VT13(RefereeRc) 及 FS-i6X 提供独立接收器,由 RemoteReceiver 基类统一管理有效帧序号、接收时间与失控标志,UART、时钟和控制映射交由接入层处理 - 将 Protocol::Receive 改为基于有界缓存的 A5/A9 分帧解析,VT13 的校验与解码下沉到 RefereeRcReceiver,Protocol 仅负责字节流拆帧 - 在 Protocol/Referee/Host 的 ProcessDataRx 中按结构体大小严格校验载荷长度,避免越界拷贝 - 移除已废弃的 0x0304 REMOTE_CONTROL_DATA 及 0x53 REMOTE_CONTROL_VT13 命令分支 - 新增 dt7、vt13、fs_i6x 示例程序 --- boards/CMakeLists.txt | 3 +- boards/drivers/CMakeLists.txt | 4 +- boards/drivers/include/protocol.h | 27 +-- boards/drivers/src/protocol.cpp | 228 +++++++++++------- boards/remote/CMakeLists.txt | 9 + .../remote/include/protocols/dbus_receiver.h | 192 +++++++++++++++ .../include/protocols/refereerc_receiver.h | 145 +++++++++++ .../remote/include/protocols/sbus_receiver.h | 126 ++++++++++ boards/remote/include/remote.h | 188 +++++++++++++++ boards/remote/src/protocols/dbus_receiver.cpp | 115 +++++++++ .../src/protocols/refereerc_receiver.cpp | 98 ++++++++ boards/remote/src/protocols/sbus_receiver.cpp | 99 ++++++++ .../DJI_Board_TypeC_general/CMakeLists.txt | 1 + .../controller/CMakeLists.txt | 13 + .../controller/dt7.cpp | 73 ++++++ .../controller/fs_i6x.cpp | 97 ++++++++ .../controller/vt13.cpp | 100 ++++++++ 17 files changed, 1420 insertions(+), 98 deletions(-) create mode 100644 boards/remote/CMakeLists.txt create mode 100644 boards/remote/include/protocols/dbus_receiver.h create mode 100644 boards/remote/include/protocols/refereerc_receiver.h create mode 100644 boards/remote/include/protocols/sbus_receiver.h create mode 100644 boards/remote/include/remote.h create mode 100644 boards/remote/src/protocols/dbus_receiver.cpp create mode 100644 boards/remote/src/protocols/refereerc_receiver.cpp create mode 100644 boards/remote/src/protocols/sbus_receiver.cpp create mode 100644 examples/DJI_Board_TypeC_general/controller/CMakeLists.txt create mode 100644 examples/DJI_Board_TypeC_general/controller/dt7.cpp create mode 100644 examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp create mode 100644 examples/DJI_Board_TypeC_general/controller/vt13.cpp diff --git a/boards/CMakeLists.txt b/boards/CMakeLists.txt index 4ac579e8..b9be9a4b 100644 --- a/boards/CMakeLists.txt +++ b/boards/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(base) add_subdirectory(platform) add_subdirectory(algorithm) +add_subdirectory(remote) add_subdirectory(drivers) add_subdirectory(components) -add_subdirectory(third_party) \ No newline at end of file +add_subdirectory(third_party) diff --git a/boards/drivers/CMakeLists.txt b/boards/drivers/CMakeLists.txt index 3562e590..2543a1d4 100644 --- a/boards/drivers/CMakeLists.txt +++ b/boards/drivers/CMakeLists.txt @@ -4,9 +4,11 @@ file(GLOB_RECURSE CRC_CHECK_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/c file(GLOB_RECURSE DRIVER_SOURCES_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.*) set(DRIVER_SOURCES ${DRIVER_SOURCES_FILES} + ${UICRM_REMOTE_SOURCES} ${CRC_CHECK_SOURCES}) set(DRIVER_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include + ${UICRM_REMOTE_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include/Motor ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/crc_check/include) @@ -99,4 +101,4 @@ uicrm_add_board_specific_library(BulletExchanger_F103_drivers SOURCES ${DRIVER_SOURCES} INCLUDES ${DRIVER_INCLUDES} DEPENDS BulletExchanger_F103_platform BulletExchanger_F103_algorithm) -target_include_directories(BulletExchanger_F103_drivers PUBLIC ${DRIVER_INCLUDES}) \ No newline at end of file +target_include_directories(BulletExchanger_F103_drivers PUBLIC ${DRIVER_INCLUDES}) diff --git a/boards/drivers/include/protocol.h b/boards/drivers/include/protocol.h index f9b6e652..93c963cf 100644 --- a/boards/drivers/include/protocol.h +++ b/boards/drivers/include/protocol.h @@ -26,6 +26,7 @@ #include "bsp_usb.h" #include "connection_driver.h" #include "dji_remote.h" +#include "protocols/refereerc_receiver.h" namespace communication { @@ -46,6 +47,7 @@ namespace communication { * @return true for success; false for failure */ bool Receive(package_t package); + const remote::RefereeRcReceiver& Vt13() const { return refereerc_receiver_; } /** * @brief Generate the package to be sent according to the command and save to the internal @@ -63,15 +65,8 @@ namespace communication { uint8_t bufferRx[MAX_FRAME_LEN] = {0}; uint8_t bufferTx[MAX_FRAME_LEN] = {0}; - - struct { - int idx = 0; - enum mode { - WAITING_FOR_SOF, - RECEIVING_REFEREE, - RECEIVING_VT13, - } mode = WAITING_FOR_SOF; - } rx_state; + // Called only for a complete VT13 frame accepted by the new receiver. + virtual void ProcessVt13Rx(const uint8_t* data, size_t size); /** * @brief verify the header of frame with crc8 @@ -126,6 +121,12 @@ namespace communication { * @return length of the data that is copied into buffer */ virtual int ProcessDataTx(int cmd_id, uint8_t* data) = 0; + + private: + size_t rx_used_ = 0; + remote::RefereeRcReceiver refereerc_receiver_; + void DiscardRx(size_t size); + void ResyncRx(); }; class UARTProtocol : public Protocol { @@ -215,7 +216,6 @@ namespace communication { * 0x0301 STUDENT_INTERACTIVE * 0x0302 ROBOT_INTERACTIVE [x] * 0x0303 ROBOT_COMMAND [x] - * 0x0304 REMOTE_CONTROL_DATA * 0x0305 CLIENT_MAP_COMMAND [x] */ @@ -240,8 +240,6 @@ namespace communication { RFID_STATUS = 0x0209, DART_CLIENT_CMD = 0x020A, STUDENT_INTERACTIVE = 0x0301, - REMOTE_CONTROL_DATA = 0x304, - REMOTE_CONTROL_VT13 = 0x53, CUSTOM_CLIENT_DATA = 0x0306, } referee_cmd; @@ -535,7 +533,7 @@ namespace communication { uint8_t cmd_source; } __packed map_command_t; - /* ===== REMOTE_CONTROL_DATA 0x0304 30Hz ===== */ + // Obsolete 0x0304 layout, retained only for old robot source compatibility. typedef struct { remote::mouse_t mouse; remote::keyboard_t keyboard; @@ -610,7 +608,7 @@ namespace communication { custom_robot_data_t custom_robot_data{}; // 0x0302 map_command_t map_command{}; // 0x0303 - remote_control_t remote_control{}; // 0x0304 + remote_control_t remote_control{}; // Obsolete: never updated by Receive; migrate old callers. map_robot_data_t map_robot_data{}; // 0x0305 custom_client_data_t custom_client_data{}; // 0x0306 custom_client_map_command_t custom_client_map_command{}; // 0x0307 @@ -641,6 +639,7 @@ namespace communication { */ int ProcessDataTx(int cmd_id, uint8_t* data) final; + void ProcessVt13Rx(const uint8_t* data, size_t size) override; content graph_content_ = NO_GRAPH; }; diff --git a/boards/drivers/src/protocol.cpp b/boards/drivers/src/protocol.cpp index 272cf974..3881fbc3 100644 --- a/boards/drivers/src/protocol.cpp +++ b/boards/drivers/src/protocol.cpp @@ -25,6 +25,7 @@ #include "bsp_usb.h" #include "crc_check.h" #include "dji_remote.h" +#include "bsp_os.h" static const uint8_t SOF = 0xA5; static const int FRAME_HEADER_LEN = 5; @@ -33,46 +34,75 @@ static const int FRAME_TAIL_LEN = 2; static const int BYTE = 8; namespace communication { + void Protocol::DiscardRx(size_t size) { + rx_used_ -= size; + std::memmove(bufferRx, bufferRx + size, rx_used_); + } + + void Protocol::ResyncRx() { + size_t next = 1; + while (next < rx_used_ && bufferRx[next] != SOF && + bufferRx[next] != remote::RefereeRcReceiver::SOF) { + ++next; + } + DiscardRx(next); + } + + void Protocol::ProcessVt13Rx(const uint8_t* data, size_t size) { + ProcessDataRx(remote::RefereeRcReceiver::CMD, data, static_cast(size)); + } + bool Protocol::Receive(package_t package) { + if (!package.data || package.length <= 0) return false; + // Preserve the legacy link heartbeat. Input-source health is independent. Heartbeat(); + const uint32_t now_ms = bsp::GetHighresTickMilliSec(); for (int i = 0; i < package.length; ++i) { - if (rx_state.mode == rx_state.mode::WAITING_FOR_SOF) { - // 还未接收到帧头,检测是否为帧头 - if (package.data[i] == SOF) { - rx_state.mode = rx_state.mode::RECEIVING_REFEREE; - bufferRx[0] = SOF; - rx_state.idx = 1; - } else if (package.data[i] == remote::vt13_packet_t::SOF) { - rx_state.mode = rx_state.mode::RECEIVING_VT13; - bufferRx[0] = remote::vt13_packet_t::SOF; - rx_state.idx = 1; + const auto byte = package.data[i]; + if (!rx_used_ && byte != SOF && byte != remote::RefereeRcReceiver::SOF) continue; + // A5 lengths are capped below; every full candidate is consumed or + // resynchronized before the next append, keeping this buffer bounded. + bufferRx[rx_used_++] = byte; + while (rx_used_) { + if (bufferRx[0] != SOF && bufferRx[0] != remote::RefereeRcReceiver::SOF) { + ResyncRx(); + continue; } - } else if (rx_state.mode == rx_state.RECEIVING_REFEREE) { - // 接收裁判系统的数据 - bufferRx[rx_state.idx++] = package.data[i]; - - if (rx_state.idx >= FRAME_HEADER_LEN + CMD_ID_LEN + FRAME_TAIL_LEN) { - int DATA_LENGTH = bufferRx[2] << BYTE | bufferRx[1]; - if (rx_state.idx >= FRAME_HEADER_LEN + CMD_ID_LEN + DATA_LENGTH + FRAME_TAIL_LEN) { - if (VerifyHeader(bufferRx, FRAME_HEADER_LEN) && - VerifyFrame(bufferRx, FRAME_HEADER_LEN + CMD_ID_LEN + DATA_LENGTH + FRAME_TAIL_LEN)) { - int cmd_id = bufferRx[FRAME_HEADER_LEN + 1] << BYTE | bufferRx[FRAME_HEADER_LEN]; - ProcessDataRx(cmd_id, bufferRx + FRAME_HEADER_LEN + CMD_ID_LEN, DATA_LENGTH); - } - rx_state.mode = rx_state.WAITING_FOR_SOF; - rx_state.idx = 0; + if (bufferRx[0] == remote::RefereeRcReceiver::SOF) { + if (rx_used_ < 2) break; + if (bufferRx[1] != remote::RefereeRcReceiver::CMD) { + ResyncRx(); + continue; } - } - } else if (rx_state.mode == rx_state.mode::RECEIVING_VT13) { - // VT13遥控器与图传链路从同一个UART输出,包头不同。 - // Todo: 应该把图传链路和遥控器数据分开处理 - bufferRx[rx_state.idx++] = package.data[i]; - if (rx_state.idx >= static_cast(sizeof(remote::vt13_packet_t))) { - if (verify_crc16_check_sum(bufferRx, sizeof(remote::vt13_packet_t))) { - ProcessDataRx(REMOTE_CONTROL_VT13, bufferRx, sizeof(remote::vt13_packet_t)); + if (rx_used_ < remote::RefereeRcReceiver::FRAME_SIZE) break; + // Protocol owns stream framing; the receiver owns VT13 + // validation, decoding and the independent input timestamp. + refereerc_receiver_.ResetStream(); + const auto sequence = refereerc_receiver_.GetSequence(); + refereerc_receiver_.UpdateData(bufferRx, remote::RefereeRcReceiver::FRAME_SIZE, now_ms); + refereerc_receiver_.ResetStream(); + if (refereerc_receiver_.GetSequence() == sequence) { + ResyncRx(); + continue; + } + ProcessVt13Rx(bufferRx, remote::RefereeRcReceiver::FRAME_SIZE); + DiscardRx(remote::RefereeRcReceiver::FRAME_SIZE); + } else { + if (rx_used_ < FRAME_HEADER_LEN) break; + const int payload = int(bufferRx[1]) | (int(bufferRx[2]) << BYTE); + if (!VerifyHeader(bufferRx, FRAME_HEADER_LEN) || payload > MAX_FRAME_LEN - 9) { + ResyncRx(); + continue; } - rx_state.mode = rx_state.WAITING_FOR_SOF; - rx_state.idx = 0; + const int total = payload + FRAME_HEADER_LEN + CMD_ID_LEN + FRAME_TAIL_LEN; + if (rx_used_ < static_cast(total)) break; + if (!VerifyFrame(bufferRx, total)) { + ResyncRx(); + continue; + } + const int cmd = int(bufferRx[5]) | (int(bufferRx[6]) << BYTE); + ProcessDataRx(cmd, bufferRx + FRAME_HEADER_LEN + CMD_ID_LEN, payload); + DiscardRx(static_cast(total)); } } } @@ -82,7 +112,7 @@ namespace communication { package_t Protocol::Transmit(int cmd_id) { bufferTx[0] = SOF; int DATA_LENGTH = ProcessDataTx(cmd_id, bufferTx + FRAME_HEADER_LEN + CMD_ID_LEN); - if (DATA_LENGTH < 0) + if (DATA_LENGTH < 0 || DATA_LENGTH > MAX_FRAME_LEN - 9) return package_t{nullptr, 0}; bufferTx[1] = (uint8_t)((uint32_t)DATA_LENGTH & 0xFF); bufferTx[2] = (uint8_t)((uint32_t)DATA_LENGTH >> BYTE); @@ -138,7 +168,7 @@ namespace communication { package_t UARTProtocol::Transmit(int cmd_id) { package_t package = Protocol::Transmit(cmd_id); - uart_->Write(package.data, package.length); + if (package.data && package.length > 0) uart_->Write(package.data, package.length); return package; } @@ -177,7 +207,7 @@ namespace communication { package_t USBProtocol::Transmit(int cmd_id) { package_t package = Protocol::Transmit(cmd_id); - usb_->Write(package.data, package.length); + if (package.data && package.length > 0) usb_->Write(package.data, package.length); return package; } @@ -191,61 +221,72 @@ namespace communication { bool Referee::ProcessDataRx(int cmd_id, const uint8_t* data, int length) { switch (cmd_id) { case GAME_STATUS: - memcpy(&game_status, data, length); + if (length != static_cast(sizeof(game_status))) return false; + memcpy(&game_status, data, sizeof(game_status)); break; case GAME_RESULT: - memcpy(&game_result, data, length); + if (length != static_cast(sizeof(game_result))) return false; + memcpy(&game_result, data, sizeof(game_result)); break; case GAME_ROBOT_HP: - memcpy(&game_robot_HP, data, length); + if (length != static_cast(sizeof(game_robot_HP))) return false; + memcpy(&game_robot_HP, data, sizeof(game_robot_HP)); break; case EVENT_DATA: - memcpy(&event_data, data, length); + if (length != static_cast(sizeof(event_data))) return false; + memcpy(&event_data, data, sizeof(event_data)); break; case SUPPLY_PROJECTILE_ACTION: - memcpy(&supply_projectile_action, data, length); + if (length != static_cast(sizeof(supply_projectile_action))) return false; + memcpy(&supply_projectile_action, data, sizeof(supply_projectile_action)); break; case REFEREE_WARNING: - memcpy(&referee_warning, data, length); + if (length != static_cast(sizeof(referee_warning))) return false; + memcpy(&referee_warning, data, sizeof(referee_warning)); break; case DART_REMAINING_TIME: - memcpy(&dart_remaining_time, data, length); + if (length != static_cast(sizeof(dart_remaining_time))) return false; + memcpy(&dart_remaining_time, data, sizeof(dart_remaining_time)); break; case GAME_ROBOT_STATUS: - memcpy(&game_robot_status, data, length); + if (length != static_cast(sizeof(game_robot_status))) return false; + memcpy(&game_robot_status, data, sizeof(game_robot_status)); break; case POWER_HEAT_DATA: - memcpy(&power_heat_data, data, length); + if (length != static_cast(sizeof(power_heat_data))) return false; + memcpy(&power_heat_data, data, sizeof(power_heat_data)); break; case GAME_ROBOT_POS: - memcpy(&game_robot_pos, data, length); + if (length != static_cast(sizeof(game_robot_pos))) return false; + memcpy(&game_robot_pos, data, sizeof(game_robot_pos)); break; case BUFF: - memcpy(&buff, data, length); + if (length != static_cast(sizeof(buff))) return false; + memcpy(&buff, data, sizeof(buff)); break; case AERIAL_ROBOT_ENERGY: - memcpy(&aerial_robot_energy, data, length); + if (length != static_cast(sizeof(aerial_robot_energy))) return false; + memcpy(&aerial_robot_energy, data, sizeof(aerial_robot_energy)); break; case ROBOT_HURT: - memcpy(&robot_hurt, data, length); + if (length != static_cast(sizeof(robot_hurt))) return false; + memcpy(&robot_hurt, data, sizeof(robot_hurt)); break; case SHOOT_DATA: - memcpy(&shoot_data, data, length); + if (length != static_cast(sizeof(shoot_data))) return false; + memcpy(&shoot_data, data, sizeof(shoot_data)); break; case BULLET_REMAINING: - memcpy(&bullet_remaining, data, length); + if (length != static_cast(sizeof(bullet_remaining))) return false; + memcpy(&bullet_remaining, data, sizeof(bullet_remaining)); break; case RFID_STATUS: - memcpy(&rfid_status, data, length); + if (length != static_cast(sizeof(rfid_status))) return false; + memcpy(&rfid_status, data, sizeof(rfid_status)); break; case DART_CLIENT_CMD: - memcpy(&dart_client_cmd, data, length); - break; - case REMOTE_CONTROL_DATA: - memcpy(&remote_control, data, length); - break; - case REMOTE_CONTROL_VT13: - memcpy(&vt13_packet, data, length); + if (length != static_cast(sizeof(dart_client_cmd))) return false; + memcpy(&dart_client_cmd, data, sizeof(dart_client_cmd)); break; default: return false; @@ -253,6 +294,11 @@ namespace communication { return true; } + void Referee::ProcessVt13Rx(const uint8_t* data, size_t size) { + // Wire-compatible snapshot only; validation/decoding lives in RefereeRcReceiver. + if (size == sizeof(vt13_packet)) memcpy(&vt13_packet, data, size); + } + int Referee::ProcessDataTx(int cmd_id, uint8_t* data) { int data_len; switch (cmd_id) { @@ -299,8 +345,6 @@ namespace communication { default: data_len = -1; } - if (data_len > 0) - uart_->Write(data, data_len); return data_len; } @@ -314,35 +358,45 @@ namespace communication { bool Host::ProcessDataRx(int cmd_id, const uint8_t* data, int length) { switch (cmd_id) { case PACK: - memcpy(&pack, data, length); + if (length != static_cast(sizeof(pack))) return false; + memcpy(&pack, data, sizeof(pack)); break; case TARGET_ANGLE: // memset(&target_angle, 0, sizeof(target_angle)); - memcpy(&target_angle, data, length); + if (length != static_cast(sizeof(target_angle))) return false; + memcpy(&target_angle, data, sizeof(target_angle)); break; case NO_TARGET_FLAG: - memcpy(&no_target_flag, data, length); + if (length != static_cast(sizeof(no_target_flag))) return false; + memcpy(&no_target_flag, data, sizeof(no_target_flag)); break; case SHOOT_CMD: - memcpy(&shoot_cmd, data, length); + if (length != static_cast(sizeof(shoot_cmd))) return false; + memcpy(&shoot_cmd, data, sizeof(shoot_cmd)); break; case ROBOT_MOVE_SPEED: - memcpy(&robot_move, data, length); + if (length != static_cast(sizeof(robot_move))) return false; + memcpy(&robot_move, data, sizeof(robot_move)); break; case ROBOT_POWER_HEAT_HP_UPLOAD: - memcpy(&robot_power_heat_hp_upload, data, length); + if (length != static_cast(sizeof(robot_power_heat_hp_upload))) return false; + memcpy(&robot_power_heat_hp_upload, data, sizeof(robot_power_heat_hp_upload)); break; case GIMBAL_CURRENT_STATUS: - memcpy(&gimbal_current_status, data, length); + if (length != static_cast(sizeof(gimbal_current_status))) return false; + memcpy(&gimbal_current_status, data, sizeof(gimbal_current_status)); break; case CHASSIS_CURRENT_STATUS: - memcpy(&chassis_current_status, data, length); + if (length != static_cast(sizeof(chassis_current_status))) return false; + memcpy(&chassis_current_status, data, sizeof(chassis_current_status)); break; case AUTOAIM_ENABLE: - memcpy(&autoaim_enable, data, length); + if (length != static_cast(sizeof(autoaim_enable))) return false; + memcpy(&autoaim_enable, data, sizeof(autoaim_enable)); break; case ROBOT_STATUS_UPLOAD: - memcpy(&robot_status_upload, data, length); + if (length != static_cast(sizeof(robot_status_upload))) return false; + memcpy(&robot_status_upload, data, sizeof(robot_status_upload)); break; default: return false; @@ -408,35 +462,45 @@ namespace communication { bool HostUSB::ProcessDataRx(int cmd_id, const uint8_t* data, int length) { switch (cmd_id) { case PACK: - memcpy(&pack, data, length); + if (length != static_cast(sizeof(pack))) return false; + memcpy(&pack, data, sizeof(pack)); break; case TARGET_ANGLE: // memset(&target_angle, 0, sizeof(target_angle)); - memcpy(&target_angle, data, length); + if (length != static_cast(sizeof(target_angle))) return false; + memcpy(&target_angle, data, sizeof(target_angle)); break; case NO_TARGET_FLAG: - memcpy(&no_target_flag, data, length); + if (length != static_cast(sizeof(no_target_flag))) return false; + memcpy(&no_target_flag, data, sizeof(no_target_flag)); break; case SHOOT_CMD: - memcpy(&shoot_cmd, data, length); + if (length != static_cast(sizeof(shoot_cmd))) return false; + memcpy(&shoot_cmd, data, sizeof(shoot_cmd)); break; case ROBOT_MOVE_SPEED: - memcpy(&robot_move, data, length); + if (length != static_cast(sizeof(robot_move))) return false; + memcpy(&robot_move, data, sizeof(robot_move)); break; case ROBOT_POWER_HEAT_HP_UPLOAD: - memcpy(&robot_power_heat_hp_upload, data, length); + if (length != static_cast(sizeof(robot_power_heat_hp_upload))) return false; + memcpy(&robot_power_heat_hp_upload, data, sizeof(robot_power_heat_hp_upload)); break; case GIMBAL_CURRENT_STATUS: - memcpy(&gimbal_current_status, data, length); + if (length != static_cast(sizeof(gimbal_current_status))) return false; + memcpy(&gimbal_current_status, data, sizeof(gimbal_current_status)); break; case CHASSIS_CURRENT_STATUS: - memcpy(&chassis_current_status, data, length); + if (length != static_cast(sizeof(chassis_current_status))) return false; + memcpy(&chassis_current_status, data, sizeof(chassis_current_status)); break; case AUTOAIM_ENABLE: - memcpy(&autoaim_enable, data, length); + if (length != static_cast(sizeof(autoaim_enable))) return false; + memcpy(&autoaim_enable, data, sizeof(autoaim_enable)); break; case ROBOT_STATUS_UPLOAD: - memcpy(&robot_status_upload, data, length); + if (length != static_cast(sizeof(robot_status_upload))) return false; + memcpy(&robot_status_upload, data, sizeof(robot_status_upload)); break; default: return false; diff --git a/boards/remote/CMakeLists.txt b/boards/remote/CMakeLists.txt new file mode 100644 index 00000000..eb1a9dfd --- /dev/null +++ b/boards/remote/CMakeLists.txt @@ -0,0 +1,9 @@ +set(UICRM_REMOTE_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/protocols/dbus_receiver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/protocols/sbus_receiver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/protocols/refereerc_receiver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/controller/fs_i6x_receiver.cpp) + +# The board-specific driver libraries compile these sources with their own target settings. +set(UICRM_REMOTE_SOURCES ${UICRM_REMOTE_SOURCES} PARENT_SCOPE) +set(UICRM_REMOTE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE) diff --git a/boards/remote/include/protocols/dbus_receiver.h b/boards/remote/include/protocols/dbus_receiver.h new file mode 100644 index 00000000..8f15eea5 --- /dev/null +++ b/boards/remote/include/protocols/dbus_receiver.h @@ -0,0 +1,192 @@ +/*########################################################### + # Copyright (c) 2026-2027. BNBU/UIC RoboMaster # + # # + # This program is free software: you can redistribute it # + # and/or modify it under the terms of the GNU General # + # Public License as published by the Free Software # + # Foundation, either version 3 of the License, or (at # + # your option) any later version. # + # # + # This program is distributed in the hope that it will be # + # useful, but WITHOUT ANY WARRANTY; without even # + # the implied warranty of MERCHANTABILITY or FITNESS # + # FOR A PARTICULAR PURPOSE. See the GNU General # + # Public License for more details. # + # # + # You should have received a copy of the GNU General # + # Public License along with this program. If not, see # + # . # + ###########################################################*/ + +#pragma once + +#include + +#include "remote.h" +#include "bsp_uart.h" + +namespace remote { + /** @brief DBUS 拨杆位置,数值与协议编码一致。 */ + enum class DbusSwitchPosition : uint8_t { + Up = 1, ///< 上 + Down = 2, ///< 下 + Middle = 3 ///< 中 + }; + + /** + * @brief DBUS 鼠标输入,保持协议中的原始有符号数值。 + * @details 三轴范围均为 -32768~32767,静止值为 0,不套用摇杆的 ±660 范围或死区。 + * 原始左右键字段必须为 0 或 1,否则拒绝整帧;输出 false 表示松开,true 表示按下。 + */ + struct DbusMouseState { + int16_t x = 0; ///< 鼠标 X 轴输入,范围 -32768~32767。 + int16_t y = 0; ///< 鼠标 Y 轴输入,范围 -32768~32767。 + int16_t z = 0; ///< 鼠标滚轮输入,范围 -32768~32767。 + bool left = false; ///< 鼠标左键是否按下。 + bool right = false; ///< 鼠标右键是否按下。 + }; + + /** + * @brief DBUS 键盘状态,按旧 API 提供完整位图 code 和按键位域 bit。 + * @details 位序沿用旧代码;多个按键可同时为 1,不采用旧版手册中不同的键位定义。 + * code 与 bit 共享存储,支持 keyboard.code 或 keyboard.bit.W 等访问。 + * code 范围为 0~65535,每个按键位只能为 0 或 1,多个按键可同时按下。 + * @note 位域视图采用本项目 GCC/ARM 布局;线上数据仍按小端字节显式解码, + * 不把接收缓存强制转换为该类型。新编译器平台须验证位域布局。 + */ + union DbusKeyboardState { + uint16_t code = 0; ///< 完整 16 位按键位图,默认没有按键按下。 + struct { + uint16_t W : 1; ///< bit0:W 键是否按下。 + uint16_t S : 1; ///< bit1:S 键是否按下。 + uint16_t A : 1; ///< bit2:A 键是否按下。 + uint16_t D : 1; ///< bit3:D 键是否按下。 + uint16_t SHIFT : 1; ///< bit4:SHIFT 键是否按下。 + uint16_t CTRL : 1; ///< bit5:CTRL 键是否按下。 + uint16_t Q : 1; ///< bit6:Q 键是否按下。 + uint16_t E : 1; ///< bit7:E 键是否按下。 + uint16_t R : 1; ///< bit8:R 键是否按下。 + uint16_t F : 1; ///< bit9:F 键是否按下。 + uint16_t G : 1; ///< bit10:G 键是否按下。 + uint16_t Z : 1; ///< bit11:Z 键是否按下。 + uint16_t X : 1; ///< bit12:X 键是否按下。 + uint16_t C : 1; ///< bit13:C 键是否按下。 + uint16_t V : 1; ///< bit14:V 键是否按下。 + uint16_t B : 1; ///< bit15:B 键是否按下。 + } __attribute__((packed)) bit; + } __attribute__((packed)); + static_assert(sizeof(DbusKeyboardState) == 2, "DBUS keyboard must occupy two bytes"); + + /** + * @brief DBUS 有效帧快照,通道数值沿用旧 DBUS 的减中心与死区处理。 + * @details 原始值减去 1024,绝对值不大于 10 时置零,正常行程为 -660~660。 + * 不额外缩放或限幅;任何通道的原始值超出 364~1684 时拒绝整帧。 + */ + struct DbusFrame { + /** + * @brief 五个通道的有符号输入值,正常行程为 -660~660,中心为 0。 + * @details 下标 0:右摇杆 X;1:右摇杆 Y;2:左摇杆 X;3:左摇杆 Y;4:左拨轮。 + * 摇杆方向沿用旧代码:X 左负右正,Y 上负下正;拨轮方向沿用设备原编码。 + * @note 遥控器的样式 + * + * ch4() + * + * L_sw* *R_sw + * ch3-^ ^-ch1 + * ch2-< >+ -< >+ch0 + * +v v+ + */ + std::array channels{}; + DbusSwitchPosition right_switch = DbusSwitchPosition::Middle; ///< 右拨杆位置。 + DbusSwitchPosition left_switch = DbusSwitchPosition::Middle; ///< 左拨杆位置。 + DbusMouseState mouse{}; ///< 鼠标状态。 + DbusKeyboardState keyboard{}; ///< 键盘状态,支持 code 和 bit 按键访问。 + }; + + /** + * @brief DBUS 18 字节接收器,支持通过 UART 句柄构造后自动接收。 + * @details DBUS 无帧头及 CRC,校验长度、拨杆、鼠标按钮和配置的通道范围。 + * 字段合理性检查不能保证完整性,也不能用于猜测字节流的帧边界。 + * @note UART 模式内部通过 IDLE 回调接收;跨 ISR/任务读取仍须同步保护。 + */ + class DbusReceiver final : public RemoteReceiver { + public: + static constexpr size_t FRAME_SIZE = 18; ///< 单帧长度,单位字节。 + static constexpr uint16_t CHANNEL_MIN = 364; ///< 原始通道有效下限。 + static constexpr uint16_t CHANNEL_MAX = 1684; ///< 原始通道有效上限。 + + /** + * @brief 绑定并拥有 UART 接收对象,自动配置缓存和接收回调。 + * @param[in] huart 已完成板级配置的 UART 句柄,不得为同一 UART 重复创建接收对象。 + * @param[in] online_threshold_ms 在线超时,单位毫秒,默认 250。 + * @note 波特率、偶校验、停止位及反相仍由板级配置负责;对象须覆盖中断使用周期。 + */ + explicit DbusReceiver(UART_HandleTypeDef* huart, uint32_t online_threshold_ms = 250); + + /** + * @brief 复用旧包装已拥有的 UART,不创建第二个 UART 对象。 + * @param[in] uart 已存在的 UART,生命周期须长于本接收器。 + * @note 兼容包装在自身回调中调用 RxCompleteCallback;本构造不替换原回调。 + */ + explicit DbusReceiver(bsp::UART& uart, uint32_t online_threshold_ms = 250); + + /** @brief 释放本接收器拥有的 UART;借用的 UART 不释放。 */ + ~DbusReceiver() override; + + DbusReceiver(const DbusReceiver&) = delete; + + DbusReceiver& operator=(const DbusReceiver&) = delete; + + /** @brief 使用系统毫秒时钟判断有效 DBUS 帧是否在线,无需调用方传时间。 */ + bool IsOnline() const; + + /** @brief UART 接收回调入口,读取接收块并按 IDLE 边界校验;UART 模式自动调用。 */ + void RxCompleteCallback(); + + /** + * @brief 输入具有明确边界的完整 DBUS 接收块,一次调用只处理一帧。 + * @param[in] data 接收块地址,须从帧起点开始,调用结束后不保留该指针。 + * @param[in] size 接收块字节数,必须恰好为 FRAME_SIZE(18 字节)。 + * @param[in] now_ms 本块接收时间,单位毫秒。 + * @details UART IDLE 回调自动调用本接口;手动接入时调用方负责提供帧边界。 + * 空指针、错误长度或无效字段不修改状态、序号或有效帧时间。 + * @note 不累积半包,不拆分多帧块;5+13 字节的两次调用和一次 36 字节输入均拒绝。 + */ + void UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) override; + + /** + * @brief 拷贝最后一帧有效状态。 + * @param[out] output 成功时接收完整快照;失败时保持原值。 + * @return 曾接收有效帧时为 true,否则为 false。 + * @note 离线后仍可读取最后状态;用于控制前须另行判断 IsOnline。 + */ + bool GetState(DbusFrame& output) const; + + /** + * @brief 设置五个通道统一使用的原始值校验范围,默认 364~1684。 + * @param[in] minimum 允许的最小值,包含边界。 + * @param[in] maximum 允许的最大值,包含边界。 + * @return 364 <= minimum <= maximum <= 1684 时为 true;否则返回 false 并保留配置。 + * @note 参数使用线上的原始编码值,仅影响后续帧校验;输出仍按旧 DBUS 语义减中心并处理死区。 + */ + bool SetChannelRange(uint16_t minimum, uint16_t maximum); + + private: + /** + * @brief 校验并解码一帧,对有效数据更新快照并提交状态。 + * @param[in] data 已收齐的 FRAME_SIZE 字节候选帧。 + * @param[in] now_ms 本帧接收时间,单位毫秒。 + * @return 校验通过并提交时为 true,否则为 false。 + * @details 校验五通道原始范围、左右拨杆及鼠标按钮;转换通道中心与死区,解码键鼠。 + * 所有校验通过后才整体替换最后状态并调用 CommitValidFrame;失败时状态、序号及有效时间不变。 + * @note 仅由内部完整候选帧入口调用,不负责收集半包或恢复字节边界。 + */ + bool Decode(const uint8_t* data, uint32_t now_ms); + static void UartCallback(void* context); ///< UART 回调转发入口。 + bsp::UART* uart_ = nullptr; ///< 内部拥有或旧包装借用的 UART。 + bool owns_uart_ = false; ///< 是否负责销毁 UART。 + uint16_t channel_min_ = CHANNEL_MIN; ///< 原始通道值校验下限。 + uint16_t channel_max_ = CHANNEL_MAX; ///< 原始通道值校验上限。 + DbusFrame state_{}; ///< 最后一帧有效状态。 + }; +} // namespace remote diff --git a/boards/remote/include/protocols/refereerc_receiver.h b/boards/remote/include/protocols/refereerc_receiver.h new file mode 100644 index 00000000..1c72f5e3 --- /dev/null +++ b/boards/remote/include/protocols/refereerc_receiver.h @@ -0,0 +1,145 @@ +/*########################################################### +# Copyright (c) 2026-2027. BNBU/UIC RoboMaster # + # # + # This program is free software: you can redistribute it # + # and/or modify it under the terms of the GNU General # + # Public License as published by the Free Software # + # Foundation, either version 3 of the License, or (at # + # your option) any later version. # + # # + # This program is distributed in the hope that it will be # + # useful, but WITHOUT ANY WARRANTY; without even # + # the implied warranty of MERCHANTABILITY or FITNESS # + # FOR A PARTICULAR PURPOSE. See the GNU General # + # Public License for more details. # + # # + # You should have received a copy of the GNU General # + # Public License along with this program. If not, see # + # . # + ###########################################################*/ +#pragma once + +#include + +#include "remote.h" + +namespace remote { + /** @brief VT13 模式编码;是否允许控制由本车逻辑决定。 */ + enum class Vt13Mode : uint8_t { + C = 0, ///< C 模式。 + N = 1, ///< N 模式。 + S = 2 ///< S 模式。 + }; + + /** @brief VT13 鼠标输入,保留协议中的原始有符号数值。 */ + struct Vt13MouseState { + int16_t x = 0; ///< 鼠标 X 轴输入。 + int16_t y = 0; ///< 鼠标 Y 轴输入。 + int16_t z = 0; ///< 鼠标滚轮输入。 + bool left = false; ///< 鼠标左键是否按下。 + bool right = false; ///< 鼠标右键是否按下。 + bool middle = false; ///< 鼠标中键是否按下。 + }; + + /** + * @brief VT13 键盘状态,提供完整位图 code 和命名按键位域 bit。 + * @details 位序与 VT13 协议及旧 keyboard_t 一致;多个按键可同时按下。 + * code 与 bit 共享两字节存储,code 默认为 0,各按键位 0 表示松开、1 表示按下。 + * @note 位域视图采用本项目 GCC/ARM 布局;线上数据仍按小端字节显式解码, + * 不将接收缓存强制转换为此类型。更换编译器平台须验证位域布局。 + */ + union Vt13KeyboardState { + uint16_t code = 0; ///< 完整 16 位按键位图,范围 0~65535。 + struct { + uint16_t W : 1; ///< bit0:W 键。 + uint16_t S : 1; ///< bit1:S 键。 + uint16_t A : 1; ///< bit2:A 键。 + uint16_t D : 1; ///< bit3:D 键。 + uint16_t SHIFT : 1; ///< bit4:SHIFT 键。 + uint16_t CTRL : 1; ///< bit5:CTRL 键。 + uint16_t Q : 1; ///< bit6:Q 键。 + uint16_t E : 1; ///< bit7:E 键。 + uint16_t R : 1; ///< bit8:R 键。 + uint16_t F : 1; ///< bit9:F 键。 + uint16_t G : 1; ///< bit10:G 键。 + uint16_t Z : 1; ///< bit11:Z 键。 + uint16_t X : 1; ///< bit12:X 键。 + uint16_t C : 1; ///< bit13:C 键。 + uint16_t V : 1; ///< bit14:V 键。 + uint16_t B : 1; ///< bit15:B 键。 + } __attribute__((packed)) bit; + } __attribute__((packed)); + static_assert(sizeof(Vt13KeyboardState) == 2, "VT13 keyboard must occupy two bytes"); + + /** @brief VT13 有效帧快照,通道减中心并处理死区,不包含本车控制映射。 */ + struct Vt13Frame { + /** + * @brief 五通道减去 1024,包含 ±10 死区;不缩放或额外限幅。 + * @details 输出范围 -660~660,中心为 0;顺序为右 X/Y、左 Y/X、拨轮。 + */ + std::array channels{}; + Vt13Mode mode = Vt13Mode::C; ///< 模式选择,不自动转换为协议失控标志。 + bool pause = false; ///< 暂停按钮状态。 + bool left_button = false; ///< 遥控器左侧按钮状态,与鼠标左键不同。 + bool right_button = false; ///< 遥控器右侧按钮状态,与鼠标右键不同。 + bool trigger = false; ///< 扳机状态。 + Vt13MouseState mouse{}; ///< 鼠标状态。 + Vt13KeyboardState keyboard{}; ///< 键盘状态,支持 code 和 bit 按键访问。 + uint16_t crc16 = 0; ///< 已通过校验的帧内 CRC16 值。 + }; + + /** + * @brief VT13 21 字节遥控协议接收器,无 UART、HAL 或系统时钟依赖。 + * @details 验证 0xA9 帧头、0x53 命令字、既有 CRC16、合法模式 0/1/2、 + * 五通道范围 364~1684,以及各占两位的鼠标左/右/中键编码 0/1。 + * 仅有效帧更新数据和独立在线时间,N/S 模式及暂停按钮不自动视为协议失控。 + * @note VT13 由图传链路承载;A5/A9 混合分帧位于 protocol.cpp,不属于本接收器职责。 + * 所有输入与读取须由接入层同步保护。 + */ + class RefereeRcReceiver final : public RemoteReceiver { + public: + static constexpr size_t FRAME_SIZE = 21; ///< 单帧长度,单位字节。 + static constexpr uint8_t SOF = 0xA9; ///< VT13 帧头。 + static constexpr uint8_t CMD = 0x53; ///< VT13 命令字。 + static constexpr uint16_t CHANNEL_MIN = 364; ///< 五通道原始值有效下限,包含边界。 + static constexpr uint16_t CHANNEL_MAX = 1684; ///< 五通道原始值有效上限,包含边界。 + static constexpr uint16_t CHANNEL_CENTER = 1024; + static constexpr int16_t CHANNEL_DEADZONE = 10; + /** @brief 继承基类构造,可传入在线超时毫秒数,默认 250。 */ + using RemoteReceiver::RemoteReceiver; + + /** + * @brief 输入纯 VT13 字节流,支持半包、连续帧及错误后的后缀恢复。 + * @param[in] data 接收字节地址,空指针不提交状态,调用结束后不保留该指针。 + * @param[in] size 数据字节数。 + * @param[in] now_ms 本次输入的时间,单位毫秒;完成的有效帧使用此时间提交。 + * @warning 不直接输入混合 A5/A9 图传流,应由 Protocol::Receive 完成分帧后接入。 + */ + void UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) override; + + /** @brief 清除暂存半包,保留最后有效状态、序号和接收时间。 */ + void ResetStream(); + + /** + * @brief 拷贝最后一帧有效状态。 + * @param[out] output 成功时接收完整快照;失败时保持原值。 + * @return 曾接收有效帧时为 true,否则为 false。 + * @note 离线后仍可读取最后状态;控制前须检查 IsOnline 及本车模式允许条件。 + */ + bool GetState(Vt13Frame& output) const; + + private: + /** + * @brief 校验并解码内部缓存的完整候选帧,对有效数据更新快照并提交状态。 + * @param[in] now_ms 本帧接收时间,单位毫秒。 + * @return 校验通过并提交时为 true,否则为 false。 + * @details 校验帧头、命令字、CRC16、模式编码、通道范围及鼠标按钮;解码五通道、控制按钮和键鼠。 + * 所有校验通过后才整体替换最后状态并调用 CommitFrame;失败时状态、序号及有效时间不变。 + * @note 仅由内部完整候选帧入口调用,不负责收集半包或恢复字节边界。 + */ + bool Decode(uint32_t now_ms); + std::array buffer_{}; ///< 候选帧缓存。 + size_t used_ = 0; ///< 已缓存字节数。 + Vt13Frame state_{}; ///< 最后一帧有效状态。 + }; +} // namespace remote diff --git a/boards/remote/include/protocols/sbus_receiver.h b/boards/remote/include/protocols/sbus_receiver.h new file mode 100644 index 00000000..e0f39523 --- /dev/null +++ b/boards/remote/include/protocols/sbus_receiver.h @@ -0,0 +1,126 @@ +/*########################################################### +# Copyright (c) 2026-2027. BNBU/UIC RoboMaster # + # # + # This program is free software: you can redistribute it # + # and/or modify it under the terms of the GNU General # + # Public License as published by the Free Software # + # Foundation, either version 3 of the License, or (at # + # your option) any later version. # + # # + # This program is distributed in the hope that it will be # + # useful, but WITHOUT ANY WARRANTY; without even # + # the implied warranty of MERCHANTABILITY or FITNESS # + # FOR A PARTICULAR PURPOSE. See the GNU General # + # Public License for more details. # + # # + # You should have received a copy of the GNU General # + # Public License along with this program. If not, see # + # . # + ###########################################################*/ +#pragma once + +#include + +#include "bsp_uart.h" +#include "remote.h" + +namespace remote { + /** @brief SBUS 有效帧快照,保留原始通道和协议标志,不做本车控制映射。 */ + struct SbusFrame { + std::array channels{}; ///< 原始 11 位值 0~2047,下标 0 对应通道 1;部件映射由设备配置决定。 + uint8_t flags = 0; ///< 原始标志字节。 + bool channel17 = false; ///< 数字通道 17。 + bool channel18 = false; ///< 数字通道 18。 + bool frame_lost = false; ///< 接收机报告丢帧,不自动等同于失控。 + bool failsafe = false; ///< 接收机报告失控;有效失控帧仍会刷新通信在线。 + }; + + /** + * @brief SBUS 25 字节流接收器,支持通过 UART 句柄构造后自动接收。 + * @details 按 0x0F 帧头及配置的尾字节识别候选帧,支持半包、连续帧与错误后的后缀恢复。 + * SBUS 无 CRC,帧头和尾字节检查不能保证数据完整性。通道不减中心、不做死区或限幅。 + * @note 不绑定设备的摇杆、拨杆或通道端点;所有调用与状态读取须由接入层同步。 + */ + class SbusReceiver final : public RemoteReceiver { + public: + static constexpr size_t FRAME_SIZE = 25; ///< 单帧长度,单位字节。 + /** + * @brief 创建手动输入模式接收器,设置在线超时及允许的帧尾字节,不创建 UART。 + * @param[in] online_threshold_ms 在线超时,单位毫秒,默认 250。 + * @param[in] footer 唯一允许的帧尾字节,默认 0x00,须按实际接收机配置。 + */ + explicit SbusReceiver(uint32_t online_threshold_ms = 250, uint8_t footer = 0x00); + /** + * @brief 创建并拥有 UART 接收对象,自动配置缓存和注册接收回调。 + * @param[in] huart 已完成板级配置的 UART 句柄,不得重复绑定同一 UART。 + * @param[in] online_threshold_ms 在线超时,单位毫秒,默认 250。 + * @param[in] footer 唯一允许的帧尾字节,默认 0x00。 + * @note 波特率、数据位、校验位、停止位及反相由板级配置;对象须覆盖中断使用周期。 + */ + explicit SbusReceiver(UART_HandleTypeDef* huart, uint32_t online_threshold_ms = 250, + uint8_t footer = 0x00); + /** + * @brief 借用旧兼容包装的 UART,不创建第二个 UART、不替换原回调。 + * @param[in] uart 生命周期须长于本接收器的 UART 对象。 + * @param[in] online_threshold_ms 在线超时,单位毫秒,默认 250。 + * @param[in] footer 唯一允许的帧尾字节,默认 0x00。 + * @note 包装在自身回调中调用 RxCompleteCallback,接收器内部完成数据读取。 + */ + explicit SbusReceiver(bsp::UART& uart, uint32_t online_threshold_ms = 250, + uint8_t footer = 0x00); + /** @brief 释放本接收器拥有的 UART;借用的 UART 不释放。 */ + ~SbusReceiver() override; + SbusReceiver(const SbusReceiver&) = delete; + SbusReceiver& operator=(const SbusReceiver&) = delete; + /** @brief 使用系统毫秒时钟判断最近有效帧是否在线;失控标志须另行查询。 */ + bool IsOnline() const; + /** @brief 保留显式时钟查询,供手动输入和测试使用。 */ + using RemoteReceiver::IsOnline; + /** + * @brief UART 回调入口,读取接收块并交给流解析;UART 模式自动调用。 + * @note IDLE 块可以是半包或连续数据,不要求等于一帧;读取失败时清除半包。 + */ + void RxCompleteCallback(); + /** + * @brief 输入 SBUS 字节流,内部暂存半包并提交完整有效帧。 + * @param[in] data 接收字节地址,空指针不提交状态,调用结束后不保留该指针。 + * @param[in] size 数据字节数。 + * @param[in] now_ms 本次输入的时间,单位毫秒;完成的有效帧使用此时间提交。 + * @note 有效失控帧仍更新状态与在线时间,控制前须同时检查 IsFailsafe。 + */ + void UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) override; + /** @brief 清除暂存半包,保留最后有效状态、序号和接收时间。 */ + void ResetStream(); + /** + * @brief 拷贝最后一帧有效状态。 + * @param[out] output 成功时接收完整快照;失败时保持原值。 + * @return 曾接收有效帧时为 true,否则为 false。 + * @note 离线后仍可读取最后状态;控制前须检查 IsOnline 和 IsFailsafe。 + */ + bool GetState(SbusFrame& output) const; + /** + * @brief 修改唯一允许的帧尾字节,并清除暂存半包。 + * @param[in] footer 实际接收机使用的帧尾字节。 + * @note 不清除最后有效状态、序号或接收时间;不会自动接受其他尾字节变体。 + */ + void SetFooter(uint8_t footer); + + private: + /** + * @brief 校验并解码内部缓存的完整候选帧,对有效数据更新快照并提交状态。 + * @param[in] now_ms 本帧接收时间,单位毫秒。 + * @return 校验通过并提交时为 true,否则为 false。 + * @details 校验帧头与配置的尾字节;解码 16 个原始通道及数字通道、丢帧和失控标志。 + * 所有校验通过后才整体替换最后状态并调用 CommitFrame;失败时状态、序号及有效时间不变。 + * @note 仅由内部完整候选帧入口调用,不负责收集半包或恢复字节边界。 + */ + bool Decode(uint32_t now_ms); + static void UartCallback(void* context); ///< UART 回调转发入口。 + bsp::UART* uart_ = nullptr; ///< 内部拥有或旧包装借用的 UART。 + bool owns_uart_ = false; ///< 是否负责销毁 UART。 + std::array buffer_{}; ///< 候选帧缓存。 + size_t used_ = 0; ///< 已缓存字节数。 + uint8_t footer_; ///< 唯一允许的帧尾字节。 + SbusFrame state_{}; ///< 最后一帧有效状态。 + }; +} // namespace remote diff --git a/boards/remote/include/remote.h b/boards/remote/include/remote.h new file mode 100644 index 00000000..5db9532d --- /dev/null +++ b/boards/remote/include/remote.h @@ -0,0 +1,188 @@ +/*########################################################### +# Copyright (c) 2026-2027. BNBU/UIC RoboMaster # + # # + # This program is free software: you can redistribute it # + # and/or modify it under the terms of the GNU General # + # Public License as published by the Free Software # + # Foundation, either version 3 of the License, or (at # + # your option) any later version. # + # # + # This program is distributed in the hope that it will be # + # useful, but WITHOUT ANY WARRANTY; without even # + # the implied warranty of MERCHANTABILITY or FITNESS # + # FOR A PARTICULAR PURPOSE. See the GNU General # + # Public License for more details. # + # # + # You should have received a copy of the GNU General # + # Public License along with this program. If not, see # + # . # + ###########################################################*/ +#pragma once + +#include +#include +#include +#include + +/** @brief 遥控协议解析与状态管理。 */ +namespace remote { + /** + * @brief 遥控接收器的公共状态接口。 + * @details 仅管理有效帧序号、接收时间及协议失控标志,不统一各协议的通道布局。 + * UART、时钟和控制映射由接入层提供。校验失败或数据未收齐时不提交状态。 + * @note 所有方法须在同一线程调用或由接入层同步保护,不保证跨 ISR/任务的原子快照。 + */ + class RemoteReceiver { + public: + /** + * @brief 设置接收器的初始在线超时。 + * @param[in] online_threshold_ms 超时阈值,单位毫秒,默认 250。 + */ + explicit RemoteReceiver(uint32_t online_threshold_ms = 250) : online_threshold_ms_(online_threshold_ms) { + } + + /** @brief 支持通过基类指针销毁派生接收器。 */ + virtual ~RemoteReceiver() = default; + + /** + * @brief 输入接收字节,具体边界和校验规则由派生协议定义。 + * @param[in] data 接收数据地址,调用结束后不保留该指针;空指针不提交有效帧。 + * @param[in] size 数据字节数。 + * @param[in] now_ms 本次输入的时间,单位毫秒,须与 IsOnline 使用相同时间基准。 + * @note DBUS 每次输入必须是具有明确边界的完整 18 字节块;SBUS/VT13 可输入半包或连续字节流。 + */ + virtual void UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) = 0; + + /** + * @brief 判断最近一次有效帧是否仍在超时范围内。 + * @param[in] now_ms 当前时间,单位毫秒,须与 UpdateData 使用相同时间基准。 + * @return 已接收有效帧且时间差严格小于阈值时为 true,否则为 false。 + * @note 支持时间为 0 的首帧及 uint32_t 计时回绕;超过完整计时周期无法区分。 + * 在线仅表示通信仍在更新,不代表 IsFailsafe 为 false 或机器人允许控制。 + */ + bool IsOnline(uint32_t now_ms) const { + return received_ && uint32_t(now_ms - last_valid_ms_) < online_threshold_ms_; + } + + /** @brief 获取有效帧提交序号,每帧递增一次,按 uint32_t 自然回绕;首次提交前为 0。 */ + uint32_t GetSequence() const { + return sequence_; + } + + /** + * @brief 获取最近有效帧的协议失控标志。 + * @return 最近有效帧报告失控时为 true,否则为 false;首次有效帧前为 false。 + * @note 无失控标志的协议提交 false;此接口不包含超时或机器人模式判定。 + */ + bool IsFailsafe() const { + return failsafe_; + } + + /** + * @brief 获取最近一次有效帧的提交时间,单位毫秒。 + * @return 最近有效帧的 now_ms;首次提交前为 0,是否已有帧须使用 HasState 判断。 + */ + uint32_t GetLastValidTimeMs() const { + return last_valid_ms_; + } + + /** @brief 判断是否曾接收有效帧;后续超时或重置半包不会清除此标志。 */ + bool HasState() const { + return received_; + } + + /** + * @brief 修改在线超时阈值,不清除最后状态或接收时间。 + * @param[in] threshold_ms 超时阈值,单位毫秒;设为 0 时 IsOnline 始终返回 false。 + */ + void SetThreshold(uint32_t threshold_ms) { + online_threshold_ms_ = threshold_ms; + } + + protected: + /** + * @brief 派生接收器在完整校验并更新协议状态后提交有效帧。 + * @param[in] now_ms 有效帧的接收时间,单位毫秒。 + * @param[in] failsafe 当前帧的协议失控标志。 + * @details 更新接收时间及失控标志,标记已有状态,并将有效帧序号递增一次。 + */ + void CommitFrame(uint32_t now_ms, bool failsafe) { + last_valid_ms_ = now_ms; + failsafe_ = failsafe; + received_ = true; + ++sequence_; + } + + private: + uint32_t online_threshold_ms_; ///< 在线超时阈值,单位毫秒。 + uint32_t last_valid_ms_ = 0; ///< 最近有效帧时间,单位毫秒。 + uint32_t sequence_ = 0; ///< 有效帧提交序号。 + bool received_ = false; ///< 是否曾提交有效帧。 + bool failsafe_ = false; ///< 最近有效帧的协议失控标志。 + }; + /** @brief 接收器内部字节解码工具,不涉及 UART、控制映射或有效帧提交。 */ + namespace detail { + /** + * @brief 按低位优先的位序提取无符号字段,可跨越字节边界。 + * @param[in] data 数据起始地址,不得为空。 + * @param[in] bit_offset 起始位偏移,单位为位;0 表示 data[0] 的最低位。 + * @param[in] bit_count 提取位数,范围 0~16;为 0 时返回 0。 + * @return 提取后的无符号数,源起始位成为结果最低位。 + * @pre data 必须覆盖全部待读位,bit_offset + bit_count 不得溢出。 + * @note 不检查缓冲长度,不做符号扩展、数值范围校验或中心转换。 + * 例如 DecodeBits(data, 11, 11) 提取 DBUS 通道 1 的原始编码。 + */ + inline uint16_t DecodeBits(const uint8_t* data, size_t bit_offset, unsigned bit_count) { + uint16_t value = 0; + for (unsigned i = 0; i < bit_count; ++i) { + value |= uint16_t((data[(bit_offset + i) / 8] >> ((bit_offset + i) % 8)) & 1u) << i; + } + return value; + } + + /** + * @brief 从两个小端字节解码无符号 16 位整数。 + * @param[in] data 字段起始地址,须至少包含两个可读字节,不得为空。 + * @return data[0] 为低字节、data[1] 为高字节,结果范围 0~65535。 + * @note 不检查缓冲长度,与主机字节序及对齐方式无关。 + * 例如字节 {0x34, 0x12} 解码为 0x1234,可用于键盘位图和帧内 CRC 值。 + */ + inline uint16_t DecodeUint16LE(const uint8_t* data) { + return uint16_t(data[0]) | (uint16_t(data[1]) << 8); + } + + /** + * @brief 从两个小端字节解码二进制补码形式的有符号 16 位整数。 + * @param[in] data 字段起始地址,须至少包含两个可读字节,不得为空。 + * @return 保留符号的数值,范围 -32768~32767。 + * @details 先读取无符号编码;编码超过 32767 时减去 65536 得到负值。 + * @note 不检查缓冲长度,不做死区或比例转换;例如 {0xFF, 0xFF} 解码为 -1。 + */ + inline int16_t DecodeInt16LE(const uint8_t* data) { + const uint16_t value = DecodeUint16LE(data); + return static_cast(value <= 32767 ? int32_t(value) : int32_t(value) - 65536); + } + + /** + * @brief 错帧后从缓存后缀查找下一个可能的帧头,并将保留数据移到缓存起始位置。 + * @tparam N 固定缓存容量,单位字节。 + * @param[in,out] buffer 当前候选帧缓存;保留的数据可能只是下一帧的半包。 + * @param[in,out] used 调用前为有效字节数,调用后为保留字节数。 + * @param[in] sof 要查找的帧头字节,例如 SBUS 的 0x0F 或 VT13 的 0xA9。 + * @pre 1 <= used <= N,只在当前候选帧被判定无效后调用。 + * @details 从下标 1 开始查找,跳过当前无效帧头;找到后保留该字节及其后的全部数据。 + * 未找到时 used 置 0。buffer 中 used 之后的内容无效,不必清零。 + * @note 只恢复候选边界,不验证帧长度、命令字或 CRC,不修改接收器状态。 + * DBUS 没有帧头,不能使用此方法恢复对齐。 + */ + template + void FindNextFrame(std::array& buffer, size_t& used, uint8_t sof) { + size_t offset = 1; + while (offset < used && buffer[offset] != sof) { + ++offset; + } + used -= offset; + std::memmove(buffer.data(), buffer.data() + offset, used); + } + } // namespace detail +} // namespace remote diff --git a/boards/remote/src/protocols/dbus_receiver.cpp b/boards/remote/src/protocols/dbus_receiver.cpp new file mode 100644 index 00000000..e0aa976d --- /dev/null +++ b/boards/remote/src/protocols/dbus_receiver.cpp @@ -0,0 +1,115 @@ +/*########################################################### + # Copyright (c) 2026-2027. BNBU/UIC RoboMaster # + # # + # This program is free software: you can redistribute it # + # and/or modify it under the terms of the GNU General # + # Public License as published by the Free Software # + # Foundation, either version 3 of the License, or (at # + # your option) any later version. # + # # + # This program is distributed in the hope that it will be # + # useful, but WITHOUT ANY WARRANTY; without even # + # the implied warranty of MERCHANTABILITY or FITNESS # + # FOR A PARTICULAR PURPOSE. See the GNU General # + # Public License for more details. # + # # + # You should have received a copy of the GNU General # + # Public License along with this program. If not, see # + # . # + ###########################################################*/ +#include "protocols/dbus_receiver.h" + +#include "bsp_os.h" + +namespace remote { + DbusReceiver::DbusReceiver(UART_HandleTypeDef* huart, uint32_t online_threshold_ms) + : RemoteReceiver(online_threshold_ms), uart_(new bsp::UART(huart)), owns_uart_(true) { + uart_->RegisterCallback(UartCallback, this); + uart_->SetupRx(FRAME_SIZE + 1); + } + + DbusReceiver::DbusReceiver(bsp::UART& uart, uint32_t online_threshold_ms) + : RemoteReceiver(online_threshold_ms), uart_(&uart) { + uart_->SetupRx(FRAME_SIZE + 1); + } + + DbusReceiver::~DbusReceiver() { + if (owns_uart_) delete uart_; + } + + bool DbusReceiver::IsOnline() const { + return RemoteReceiver::IsOnline(bsp::GetHighresTickMilliSec()); + } + + void DbusReceiver::UartCallback(void* context) { + static_cast(context)->RxCompleteCallback(); + } + + void DbusReceiver::RxCompleteCallback() { + if (!uart_) return; + uint8_t* data = nullptr; + const int32_t length = uart_->Read(&data); + UpdateData(data, length > 0 ? static_cast(length) : 0, + bsp::GetHighresTickMilliSec()); + } + + void DbusReceiver::UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) { + // UART IDLE supplies a candidate frame boundary; only a full block is accepted. + if (data != nullptr && size == FRAME_SIZE) { + Decode(data, now_ms); + } + } + + bool DbusReceiver::SetChannelRange(uint16_t minimum, uint16_t maximum) { + if (minimum < CHANNEL_MIN || minimum > maximum || maximum > CHANNEL_MAX) { + return false; + } + channel_min_ = minimum; + channel_max_ = maximum; + return true; + } + + bool DbusReceiver::GetState(DbusFrame& output) const { + if (!HasState()) { + return false; + } + output = state_; + return true; + } + + bool DbusReceiver::Decode(const uint8_t* data, uint32_t now_ms) { + DbusFrame next; + for (size_t i = 0; i < next.channels.size(); ++i) { + // 处理 ch0-4 + const size_t offset = i < 4 ? 11 * i : 128; + const uint16_t raw = detail::DecodeBits(data, offset, 11); + + // 检测范围 364 - 1024 - 1684 + if (raw < channel_min_ || raw > channel_max_) { + return false; + } + // 原始值转通道值 + const int16_t value = static_cast(raw) - 1024; + // 死区处理 + next.channels[i] = value >= -10 && value <= 10 ? 0 : value; + } + // 处理左右拨杆 + const auto right = detail::DecodeBits(data, 44, 2); + const auto left = detail::DecodeBits(data, 46, 2); + // 检测左右拨杆范围 + 鼠标左右键(data[12]/data[13]) + if (right == 0 || left == 0 || data[12] > 1 || data[13] > 1) { + return false; + } + next.right_switch = static_cast(right); + next.left_switch = static_cast(left); + next.mouse.x = detail::DecodeInt16LE(data + 6); + next.mouse.y = detail::DecodeInt16LE(data + 8); + next.mouse.z = detail::DecodeInt16LE(data + 10); + next.mouse.left = data[12] != 0; + next.mouse.right = data[13] != 0; + next.keyboard.code = detail::DecodeUint16LE(data + 14); + state_ = next; + CommitFrame(now_ms, false); + return true; + } +} // namespace remote diff --git a/boards/remote/src/protocols/refereerc_receiver.cpp b/boards/remote/src/protocols/refereerc_receiver.cpp new file mode 100644 index 00000000..84767acf --- /dev/null +++ b/boards/remote/src/protocols/refereerc_receiver.cpp @@ -0,0 +1,98 @@ +/*########################################################### + # Copyright (c) 2026-2027. BNBU/UIC RoboMaster # + # # + # This program is free software: you can redistribute it # + # and/or modify it under the terms of the GNU General # + # Public License as published by the Free Software # + # Foundation, either version 3 of the License, or (at # + # your option) any later version. # + # # + # This program is distributed in the hope that it will be # + # useful, but WITHOUT ANY WARRANTY; without even # + # the implied warranty of MERCHANTABILITY or FITNESS # + # FOR A PARTICULAR PURPOSE. See the GNU General # + # Public License for more details. # + # # + # You should have received a copy of the GNU General # + # Public License along with this program. If not, see # + # . # + ###########################################################*/ +#include "protocols/refereerc_receiver.h" + +#include "crc_check.h" + +namespace remote { + void RefereeRcReceiver::UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) { + if (data == nullptr) { + return; + } + for (size_t i = 0; i < size; ++i) { + if (used_ == 0 && data[i] != SOF) { + continue; + } + buffer_[used_++] = data[i]; + if (used_ == FRAME_SIZE) { + if (Decode(now_ms)) { + used_ = 0; + } else { + detail::FindNextFrame(buffer_, used_, SOF); + } + } + } + } + + void RefereeRcReceiver::ResetStream() { + used_ = 0; + } + + bool RefereeRcReceiver::GetState(Vt13Frame& output) const { + if (!HasState()) { + return false; + } + output = state_; + return true; + } + + bool RefereeRcReceiver::Decode(uint32_t now_ms) { + if (buffer_[0] != SOF || buffer_[1] != CMD || !verify_crc16_check_sum(buffer_.data(), FRAME_SIZE)) { + return false; + } + Vt13Frame next; + for (size_t i = 0; i < next.channels.size(); ++i) { + const size_t offset = i < 4 ? 16 + 11 * i : 65; + const uint16_t raw = detail::DecodeBits(buffer_.data(), offset, 11); + if (raw < CHANNEL_MIN || raw > CHANNEL_MAX) { + return false; + } + const int16_t value = static_cast(raw) - CHANNEL_CENTER; + next.channels[i] = value >= -CHANNEL_DEADZONE && value <= CHANNEL_DEADZONE ? 0 : value; + } + const auto mode = detail::DecodeBits(buffer_.data(), 60, 2); + if (mode > 2) { + return false; + } + next.mode = static_cast(mode); + next.pause = detail::DecodeBits(buffer_.data(), 62, 1) != 0; + next.left_button = detail::DecodeBits(buffer_.data(), 63, 1) != 0; + next.right_button = detail::DecodeBits(buffer_.data(), 64, 1) != 0; + next.trigger = detail::DecodeBits(buffer_.data(), 76, 1) != 0; + next.mouse.x = detail::DecodeInt16LE(buffer_.data() + 10); + next.mouse.y = detail::DecodeInt16LE(buffer_.data() + 12); + next.mouse.z = detail::DecodeInt16LE(buffer_.data() + 14); + // Each mouse button occupies two bits, but only 0 and 1 are valid. + const auto left = detail::DecodeBits(buffer_.data(), 128, 2); + const auto right = detail::DecodeBits(buffer_.data(), 130, 2); + const auto middle = detail::DecodeBits(buffer_.data(), 132, 2); + if (left > 1 || right > 1 || middle > 1) { + return false; + } + next.mouse.left = left != 0; + next.mouse.right = right != 0; + next.mouse.middle = middle != 0; + next.keyboard.code = detail::DecodeUint16LE(buffer_.data() + 17); + next.crc16 = detail::DecodeUint16LE(buffer_.data() + 19); + state_ = next; + CommitFrame(now_ms, false); + return true; + } +} // namespace remote diff --git a/boards/remote/src/protocols/sbus_receiver.cpp b/boards/remote/src/protocols/sbus_receiver.cpp new file mode 100644 index 00000000..c61b5dc8 --- /dev/null +++ b/boards/remote/src/protocols/sbus_receiver.cpp @@ -0,0 +1,99 @@ +// Copyright (c) 2026. BNU-HKBU UIC RoboMaster +// SPDX-License-Identifier: GPL-3.0-or-later +#include "protocols/sbus_receiver.h" + +#include "bsp_os.h" + +namespace remote { + SbusReceiver::SbusReceiver(uint32_t online_threshold_ms, uint8_t footer) + : RemoteReceiver(online_threshold_ms), footer_(footer) { + } + + SbusReceiver::SbusReceiver(UART_HandleTypeDef* huart, uint32_t online_threshold_ms, uint8_t footer) + : RemoteReceiver(online_threshold_ms), uart_(new bsp::UART(huart)), owns_uart_(true), footer_(footer) { + uart_->RegisterCallback(UartCallback, this); + uart_->SetupRx(FRAME_SIZE + 1); + } + + SbusReceiver::SbusReceiver(bsp::UART& uart, uint32_t online_threshold_ms, uint8_t footer) + : RemoteReceiver(online_threshold_ms), uart_(&uart), footer_(footer) { + uart_->SetupRx(FRAME_SIZE + 1); + } + + SbusReceiver::~SbusReceiver() { + if (owns_uart_) delete uart_; + } + + bool SbusReceiver::IsOnline() const { + return RemoteReceiver::IsOnline(bsp::GetHighresTickMilliSec()); + } + + void SbusReceiver::UartCallback(void* context) { + static_cast(context)->RxCompleteCallback(); + } + + void SbusReceiver::RxCompleteCallback() { + if (!uart_) return; + uint8_t* data = nullptr; + const int32_t length = uart_->Read(&data); + if (length <= 0 || data == nullptr) { + if (length != 0) ResetStream(); + return; + } + UpdateData(data, static_cast(length), bsp::GetHighresTickMilliSec()); + } + + void SbusReceiver::UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) { + if (data == nullptr) { + return; + } + for (size_t i = 0; i < size; ++i) { + if (used_ == 0 && data[i] != 0x0F) { + continue; + } + buffer_[used_++] = data[i]; + if (used_ == FRAME_SIZE) { + if (Decode(now_ms)) { + used_ = 0; + } else { + detail::FindNextFrame(buffer_, used_, 0x0F); + } + } + } + } + + void SbusReceiver::ResetStream() { + used_ = 0; + } + + void SbusReceiver::SetFooter(uint8_t footer) { + footer_ = footer; + ResetStream(); + } + + bool SbusReceiver::GetState(SbusFrame& output) const { + if (!HasState()) { + return false; + } + output = state_; + return true; + } + + bool SbusReceiver::Decode(uint32_t now_ms) { + if (buffer_[0] != 0x0F || buffer_[24] != footer_) { + return false; + } + SbusFrame next; + for (size_t i = 0; i < next.channels.size(); ++i) { + next.channels[i] = detail::DecodeBits(buffer_.data(), 8 + 11 * i, 11); + } + next.flags = buffer_[23]; + next.channel17 = (next.flags & 0x01) != 0; + next.channel18 = (next.flags & 0x02) != 0; + next.frame_lost = (next.flags & 0x04) != 0; + next.failsafe = (next.flags & 0x08) != 0; + state_ = next; + CommitFrame(now_ms, next.failsafe); + return true; + } +} // namespace remote diff --git a/examples/DJI_Board_TypeC_general/CMakeLists.txt b/examples/DJI_Board_TypeC_general/CMakeLists.txt index 411274d9..ff048f90 100644 --- a/examples/DJI_Board_TypeC_general/CMakeLists.txt +++ b/examples/DJI_Board_TypeC_general/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(buzzer) add_subdirectory(can_bridge) add_subdirectory(chassis) add_subdirectory(cybergear) +add_subdirectory(controller) add_subdirectory(dbus) add_subdirectory(gimbal) add_subdirectory(imu) diff --git a/examples/DJI_Board_TypeC_general/controller/CMakeLists.txt b/examples/DJI_Board_TypeC_general/controller/CMakeLists.txt new file mode 100644 index 00000000..01adbde1 --- /dev/null +++ b/examples/DJI_Board_TypeC_general/controller/CMakeLists.txt @@ -0,0 +1,13 @@ +project(example_controller_${BOARD_NAME} ASM C CXX) + +uicrm_add_arm_executable(${PROJECT_NAME}_dt7 + TARGET ${BOARD_NAME} + SOURCES dt7.cpp) + +uicrm_add_arm_executable(${PROJECT_NAME}_vt13 + TARGET ${BOARD_NAME} + SOURCES vt13.cpp) + +uicrm_add_arm_executable(${PROJECT_NAME}_fs_i6x + TARGET ${BOARD_NAME} + SOURCES fs_i6x.cpp) diff --git a/examples/DJI_Board_TypeC_general/controller/dt7.cpp b/examples/DJI_Board_TypeC_general/controller/dt7.cpp new file mode 100644 index 00000000..749fedbf --- /dev/null +++ b/examples/DJI_Board_TypeC_general/controller/dt7.cpp @@ -0,0 +1,73 @@ +/*########################################################### +# Copyright (c) 2026-2027. BNBU/UIC RoboMaster # + # # + # This program is free software: you can redistribute it # + # and/or modify it under the terms of the GNU General # + # Public License as published by the Free Software # + # Foundation, either version 3 of the License, or (at # + # your option) any later version. # + # # + # This program is distributed in the hope that it will be # + # useful, but WITHOUT ANY WARRANTY; without even # + # the implied warranty of MERCHANTABILITY or FITNESS # + # FOR A PARTICULAR PURPOSE. See the GNU General # + # Public License for more details. # + # # + # You should have received a copy of the GNU General # + # Public License along with this program. If not, see # + # . # + ###########################################################*/ + +#include "main.h" + +#include "bsp_print.h" +#include "cmsis_os.h" +#include "protocols/dbus_receiver.h" + +namespace { + remote::DbusReceiver* receiver = nullptr; +} + +void RM_RTOS_Init(void) { + print_use_uart(&huart1); + + receiver = new remote::DbusReceiver(&huart3); +} + +void RM_RTOS_Default_Task(const void* argument) { + UNUSED(argument); + while (true) { + remote::DbusFrame state; + bool online = receiver->IsOnline(); + bool has_state = receiver->GetState(state); + uint32_t sequence = receiver->GetSequence(); + uint32_t last_valid_ms = receiver->GetLastValidTimeMs(); + + + set_cursor(0, 0); + clear_screen(); + print("DT7: %s\r\n", online ? "ONLINE" : "OFFLINE"); + print("Sequence: %lu\r\n", static_cast(sequence)); + print("Last valid: %lu ms\r\n", static_cast(last_valid_ms)); + if (has_state) { + // 离线仍保留最后有效帧;实际控制必须先检查 online。 + print("Right X/Y: %d / %d\r\n", state.channels[0], state.channels[1]); + print("Left X/Y: %d / %d\r\n", state.channels[2], state.channels[3]); + print("Dial: %d\r\n", state.channels[4]); + print("Switch L/R: %u / %u\r\n", static_cast(state.left_switch), + static_cast(state.right_switch)); + print("Mouse X/Y: %d / %d\r\n", state.mouse.x, state.mouse.y); + print("Mouse Z: %d\r\n", state.mouse.z); + print("Mouse L/R: %d / %d\r\n", state.mouse.left, state.mouse.right); + print("Keyboard: 0x%04X\r\n", static_cast(state.keyboard.code)); + const auto& key = state.keyboard.bit; + print("W/S/A/D: %d %d %d %d\r\n", key.W, key.S, key.A, key.D); + print("SHIFT/CTRL: %d %d\r\n", key.SHIFT, key.CTRL); + print("Q/E/R/F/G: %d %d %d %d %d\r\n", key.Q, key.E, key.R, key.F, key.G); + print("Z/X/C/V/B: %d %d %d %d %d\r\n", key.Z, key.X, key.C, key.V, key.B); + } else { + print("Waiting for a valid frame\r\n"); + } + osDelay(100); + } +} diff --git a/examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp b/examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp new file mode 100644 index 00000000..fa18f1b2 --- /dev/null +++ b/examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp @@ -0,0 +1,97 @@ +/*########################################################### +# Copyright (c) 2026-2027. BNBU/UIC RoboMaster # + # # + # This program is free software: you can redistribute it # + # and/or modify it under the terms of the GNU General # + # Public License as published by the Free Software # + # Foundation, either version 3 of the License, or (at # + # your option) any later version. # + # # + # This program is distributed in the hope that it will be # + # useful, but WITHOUT ANY WARRANTY; without even # + # the implied warranty of MERCHANTABILITY or FITNESS # + # FOR A PARTICULAR PURPOSE. See the GNU General # + # Public License for more details. # + # # + # You should have received a copy of the GNU General # + # Public License along with this program. If not, see # + # . # + ###########################################################*/ + +#include "main.h" + +#include "bsp_print.h" +#include "cmsis_os.h" +#include "controller/fs_i6x_receiver.h" + +namespace { + remote::FsI6xReceiver* receiver = nullptr; + + const char* PositionName(remote::FsI6xTwoPosition position) { + return position == remote::FsI6xTwoPosition::Down ? "DOWN" : "UP"; + } + + const char* PositionName(remote::FsI6xThreePosition position) { + switch (position) { + case remote::FsI6xThreePosition::Down: + return "DOWN"; + case remote::FsI6xThreePosition::Middle: + return "MID"; + case remote::FsI6xThreePosition::Up: + return "UP"; + } + return "UNKNOWN"; + } +} + +void RM_RTOS_Init(void) { + print_use_uart(&huart1); + + receiver = new remote::FsI6xReceiver(&huart3); +} + +void RM_RTOS_Default_Task(const void* argument) { + UNUSED(argument); + while (true) { + remote::FsI6xFrame state; + bool online; + bool has_state; + uint32_t sequence; + uint32_t last_valid_ms; + + // USART3 优先级为 4,FreeRTOS 临界区不能屏蔽它。 + // 保存并短暂关闭中断,拷贝后恢复原状态;打印和延时在保护区外。 + const uint32_t interrupt_mask = __get_PRIMASK(); + __disable_irq(); + online = receiver->IsOnline(); + has_state = receiver->GetState(state); + sequence = receiver->GetSequence(); + last_valid_ms = receiver->GetLastValidTimeMs(); + __set_PRIMASK(interrupt_mask); + + set_cursor(0, 0); + clear_screen(); + print("FS-i6X / iA10B: %s\r\n", online ? "ONLINE" : "OFFLINE"); + print("Sequence: %lu\r\n", static_cast(sequence)); + print("Last valid: %lu ms\r\n", static_cast(last_valid_ms)); + if (has_state) { + print("Frame lost: %d Failsafe: %d Flags: 0x%02X\r\n", + state.frame_lost, state.failsafe, static_cast(state.flags)); + print("Right X/Y: %d / %d\r\n", state.channels[0], state.channels[1]); + print("Left X/Y: %d / %d\r\n", state.channels[3], state.channels[2]); + print("VrA/VrB: %d / %d\r\n", state.channels[4], state.channels[5]); + print("SwA: %s SwB: %s SwC: %s SwD: %s\r\n", + PositionName(state.sw_a), PositionName(state.sw_b), PositionName(state.sw_c), + PositionName(state.sw_d)); + print("Usable: %d\r\n", online && !state.failsafe && !state.frame_lost); + for (size_t i = 0; i < state.raw_channels.size(); ++i) { + print("Raw CH%u: %u\r\n", static_cast(i + 1), + static_cast(state.raw_channels[i])); + } + // 离线仍可读到最后有效帧,在线也可能失控;实际控制须分别检查。 + } else { + print("Waiting for a valid SBUS frame\r\n"); + } + osDelay(100); + } +} diff --git a/examples/DJI_Board_TypeC_general/controller/vt13.cpp b/examples/DJI_Board_TypeC_general/controller/vt13.cpp new file mode 100644 index 00000000..250d7458 --- /dev/null +++ b/examples/DJI_Board_TypeC_general/controller/vt13.cpp @@ -0,0 +1,100 @@ +/*########################################################### +# Copyright (c) 2026-2027. BNBU/UIC RoboMaster # + # # + # This program is free software: you can redistribute it # + # and/or modify it under the terms of the GNU General # + # Public License as published by the Free Software # + # Foundation, either version 3 of the License, or (at # + # your option) any later version. # + # # + # This program is distributed in the hope that it will be # + # useful, but WITHOUT ANY WARRANTY; without even # + # the implied warranty of MERCHANTABILITY or FITNESS # + # FOR A PARTICULAR PURPOSE. See the GNU General # + # Public License for more details. # + # # + # You should have received a copy of the GNU General # + # Public License along with this program. If not, see # + # . # + ###########################################################*/ + +#include "main.h" + +#include "bsp_os.h" +#include "bsp_print.h" +#include "bsp_uart.h" +#include "cmsis_os.h" +#include "protocol.h" +#include "task.h" + +namespace { + communication::Referee* link = nullptr; +} + +void RM_RTOS_Init(void) { + print_use_uart(&huart1); + + // 图传模块发送端 UART:921600 baud、8 位数据、无校验、1 位停止位。 + huart6.Init.BaudRate = 921600; + huart6.Init.WordLength = UART_WORDLENGTH_8B; + huart6.Init.Parity = UART_PARITY_NONE; + huart6.Init.StopBits = UART_STOPBITS_1; + if (HAL_UART_Init(&huart6) != HAL_OK) { + Error_Handler(); + } + + auto* uart = new bsp::UART(&huart6); + // Referee 内部注册 UART 回调和接收线程,由 Protocol 完成 A5/A9 分帧。 + link = new communication::Referee(uart); + uart->SetupRx(300); +} + +void RM_RTOS_Default_Task(const void* argument) { + UNUSED(argument); + while (true) { + remote::Vt13Frame state; + bool online; + bool has_state; + uint32_t sequence; + uint32_t last_valid_ms; + + // 防止接收线程在拷贝状态期间切入;临界区内不打印、不延时。 + taskENTER_CRITICAL(); + const auto& receiver = link->Vt13(); + online = receiver.IsOnline(bsp::GetHighresTickMilliSec()); + has_state = receiver.GetState(state); + sequence = receiver.GetSequence(); + last_valid_ms = receiver.GetLastValidTimeMs(); + taskEXIT_CRITICAL(); + + set_cursor(0, 0); + clear_screen(); + // 使用遥控有效帧的在线状态,不能用 Referee::IsOnline 代替。 + print("VT13: %s\r\n", online ? "ONLINE" : "OFFLINE"); + print("Sequence: %lu\r\n", static_cast(sequence)); + print("Last valid: %lu ms\r\n", static_cast(last_valid_ms)); + if (has_state) { + // VT13 通道为 -660~660,中心 0,包含 ±10 死区;左摇杆的顺序是 Y/X。 + print("Right X/Y: %d / %d\r\n", state.channels[0], state.channels[1]); + print("Left Y/X: %d / %d\r\n", state.channels[2], state.channels[3]); + print("Dial: %d\r\n", state.channels[4]); + const char* mode = state.mode == remote::Vt13Mode::C ? "C" : + state.mode == remote::Vt13Mode::N ? "N" : "S"; + print("Mode: %s Pause: %d\r\n", mode, state.pause); + print("Button L/R: %d / %d\r\n", state.left_button, state.right_button); + print("Trigger: %d\r\n", state.trigger); + print("Mouse X/Y: %d / %d\r\n", state.mouse.x, state.mouse.y); + print("Mouse Z: %d\r\n", state.mouse.z); + print("Mouse L/R/M: %d %d %d\r\n", state.mouse.left, state.mouse.right, state.mouse.middle); + print("Keyboard: 0x%04X\r\n", static_cast(state.keyboard.code)); + const auto& key = state.keyboard.bit; + print("W/S/A/D: %d %d %d %d\r\n", key.W, key.S, key.A, key.D); + print("SHIFT/CTRL: %d %d\r\n", key.SHIFT, key.CTRL); + print("Q/E/R/F/G: %d %d %d %d %d\r\n", key.Q, key.E, key.R, key.F, key.G); + print("Z/X/C/V/B: %d %d %d %d %d\r\n", key.Z, key.X, key.C, key.V, key.B); + } else { + print("Waiting for a valid frame\r\n"); + } + osDelay(100); + } +} From b640513b9cef75961ea150de36d47f744f95ab1a Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 23 Oct 2026 10:39:04 +0800 Subject: [PATCH 03/17] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20dt7/vt13?= =?UTF-8?q?/fs=5Fi6x=20=E7=A4=BA=E4=BE=8B=E4=BB=A5=E9=80=82=E9=85=8D?= =?UTF-8?q?=E6=96=B0=E7=9A=84=E9=81=A5=E6=8E=A7=E6=8E=A5=E6=94=B6=E5=99=A8?= =?UTF-8?q?=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 示例中的接收器改用 remote::Dbus、remote::I6x 与 remote::RefereeRc,VT13 状态与模式类型重命名为 RefereeRcFrame / RefereeRcMode - FS-i6X 的通道开关枚举改用统一的 TwoPositionSwitch / ThreePositionSwitch,并修正 UP/DOWN 映射 - fs_i6x 示例补充通道对应关系说明与开关编码诊断输出,便于排查 SBUS 解析结果 --- .../controller/dt7.cpp | 6 ++-- .../controller/fs_i6x.cpp | 29 +++++++++++-------- .../controller/vt13.cpp | 8 ++--- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/examples/DJI_Board_TypeC_general/controller/dt7.cpp b/examples/DJI_Board_TypeC_general/controller/dt7.cpp index 749fedbf..61ec1332 100644 --- a/examples/DJI_Board_TypeC_general/controller/dt7.cpp +++ b/examples/DJI_Board_TypeC_general/controller/dt7.cpp @@ -22,16 +22,16 @@ #include "bsp_print.h" #include "cmsis_os.h" -#include "protocols/dbus_receiver.h" +#include "dbus.h" namespace { - remote::DbusReceiver* receiver = nullptr; + remote::Dbus* receiver = nullptr; } void RM_RTOS_Init(void) { print_use_uart(&huart1); - receiver = new remote::DbusReceiver(&huart3); + receiver = new remote::Dbus(&huart3); } void RM_RTOS_Default_Task(const void* argument) { diff --git a/examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp b/examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp index fa18f1b2..7f717fe5 100644 --- a/examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp +++ b/examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp @@ -22,23 +22,23 @@ #include "bsp_print.h" #include "cmsis_os.h" -#include "controller/fs_i6x_receiver.h" +#include "sbus.h" namespace { - remote::FsI6xReceiver* receiver = nullptr; + remote::I6x* receiver = nullptr; - const char* PositionName(remote::FsI6xTwoPosition position) { - return position == remote::FsI6xTwoPosition::Down ? "DOWN" : "UP"; + const char* PositionName(remote::TwoPositionSwitch position) { + return position == remote::TwoPositionSwitch::Up ? "UP" : "DOWN"; } - const char* PositionName(remote::FsI6xThreePosition position) { + const char* PositionName(remote::ThreePositionSwitch position) { switch (position) { - case remote::FsI6xThreePosition::Down: - return "DOWN"; - case remote::FsI6xThreePosition::Middle: - return "MID"; - case remote::FsI6xThreePosition::Up: + case remote::ThreePositionSwitch::Up: return "UP"; + case remote::ThreePositionSwitch::Mid: + return "MID"; + case remote::ThreePositionSwitch::Down: + return "DOWN"; } return "UNKNOWN"; } @@ -47,13 +47,13 @@ namespace { void RM_RTOS_Init(void) { print_use_uart(&huart1); - receiver = new remote::FsI6xReceiver(&huart3); + receiver = new remote::I6x(&huart3); } void RM_RTOS_Default_Task(const void* argument) { UNUSED(argument); while (true) { - remote::FsI6xFrame state; + remote::I6xState state; bool online; bool has_state; uint32_t sequence; @@ -77,12 +77,17 @@ void RM_RTOS_Default_Task(const void* argument) { if (has_state) { print("Frame lost: %d Failsafe: %d Flags: 0x%02X\r\n", state.frame_lost, state.failsafe, static_cast(state.flags)); + // CH1/2:右 X/Y;CH3/4:左 Y/X;CH5/6:VrA/VrB;CH7~10:SwA~SwD。 + // I6x 已统一映射到 ±660 并处理原始 ±10 死区;原始通道保留用于诊断。 print("Right X/Y: %d / %d\r\n", state.channels[0], state.channels[1]); print("Left X/Y: %d / %d\r\n", state.channels[3], state.channels[2]); print("VrA/VrB: %d / %d\r\n", state.channels[4], state.channels[5]); print("SwA: %s SwB: %s SwC: %s SwD: %s\r\n", PositionName(state.sw_a), PositionName(state.sw_b), PositionName(state.sw_c), PositionName(state.sw_d)); + print("Switch codes A/B/C/D: %u / %u / %u / %u\r\n", + static_cast(state.sw_a), static_cast(state.sw_b), + static_cast(state.sw_c), static_cast(state.sw_d)); print("Usable: %d\r\n", online && !state.failsafe && !state.frame_lost); for (size_t i = 0; i < state.raw_channels.size(); ++i) { print("Raw CH%u: %u\r\n", static_cast(i + 1), diff --git a/examples/DJI_Board_TypeC_general/controller/vt13.cpp b/examples/DJI_Board_TypeC_general/controller/vt13.cpp index 250d7458..f830692f 100644 --- a/examples/DJI_Board_TypeC_general/controller/vt13.cpp +++ b/examples/DJI_Board_TypeC_general/controller/vt13.cpp @@ -52,7 +52,7 @@ void RM_RTOS_Init(void) { void RM_RTOS_Default_Task(const void* argument) { UNUSED(argument); while (true) { - remote::Vt13Frame state; + remote::RefereeRcFrame state; bool online; bool has_state; uint32_t sequence; @@ -60,7 +60,7 @@ void RM_RTOS_Default_Task(const void* argument) { // 防止接收线程在拷贝状态期间切入;临界区内不打印、不延时。 taskENTER_CRITICAL(); - const auto& receiver = link->Vt13(); + const auto& receiver = link->RefereeRc(); online = receiver.IsOnline(bsp::GetHighresTickMilliSec()); has_state = receiver.GetState(state); sequence = receiver.GetSequence(); @@ -78,8 +78,8 @@ void RM_RTOS_Default_Task(const void* argument) { print("Right X/Y: %d / %d\r\n", state.channels[0], state.channels[1]); print("Left Y/X: %d / %d\r\n", state.channels[2], state.channels[3]); print("Dial: %d\r\n", state.channels[4]); - const char* mode = state.mode == remote::Vt13Mode::C ? "C" : - state.mode == remote::Vt13Mode::N ? "N" : "S"; + const char* mode = state.mode == remote::RefereeRcMode::C ? "C" : + state.mode == remote::RefereeRcMode::N ? "N" : "S"; print("Mode: %s Pause: %d\r\n", mode, state.pause); print("Button L/R: %d / %d\r\n", state.left_button, state.right_button); print("Trigger: %d\r\n", state.trigger); From 48f0ad2cc904307727e33ad0e9e20abf7f9d770e Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:23 +0800 Subject: [PATCH 04/17] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=20Neo=20?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E8=87=B3=20controller=20=E9=81=A5=E6=8E=A7?= =?UTF-8?q?=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- programs/Neo/gimbal/include/referee_task.h | 5 +-- programs/Neo/gimbal/include/remote_task.h | 4 +- programs/Neo/gimbal/src/chassis_task.cpp | 24 +++++++---- programs/Neo/gimbal/src/gimbal_task.cpp | 27 +++++++----- programs/Neo/gimbal/src/main.cpp | 19 ++++---- programs/Neo/gimbal/src/referee_task.cpp | 8 +--- programs/Neo/gimbal/src/remote_task.cpp | 50 ++++++++++++++-------- programs/Neo/gimbal/src/shoot_task.cpp | 4 +- programs/Neo/gimbal/src/ui_task.cpp | 15 +++++-- 9 files changed, 96 insertions(+), 60 deletions(-) diff --git a/programs/Neo/gimbal/include/referee_task.h b/programs/Neo/gimbal/include/referee_task.h index 0446d82f..bb008599 100644 --- a/programs/Neo/gimbal/include/referee_task.h +++ b/programs/Neo/gimbal/include/referee_task.h @@ -22,7 +22,7 @@ #include "bsp_print.h" #include "bsp_uart.h" #include "cmsis_os2.h" -#include "dji_dbus.h" +#include "refereerc.h" #include "main.h" #include "protocol.h" @@ -30,7 +30,6 @@ extern bsp::UART* referee_uart; extern communication::Referee* referee; -extern bsp::UART* refereerc_uart; -extern communication::Referee* refereerc; +extern controller::RefereeRC* refereerc; void init_referee(); \ No newline at end of file diff --git a/programs/Neo/gimbal/include/remote_task.h b/programs/Neo/gimbal/include/remote_task.h index fd5249b5..d0eb692b 100644 --- a/programs/Neo/gimbal/include/remote_task.h +++ b/programs/Neo/gimbal/include/remote_task.h @@ -20,12 +20,12 @@ #pragma once #include "cmsis_os2.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #include "referee_task.h" #include "user_define.h" #include "utils.h" -extern remote::DBUS* dbus; +extern controller::DBUS* dbus; extern bool turbo_shoot; /** * @brief Dbus Init diff --git a/programs/Neo/gimbal/src/chassis_task.cpp b/programs/Neo/gimbal/src/chassis_task.cpp index 1f4c7dd3..9c7a7a34 100644 --- a/programs/Neo/gimbal/src/chassis_task.cpp +++ b/programs/Neo/gimbal/src/chassis_task.cpp @@ -52,6 +52,13 @@ void chassisTask(void* arg) { chassis->Enable(); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + if (!is_activate) { kill_chassis(); while (!is_activate) { @@ -61,11 +68,11 @@ void chassisTask(void* arg) { continue; } - remote::keyboard_t keyboard; + controller::KeyboardState keyboard{}; if (dbus->IsOnline()) { - keyboard = dbus->keyboard; - } else if (refereerc->IsOnline()) { - keyboard = refereerc->remote_control.keyboard; + keyboard = dbus_state.keyboard; + } else if ((refereerc != nullptr && refereerc->IsOnline())) { + keyboard = refereerc_state.keyboard; } // 以云台为基准的(整车的)运动速度,范围为[-1, 1] @@ -80,11 +87,12 @@ void chassisTask(void* arg) { car_vy = minipc->robot_move.target_x; car_vx = -minipc->robot_move.target_y; car_vt = minipc->robot_move.target_turn; - } else if (dbus->ch0 || dbus->ch1 || dbus->ch2 || dbus->ch3 || dbus->ch4) { + } else if (dbus_state.channels[0] || dbus_state.channels[1] || dbus_state.channels[2] || + dbus_state.channels[3] || dbus_state.channels[4]) { // 优先使用遥控器 - car_vx = (float)dbus->ch0 / dbus->ROCKER_MAX; - car_vy = (float)dbus->ch1 / dbus->ROCKER_MAX; - car_vt = (float)dbus->ch4 / dbus->ROCKER_MAX; + car_vx = (float)dbus_state.channels[0] / 660.0f; + car_vy = (float)dbus_state.channels[1] / 660.0f; + car_vt = (float)dbus_state.channels[4] / 660.0f; } else { // 使用键盘 const float keyboard_speed = keyboard.bit.SHIFT ? 1 : 0.5; diff --git a/programs/Neo/gimbal/src/gimbal_task.cpp b/programs/Neo/gimbal/src/gimbal_task.cpp index 0ac908db..6ebcfc75 100644 --- a/programs/Neo/gimbal/src/gimbal_task.cpp +++ b/programs/Neo/gimbal/src/gimbal_task.cpp @@ -85,6 +85,13 @@ void gimbalTask(void* arg) { // float actural_chassis_turn_speed = chassis_vt / 6.0f; while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + bool gimbal_en = is_activate; #ifdef HAS_REFEREE gimbal_en = gimbal_en && referee->game_robot_status.mains_power_gimbal_output; @@ -118,7 +125,7 @@ void gimbalTask(void* arg) { yaw_curr = imu->INS_angle[0]; // pitch_curr = witimu->INS_angle[0]; // yaw_curr = wrap(witimu->INS_angle[2]-yaw_offset, -PI, PI); - // if (dbus->swr == remote::UP) { + // if (dbus_state.right_switch == controller::ThreePositionSwitch::Up) { // gimbal->TargetAbs(0, 0); // gimbal->Update(); // pitch_target = pitch_curr; @@ -128,19 +135,19 @@ void gimbalTask(void* arg) { // continue; // } if (dbus->IsOnline()) { - if (dbus->mouse.y != 0) { - pitch_ratio = dbus->mouse.y / 32767.0 * 7.5 / 7.0; + if (dbus_state.mouse.y != 0) { + pitch_ratio = dbus_state.mouse.y / 32767.0 * 7.5 / 7.0; } else { - pitch_ratio = -dbus->ch3 / 18000.0 / 7.0; + pitch_ratio = -dbus_state.channels[3] / 18000.0 / 7.0; } - if (dbus->mouse.x != 0) { - yaw_ratio = -dbus->mouse.x / 32767.0 * 7.5 / 7.0; + if (dbus_state.mouse.x != 0) { + yaw_ratio = -dbus_state.mouse.x / 32767.0 * 7.5 / 7.0; } else { - yaw_ratio = -dbus->ch2 / 18000.0 / 7.0; + yaw_ratio = -dbus_state.channels[2] / 18000.0 / 7.0; } - } else if (refereerc->IsOnline()) { - pitch_ratio = refereerc->remote_control.mouse.y / 32767.0 * 7.5 / 7.0; - yaw_ratio = -refereerc->remote_control.mouse.x / 32767.0 * 7.5 / 7.0; + } else if ((refereerc != nullptr && refereerc->IsOnline())) { + pitch_ratio = refereerc_state.mouse.y / 32767.0 * 7.5 / 7.0; + yaw_ratio = -refereerc_state.mouse.x / 32767.0 * 7.5 / 7.0; } else { pitch_ratio = 0; yaw_ratio = 0; diff --git a/programs/Neo/gimbal/src/main.cpp b/programs/Neo/gimbal/src/main.cpp index 3fe98220..37b4da86 100644 --- a/programs/Neo/gimbal/src/main.cpp +++ b/programs/Neo/gimbal/src/main.cpp @@ -90,6 +90,9 @@ void RM_RTOS_Default_Task(const void* arg) { // } while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + // if (referee->game_robot_status.mains_power_gimbal_output) { // gimbal_power->High(); // } else { @@ -109,16 +112,16 @@ void RM_RTOS_Default_Task(const void* arg) { // DBUS info print( - "DBUS [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [TWL: %d] [SWL: %d] [SWR: %d]" + "DBUS [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [TWL: %d] [SWL: %s] [SWR: %s]" "@ %d " "ms\r\n", - dbus->ch0, - dbus->ch1, - dbus->ch2, - dbus->ch3, - dbus->ch4, - dbus->swl, - dbus->swr + dbus_state.channels[0], + dbus_state.channels[1], + dbus_state.channels[2], + dbus_state.channels[3], + dbus_state.channels[4], + controller::SwitchName(dbus_state.left_switch), + controller::SwitchName(dbus_state.right_switch) ); print("\r\n"); diff --git a/programs/Neo/gimbal/src/referee_task.cpp b/programs/Neo/gimbal/src/referee_task.cpp index 07f0db8c..3856cf51 100644 --- a/programs/Neo/gimbal/src/referee_task.cpp +++ b/programs/Neo/gimbal/src/referee_task.cpp @@ -21,9 +21,8 @@ #include "referee_task.h" bsp::UART* referee_uart = nullptr; -bsp::UART* refereerc_uart = nullptr; communication::Referee* referee = nullptr; -communication::Referee* refereerc = nullptr; +controller::RefereeRC* refereerc = nullptr; void init_referee() { referee_uart = new bsp::UART(&BOARD_UART2); @@ -32,8 +31,5 @@ void init_referee() { referee_uart->SetupTx(300); referee = new communication::Referee(referee_uart); - // refereerc_uart = new bsp::UART(&huart1); - // refereerc_uart->SetupRx(300); - // refereerc_uart->SetupTx(300); - // refereerc = new communication::Referee(refereerc_uart); + // refereerc = new controller::RefereeRC(&huart1); } diff --git a/programs/Neo/gimbal/src/remote_task.cpp b/programs/Neo/gimbal/src/remote_task.cpp index 8ec61a69..485c8f32 100644 --- a/programs/Neo/gimbal/src/remote_task.cpp +++ b/programs/Neo/gimbal/src/remote_task.cpp @@ -23,7 +23,7 @@ #include "imu_task.h" #include "minipc_task.h" -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; bool is_activate = true; RemoteMode remote_mode = REMOTE_MODE_AUTOPILOT; @@ -35,14 +35,19 @@ RemoteMode last_remote_mode = REMOTE_MODE_SPIN; ShootMode last_shoot_mode = SHOOT_MODE_STOP; void init_remote() { - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); } osThreadId_t remoteTaskHandle; void remoteTask(void* arg) { + using enum controller::ThreePositionSwitch; + UNUSED(arg); osDelay(1000); + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + bool is_referee_robot_dead = true; bool is_referee_shoot_available = false; @@ -51,8 +56,11 @@ void remoteTask(void* arg) { // 使/失能(上/下电) auto tranlogic_active_condition = TRANLOGIC { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + const auto& referee_cmd_dead = COMPONENT(0); - return dbus->IsOnline() && dbus->swr != remote::DOWN && !referee_cmd_dead.get(); + return dbus->IsOnline() && dbus_state.right_switch != Down && !referee_cmd_dead.get(); }; auto activate_aut = control::AutomataBuilder() .item(is_referee_robot_dead) @@ -64,10 +72,10 @@ void remoteTask(void* arg) { auto tranlogic_next_remote_mode_trigger = TRANLOGIC { const auto& swr = COMPONENT(0); const auto& mode_change_key = COMPONENT(1); - return (swr.downEdge() && swr.get() == remote::UP) || mode_change_key.upEdge(); + return (swr.downEdge() && swr.get() == Up) || mode_change_key.upEdge(); }; auto remote_mode_aut = control::AutomataBuilder() - .item(dbus->swr) + .item(dbus_state.right_switch) .item(bool{}) // mode_change_key .transition(tranlogic_next_remote_mode_trigger) .transition(tranlogic_next_remote_mode_trigger) @@ -82,10 +90,10 @@ void remoteTask(void* arg) { auto tranlogic_fric_wheel_trigger = TRANLOGIC { const auto& swl = COMPONENT(0); const auto& fric_key = COMPONENT(1); - return (swl.downEdge() && swl.get() == remote::UP) || fric_key.upEdge(); + return (swl.downEdge() && swl.get() == Up) || fric_key.upEdge(); }; auto fric_wheel_aut = control::AutomataBuilder() - .item(dbus->swl) + .item(dbus_state.left_switch) .item(bool{}) // friction_key .transition(tranlogic_fric_wheel_trigger) .transition(tranlogic_fric_wheel_trigger) @@ -103,13 +111,13 @@ void remoteTask(void* arg) { const auto& referee_permit = COMPONENT(2); const auto& shoot_key = COMPONENT(3); const auto& remote_mode = COMPONENT(4); - return (swl.get() == remote::DOWN || shoot_key.get()) && + return (swl.get() == Down || shoot_key.get()) && fric_state.get() == SHOOT_FRIC_MODE_PREPARED && referee_permit.get() && (remote_mode.get() == REMOTE_MODE_AUTOPILOT ? minipc->target_angle.shoot_cmd : true); }; auto shoot_aut = control::AutomataBuilder() - .item(dbus->swl) + .item(dbus_state.left_switch) .item(SHOOT_FRIC_MODE_STOP) .item(is_referee_shoot_available) .item(bool{}) // shoot_key @@ -130,10 +138,10 @@ void remoteTask(void* arg) { auto tranlogic_bullet_cap_trigger = TRANLOGIC { const auto& swl = COMPONENT(0); const auto& fric_state = COMPONENT(1); - return swl.downEdge() && swl.get() == remote::DOWN && fric_state.get() == SHOOT_FRIC_MODE_STOP; + return swl.downEdge() && swl.get() == Down && fric_state.get() == SHOOT_FRIC_MODE_STOP; }; auto bullet_cap_aut = control::AutomataBuilder() - .item(dbus->swl) + .item(dbus_state.left_switch) .item(SHOOT_FRIC_MODE_STOP) .transition(tranlogic_bullet_cap_trigger) .transition(tranlogic_bullet_cap_trigger) @@ -145,6 +153,9 @@ void remoteTask(void* arg) { while (true) { osDelay(REMOTE_OS_DELAY); + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + #ifdef HAS_REFEREE // Kill Detection is_referee_robot_dead = referee->game_robot_status.remain_HP == 0; @@ -162,20 +173,25 @@ void remoteTask(void* arg) { if (!is_activate || !imu->DataReady() || !imu->CaliDone()) continue; - remote_mode_aut.input(std::make_tuple(dbus->swr, static_cast(dbus->keyboard.bit.SHIFT))); + remote_mode_aut.input(std::make_tuple(dbus_state.right_switch, static_cast(dbus_state.keyboard.bit.SHIFT)) + ); last_remote_mode = remote_mode; remote_mode = remote_mode_aut.state(); - fric_wheel_aut.input(std::make_tuple(dbus->swl, static_cast(dbus->keyboard.bit.Z))); + fric_wheel_aut.input(std::make_tuple(dbus_state.left_switch, static_cast(dbus_state.keyboard.bit.Z))); shoot_fric_wheel_mode = fric_wheel_aut.state(); - shoot_aut.input( - std::make_tuple(dbus->swl, shoot_fric_wheel_mode, is_referee_shoot_available, dbus->mouse.l, remote_mode) - ); + shoot_aut.input(std::make_tuple( + dbus_state.left_switch, + shoot_fric_wheel_mode, + is_referee_shoot_available, + dbus_state.mouse.left, + remote_mode + )); last_shoot_mode = shoot_mode; shoot_mode = shoot_aut.state(); - bullet_cap_aut.input(std::make_tuple(dbus->swl, shoot_fric_wheel_mode)); + bullet_cap_aut.input(std::make_tuple(dbus_state.left_switch, shoot_fric_wheel_mode)); bullet_cap_mode = bullet_cap_aut.state(); } } diff --git a/programs/Neo/gimbal/src/shoot_task.cpp b/programs/Neo/gimbal/src/shoot_task.cpp index 2ee1659a..b0c90bbc 100644 --- a/programs/Neo/gimbal/src/shoot_task.cpp +++ b/programs/Neo/gimbal/src/shoot_task.cpp @@ -57,8 +57,8 @@ void shootTask(void* arg) { while (!imu->DataReady() || !imu->CaliDone()) { osDelay(SHOOT_OS_DELAY); } - // int last_state = remote::MID; - // int last_state_2 = remote::MID; + // auto last_state = controller::ThreePositionSwitch::Mid; + // auto last_state_2 = controller::ThreePositionSwitch::Mid; // uint8_t shoot_state = 0; // int shoot_flywheel_offset = 0; // uint8_t shoot_state_2 = 0; diff --git a/programs/Neo/gimbal/src/ui_task.cpp b/programs/Neo/gimbal/src/ui_task.cpp index 50d21342..f050e3bd 100644 --- a/programs/Neo/gimbal/src/ui_task.cpp +++ b/programs/Neo/gimbal/src/ui_task.cpp @@ -134,6 +134,13 @@ void uiTask(void* arg) { BoolEdgeDetector* imu_temp_edge = new BoolEdgeDetector(false); BoolEdgeDetector* shoot_jam_edge = new BoolEdgeDetector(false); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + // Update chassis GUI relative_angle = yaw_motor->GetThetaDelta(gimbal_param->yaw_offset_); pitch_angle = pitch_motor->GetThetaDelta(gimbal_param->pitch_offset_); @@ -263,9 +270,9 @@ void uiTask(void* arg) { // clear self-diagnosis messages if (dbus->IsOnline()) { - v_edge->input(dbus->keyboard.bit.V); + v_edge->input(dbus_state.keyboard.bit.V); } else { - v_edge->input(refereerc->remote_control.keyboard.bit.V); + v_edge->input(refereerc_state.keyboard.bit.V); } if (v_edge->posEdge()) { @@ -337,9 +344,9 @@ void uiTask(void* arg) { continue; } if (dbus->IsOnline()) { - c_edge->input(dbus->keyboard.bit.C); + c_edge->input(dbus_state.keyboard.bit.C); } else { - c_edge->input(refereerc->remote_control.keyboard.bit.C); + c_edge->input(refereerc_state.keyboard.bit.C); } if (c_edge->posEdge()) { diagGUI->Clear(UI_Delay); From d891f6c3b318269f22fa8203d7be851bb174d534 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:22 +0800 Subject: [PATCH 05/17] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=20Hero=20?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E8=87=B3=20controller=20=E9=81=A5=E6=8E=A7?= =?UTF-8?q?=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- programs/Hero/gimbal/include/referee_task.h | 5 +- programs/Hero/gimbal/include/remote_task.h | 4 +- programs/Hero/gimbal/src/chassis_task.cpp | 39 +++++---- programs/Hero/gimbal/src/gimbal_task.cpp | 48 ++++++----- programs/Hero/gimbal/src/main.cpp | 47 +++++++---- programs/Hero/gimbal/src/referee_task.cpp | 9 +- programs/Hero/gimbal/src/remote_task.cpp | 93 +++++++++++---------- programs/Hero/gimbal/src/shoot_task.cpp | 4 +- programs/Hero/gimbal/src/ui_task.cpp | 15 +++- 9 files changed, 145 insertions(+), 119 deletions(-) diff --git a/programs/Hero/gimbal/include/referee_task.h b/programs/Hero/gimbal/include/referee_task.h index 0446d82f..bb008599 100644 --- a/programs/Hero/gimbal/include/referee_task.h +++ b/programs/Hero/gimbal/include/referee_task.h @@ -22,7 +22,7 @@ #include "bsp_print.h" #include "bsp_uart.h" #include "cmsis_os2.h" -#include "dji_dbus.h" +#include "refereerc.h" #include "main.h" #include "protocol.h" @@ -30,7 +30,6 @@ extern bsp::UART* referee_uart; extern communication::Referee* referee; -extern bsp::UART* refereerc_uart; -extern communication::Referee* refereerc; +extern controller::RefereeRC* refereerc; void init_referee(); \ No newline at end of file diff --git a/programs/Hero/gimbal/include/remote_task.h b/programs/Hero/gimbal/include/remote_task.h index 786ec19e..be516470 100644 --- a/programs/Hero/gimbal/include/remote_task.h +++ b/programs/Hero/gimbal/include/remote_task.h @@ -20,12 +20,12 @@ #pragma once #include "cmsis_os2.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #include "referee_task.h" #include "user_define.h" #include "utils.h" -extern remote::DBUS* dbus; +extern controller::DBUS* dbus; extern bool turbo_shoot; /** * @brief Dbus Init diff --git a/programs/Hero/gimbal/src/chassis_task.cpp b/programs/Hero/gimbal/src/chassis_task.cpp index 67ad4bf7..166ad14b 100644 --- a/programs/Hero/gimbal/src/chassis_task.cpp +++ b/programs/Hero/gimbal/src/chassis_task.cpp @@ -49,6 +49,13 @@ void chassisTask(void* arg) { chassis->Enable(); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + if (remote_mode == REMOTE_MODE_KILL) { kill_chassis(); while (remote_mode == REMOTE_MODE_KILL) { @@ -58,32 +65,30 @@ void chassisTask(void* arg) { continue; } - remote::keyboard_t keyboard; + controller::KeyboardState keyboard{}; if (dbus->IsOnline()) { - keyboard = dbus->keyboard; - } else if (refereerc->IsOnline()) { - keyboard = refereerc->vt13_packet.keyboard; + keyboard = dbus_state.keyboard; + } else if ((refereerc != nullptr && refereerc->IsOnline())) { + keyboard = refereerc_state.keyboard; } // 以云台为基准的(整车的)运动速度,范围为[-1, 1] float car_vx, car_vy, car_vt; - if (dbus->ch0 || dbus->ch1 || dbus->ch2 || dbus->ch3 || dbus->ch4) { + if (dbus_state.channels[0] || dbus_state.channels[1] || dbus_state.channels[2] || dbus_state.channels[3] || + dbus_state.channels[4]) { // 优先使用遥控器 const float speed_scale = 0.5; - car_vx = (float)dbus->ch0 / dbus->ROCKER_MAX * speed_scale; - car_vy = (float)dbus->ch1 / dbus->ROCKER_MAX * speed_scale; - car_vt = (float)dbus->ch4 / dbus->ROCKER_MAX * speed_scale; - } else if (refereerc->IsOnline() && (refereerc->vt13_packet.remote.ch0 != remote::vt13_remote_t::ROCKER_MID || - refereerc->vt13_packet.remote.ch1 != remote::vt13_remote_t::ROCKER_MID || - refereerc->vt13_packet.remote.ch4 != remote::vt13_remote_t::ROCKER_MID)) { + car_vx = (float)dbus_state.channels[0] / 660.0f * speed_scale; + car_vy = (float)dbus_state.channels[1] / 660.0f * speed_scale; + car_vt = (float)dbus_state.channels[4] / 660.0f * speed_scale; + } else if ((refereerc != nullptr && refereerc->IsOnline()) && + (refereerc_state.channels[0] != 0 || refereerc_state.channels[1] != 0 || + refereerc_state.channels[4] != 0)) { // 使用VT13遥控器摇杆 const float speed_scale = 0.5; - car_vx = (float)(refereerc->vt13_packet.remote.ch0 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE * speed_scale; - car_vy = (float)(refereerc->vt13_packet.remote.ch1 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE * speed_scale; - car_vt = (float)(refereerc->vt13_packet.remote.ch4 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE * speed_scale; + car_vx = (float)(refereerc_state.channels[0]) / 660.0f * speed_scale; + car_vy = (float)(refereerc_state.channels[1]) / 660.0f * speed_scale; + car_vt = (float)(refereerc_state.channels[4]) / 660.0f * speed_scale; } else { // 使用键盘 const float keyboard_speed = keyboard.bit.SHIFT ? 1 : 0.5; diff --git a/programs/Hero/gimbal/src/gimbal_task.cpp b/programs/Hero/gimbal/src/gimbal_task.cpp index e44ecfef..6b9096df 100644 --- a/programs/Hero/gimbal/src/gimbal_task.cpp +++ b/programs/Hero/gimbal/src/gimbal_task.cpp @@ -78,6 +78,13 @@ void gimbalTask(void* arg) { float actural_chassis_turn_speed = chassis_vt / 6.0f; while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + if (remote_mode == REMOTE_MODE_KILL) { kill_gimbal(); osDelay(GIMBAL_OS_DELAY); @@ -91,7 +98,7 @@ void gimbalTask(void* arg) { yaw_curr = imu->INS_angle[0]; // pitch_curr = witimu->INS_angle[0]; // yaw_curr = wrap(witimu->INS_angle[2]-yaw_offset, -PI, PI); - // if (dbus->swr == remote::UP) { + // if (dbus_state.right_switch == controller::ThreePositionSwitch::Up) { // gimbal->TargetAbs(0, 0); // gimbal->Update(); // pitch_target = pitch_curr; @@ -101,34 +108,31 @@ void gimbalTask(void* arg) { // continue; // } if (dbus->IsOnline()) { - if (dbus->mouse.y != 0) { - pitch_ratio = dbus->mouse.y / 32767.0 * 7.5 / 7.0; - } else if (refereerc->IsOnline() && - (refereerc->vt13_packet.mouse.x != 0 || refereerc->vt13_packet.mouse.y != 0)) { + if (dbus_state.mouse.y != 0) { + pitch_ratio = dbus_state.mouse.y / 32767.0 * 7.5 / 7.0; + } else if ((refereerc != nullptr && refereerc->IsOnline()) && + (refereerc_state.mouse.x != 0 || refereerc_state.mouse.y != 0)) { // DBUS在线但摇杆/鼠标无输入时,使用VT13鼠标 - pitch_ratio = refereerc->vt13_packet.mouse.y / 32767.0 * 7.5 / 7.0; + pitch_ratio = refereerc_state.mouse.y / 32767.0 * 7.5 / 7.0; } else { - pitch_ratio = -dbus->ch3 / 18000.0 / 7.0; + pitch_ratio = -dbus_state.channels[3] / 18000.0 / 7.0; } - if (dbus->mouse.x != 0) { - yaw_ratio = -dbus->mouse.x / 32767.0 * 7.5 / 7.0; - } else if (refereerc->IsOnline() && - (refereerc->vt13_packet.mouse.x != 0 || refereerc->vt13_packet.mouse.y != 0)) { - yaw_ratio = -refereerc->vt13_packet.mouse.x / 32767.0 * 7.5 / 7.0; + if (dbus_state.mouse.x != 0) { + yaw_ratio = -dbus_state.mouse.x / 32767.0 * 7.5 / 7.0; + } else if ((refereerc != nullptr && refereerc->IsOnline()) && + (refereerc_state.mouse.x != 0 || refereerc_state.mouse.y != 0)) { + yaw_ratio = -refereerc_state.mouse.x / 32767.0 * 7.5 / 7.0; } else { - yaw_ratio = -dbus->ch2 / 18000.0 / 7.0; + yaw_ratio = -dbus_state.channels[2] / 18000.0 / 7.0; } - } else if (refereerc->IsOnline()) { + } else if ((refereerc != nullptr && refereerc->IsOnline())) { // DBUS离线时使用VT13:优先摇杆,否则鼠标 - if (refereerc->vt13_packet.remote.ch3 != remote::vt13_remote_t::ROCKER_MID || - refereerc->vt13_packet.remote.ch2 != remote::vt13_remote_t::ROCKER_MID) { - pitch_ratio = (float)(refereerc->vt13_packet.remote.ch2 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE / 18000.0 * 660.0 / 7.0; - yaw_ratio = (float)-(refereerc->vt13_packet.remote.ch3 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE / 18000.0 * 660.0 / 7.0; + if (refereerc_state.channels[3] != 0 || refereerc_state.channels[2] != 0) { + pitch_ratio = (float)(refereerc_state.channels[2]) / 660.0f / 18000.0 * 660.0 / 7.0; + yaw_ratio = (float)-(refereerc_state.channels[3]) / 660.0f / 18000.0 * 660.0 / 7.0; } else { - pitch_ratio = -refereerc->vt13_packet.mouse.y / 32767.0 * 7.5 / 7.0; - yaw_ratio = -refereerc->vt13_packet.mouse.x / 32767.0 * 7.5 / 7.0; + pitch_ratio = -refereerc_state.mouse.y / 32767.0 * 7.5 / 7.0; + yaw_ratio = -refereerc_state.mouse.x / 32767.0 * 7.5 / 7.0; } } else { pitch_ratio = 0; diff --git a/programs/Hero/gimbal/src/main.cpp b/programs/Hero/gimbal/src/main.cpp index 76d93611..34a8f692 100644 --- a/programs/Hero/gimbal/src/main.cpp +++ b/programs/Hero/gimbal/src/main.cpp @@ -96,6 +96,13 @@ void RM_RTOS_Default_Task(const void* arg) { Buzzer_Sing(DJI); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + set_cursor(0, 0); clear_screen(); @@ -106,31 +113,31 @@ void RM_RTOS_Default_Task(const void* arg) { // Movement info print( - "DBUS [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [TWL: %d] [SWL: %d] [SWR: %d]" + "DBUS [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [TWL: %d] [SWL: %s] [SWR: %s]" "@ %d " "ms\r\n", - dbus->ch0, - dbus->ch1, - dbus->ch2, - dbus->ch3, - dbus->ch4, - dbus->swl, - dbus->swr + dbus_state.channels[0], + dbus_state.channels[1], + dbus_state.channels[2], + dbus_state.channels[3], + dbus_state.channels[4], + controller::SwitchName(dbus_state.left_switch), + controller::SwitchName(dbus_state.right_switch) ); // VT13 info print( "VT13 [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [CH4: %-4d] [Mode: %d] [SWL: " "%d] " "[SWR: %d] [Trig: %d]\r\n", - refereerc->vt13_packet.remote.ch0, - refereerc->vt13_packet.remote.ch1, - refereerc->vt13_packet.remote.ch2, - refereerc->vt13_packet.remote.ch3, - refereerc->vt13_packet.remote.ch4, - refereerc->vt13_packet.remote.mode_sw, - refereerc->vt13_packet.remote.swl, - refereerc->vt13_packet.remote.swr, - refereerc->vt13_packet.remote.trigger + refereerc_state.channels[0], + refereerc_state.channels[1], + refereerc_state.channels[2], + refereerc_state.channels[3], + refereerc_state.channels[4], + static_cast(refereerc_state.mode), + refereerc_state.left_button, + refereerc_state.right_button, + refereerc_state.trigger ); print("Chassis %.3f %.3f %.3f\r\n", chassis->chassis_vy, chassis->chassis_vy, chassis->chassis_vt); print( @@ -152,7 +159,11 @@ void RM_RTOS_Default_Task(const void* arg) { print("\r\n"); print("[Referee %s] ", referee->IsOnline() ? "\033[32mOnline\033[0m" : "\033[31mOffline\033[0m"); print("\r\n"); - print("[Referee RC %s] ", refereerc->IsOnline() ? "\033[32mOnline\033[0m" : "\033[31mOffline\033[0m"); + print( + "[Referee RC %s] ", + (refereerc != nullptr && refereerc->IsOnline()) ? "\033[32mOnline\033[0m" : + "\033[31mOffline\033[0m" + ); print("\r\n"); print("[Yaw %s] ", yaw_motor->IsOnline() ? "\033[32mOnline\033[0m" : "\033[31mOffline\033[0m"); print("\r\n"); diff --git a/programs/Hero/gimbal/src/referee_task.cpp b/programs/Hero/gimbal/src/referee_task.cpp index 69548b4d..153d38b4 100644 --- a/programs/Hero/gimbal/src/referee_task.cpp +++ b/programs/Hero/gimbal/src/referee_task.cpp @@ -21,9 +21,8 @@ #include "referee_task.h" bsp::UART* referee_uart = nullptr; -bsp::UART* refereerc_uart = nullptr; communication::Referee* referee = nullptr; -communication::Referee* refereerc = nullptr; +controller::RefereeRC* refereerc = nullptr; void init_referee() { referee_uart = new bsp::UART(&BOARD_UART1); @@ -32,9 +31,5 @@ void init_referee() { referee = new communication::Referee(referee_uart); // 启动裁判系统图传链路(VT13遥控器) - refereerc_uart = new bsp::UART(&BOARD_UART2); - refereerc_uart->SetBaudrate(921600); - refereerc_uart->SetupRx(300); - refereerc_uart->SetupTx(300, false); - refereerc = new communication::Referee(refereerc_uart); + refereerc = new controller::RefereeRC(&BOARD_UART2); } diff --git a/programs/Hero/gimbal/src/remote_task.cpp b/programs/Hero/gimbal/src/remote_task.cpp index 0bda283a..00d7936c 100644 --- a/programs/Hero/gimbal/src/remote_task.cpp +++ b/programs/Hero/gimbal/src/remote_task.cpp @@ -25,7 +25,7 @@ #include "imu_task.h" -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; RemoteMode remote_mode = REMOTE_MODE_FOLLOW; RemoteMode last_remote_mode = REMOTE_MODE_FOLLOW; RemoteMode available_remote_mode[] = {REMOTE_MODE_FOLLOW, REMOTE_MODE_SPIN, REMOTE_MODE_ADVANCED}; @@ -37,28 +37,26 @@ bool is_killed = false; bool turbo_shoot = false; void init_dbus() { - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); } osThreadId_t remoteTaskHandle; void remoteTask(void* arg) { + using enum controller::ThreePositionSwitch; + UNUSED(arg); osDelay(1000); bool mode_switch = false; bool shoot_fric_switch = false; bool shoot_switch = false; bool shoot_stop_switch = false; - remote::switch_t last_state_r = remote::MID; - remote::switch_t last_state_l = remote::MID; - remote::keyboard_t last_keyboard; - remote::mouse_t last_mouse; - remote::switch_t state_r = remote::MID; - remote::switch_t state_l = remote::MID; - remote::keyboard_t keyboard; - remote::mouse_t mouse; - memset(&keyboard, 0, sizeof(keyboard)); - memset(&mouse, 0, sizeof(mouse)); - memset(&last_keyboard, 0, sizeof(last_keyboard)); - memset(&last_mouse, 0, sizeof(last_mouse)); + controller::ThreePositionSwitch last_state_r = Mid; + controller::ThreePositionSwitch last_state_l = Mid; + controller::KeyboardState last_keyboard{}; + controller::MouseState last_mouse{}; + controller::ThreePositionSwitch state_r = Mid; + controller::ThreePositionSwitch state_l = Mid; + controller::KeyboardState keyboard{}; + controller::MouseState mouse{}; bool is_dbus_offline; bool is_vt13_offline; bool is_robot_dead; @@ -74,11 +72,18 @@ void remoteTask(void* arg) { BoolEdgeDetector* vt13_trigger_edge = new BoolEdgeDetector(false); while (1) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + // 检测遥控器是否离线,或者遥控器是否在安全模式下 - is_dbus_offline = (!dbus->IsOnline()) || dbus->swr == remote::DOWN; + is_dbus_offline = (!dbus->IsOnline()) || dbus_state.right_switch == Down; // 检测VT13是否离线或不在C模式 - is_vt13_offline = - (!refereerc->IsOnline()) || refereerc->vt13_packet.remote.mode_sw != remote::vt13_remote_t::MODE_C; + is_vt13_offline = (!(refereerc != nullptr && refereerc->IsOnline())) || + refereerc_state.mode != controller::RefereeRcMode::C; #ifdef HAS_REFEREE is_robot_dead = referee->game_robot_status.remain_HP == 0; is_shoot_available = (referee->game_robot_status.shooter_heat_limit - @@ -117,22 +122,22 @@ void remoteTask(void* arg) { last_mouse = mouse; // Update State:优先使用DBUS,否则使用VT13 if (dbus->IsOnline()) { - state_r = dbus->swr; - state_l = dbus->swl; - keyboard = dbus->keyboard; - mouse = dbus->mouse; - } else if (refereerc->IsOnline()) { - state_r = remote::MID; - state_l = remote::MID; - keyboard = refereerc->vt13_packet.keyboard; - mouse = (remote::mouse_t)refereerc->vt13_packet.mouse; + state_r = dbus_state.right_switch; + state_l = dbus_state.left_switch; + keyboard = dbus_state.keyboard; + mouse = dbus_state.mouse; + } else if ((refereerc != nullptr && refereerc->IsOnline())) { + state_r = Mid; + state_l = Mid; + keyboard = refereerc_state.keyboard; + mouse = refereerc_state.mouse; } // Update Edge Detectors z_edge->input(keyboard.bit.Z); shift_edge->input(keyboard.bit.SHIFT); - mouse_left_edge->input(mouse.l); - mouse_right_edge->input(mouse.r); + mouse_left_edge->input(mouse.left); + mouse_right_edge->input(mouse.right); shoot_burst_edge->input(keyboard.bit.F); if (shoot_burst_edge->posEdge()) { @@ -140,25 +145,25 @@ void remoteTask(void* arg) { } // VT13 边沿检测 - vt13_pause_edge->input(refereerc->vt13_packet.remote.pause); - vt13_left_edge->input(refereerc->vt13_packet.remote.swl); - vt13_trigger_edge->input(refereerc->vt13_packet.remote.trigger); + vt13_pause_edge->input(refereerc_state.pause); + vt13_left_edge->input(refereerc_state.left_button); + vt13_trigger_edge->input(refereerc_state.trigger); // ========== 模式切换 ========== // DT7 右摇杆上拨 switch (state_r) { - case remote::UP: - if (last_state_r == remote::MID && dbus->IsOnline()) { + case Up: + if (last_state_r == Mid && dbus->IsOnline()) { mode_switch = true; } break; - case remote::MID: + case Mid: // 键盘 SHIFT 切换模式 if (shift_edge->posEdge()) { mode_switch = true; } break; - case remote::DOWN: + case Down: break; } // VT13 暂停键切换模式 @@ -177,24 +182,24 @@ void remoteTask(void* arg) { // ========== 摩擦轮切换 ========== // DT7 左摇杆上拨 switch (state_l) { - case remote::UP: - if (last_state_l == remote::MID && dbus->IsOnline()) { + case Up: + if (last_state_l == Mid && dbus->IsOnline()) { shoot_fric_switch = true; } break; - case remote::DOWN: - if (last_state_l == remote::MID && dbus->IsOnline()) { + case Down: + if (last_state_l == Mid && dbus->IsOnline()) { shoot_switch = true; } break; - case remote::MID: + case Mid: switch (last_state_l) { - case remote::DOWN: + case Down: shoot_stop_switch = true; break; - case remote::UP: + case Up: break; - case remote::MID: + case Mid: // 键盘 Z键 切换摩擦轮 if (z_edge->posEdge()) { shoot_fric_switch = true; @@ -236,7 +241,7 @@ void remoteTask(void* arg) { } } // 退弹 - 不受摩擦轮状态限制 - if (refereerc->vt13_packet.remote.ch4 < 424 || refereerc->vt13_packet.mouse.mid) { + if (refereerc_state.channels[4] < -600 || refereerc_state.mouse.middle) { shoot_load_mode = SHOOT_MODE_UNLOAD; } else if (shoot_load_mode == SHOOT_MODE_UNLOAD) { // 退弹条件消失,根据摩擦轮状态恢复 diff --git a/programs/Hero/gimbal/src/shoot_task.cpp b/programs/Hero/gimbal/src/shoot_task.cpp index 1dbcc134..50fce4c8 100644 --- a/programs/Hero/gimbal/src/shoot_task.cpp +++ b/programs/Hero/gimbal/src/shoot_task.cpp @@ -55,8 +55,8 @@ void shootTask(void* arg) { while (!imu->DataReady() || !imu->CaliDone()) { osDelay(SHOOT_OS_DELAY); } - // int last_state = remote::MID; - // int last_state_2 = remote::MID; + // auto last_state = controller::ThreePositionSwitch::Mid; + // auto last_state_2 = controller::ThreePositionSwitch::Mid; // uint8_t shoot_state = 0; // int shoot_flywheel_offset = 0; // uint8_t shoot_state_2 = 0; diff --git a/programs/Hero/gimbal/src/ui_task.cpp b/programs/Hero/gimbal/src/ui_task.cpp index 05d9ba4e..95689368 100644 --- a/programs/Hero/gimbal/src/ui_task.cpp +++ b/programs/Hero/gimbal/src/ui_task.cpp @@ -188,6 +188,13 @@ void uiTask(void* arg) { // BoolEdgeDetector* imu_temp_edge = new BoolEdgeDetector(false); // BoolEdgeDetector* shoot_jam_edge = new BoolEdgeDetector(false); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + // Update chassis GUI relative_angle = yaw_motor->GetThetaDelta(gimbal_param->yaw_offset_); // pitch_angle = pitch_motor->GetThetaDelta(gimbal_param->pitch_offset_); @@ -322,9 +329,9 @@ void uiTask(void* arg) { // clear self-diagnosis messages if (dbus->IsOnline()) { - v_edge->input(dbus->keyboard.bit.V); + v_edge->input(dbus_state.keyboard.bit.V); } else { - v_edge->input(refereerc->vt13_packet.keyboard.bit.V); + v_edge->input(refereerc_state.keyboard.bit.V); } if (v_edge->posEdge()) { @@ -428,9 +435,9 @@ void uiTask(void* arg) { continue; } if (dbus->IsOnline()) { - c_edge->input(dbus->keyboard.bit.C); + c_edge->input(dbus_state.keyboard.bit.C); } else { - c_edge->input(refereerc->vt13_packet.keyboard.bit.C); + c_edge->input(refereerc_state.keyboard.bit.C); } if (c_edge->posEdge()) { diagGUI->Clear(UI_Delay); From 6f712d2e1b3f297b883afb7569d76e2c70453dda Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:22 +0800 Subject: [PATCH 06/17] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=20DGStanda?= =?UTF-8?q?rd=20=E7=A8=8B=E5=BA=8F=E8=87=B3=20controller=20=E9=81=A5?= =?UTF-8?q?=E6=8E=A7=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DGStandard/gimbal/include/referee_task.h | 5 +- .../DGStandard/gimbal/include/remote_task.h | 4 +- .../DGStandard/gimbal/src/chassis_task.cpp | 38 ++++++----- .../DGStandard/gimbal/src/gimbal_task.cpp | 44 +++++++------ programs/DGStandard/gimbal/src/main.cpp | 55 +++++++++------- .../DGStandard/gimbal/src/referee_task.cpp | 10 +-- .../DGStandard/gimbal/src/remote_task.cpp | 65 ++++++++++--------- programs/DGStandard/gimbal/src/ui_task.cpp | 15 +++-- 8 files changed, 129 insertions(+), 107 deletions(-) diff --git a/programs/DGStandard/gimbal/include/referee_task.h b/programs/DGStandard/gimbal/include/referee_task.h index 1caa3466..5618d212 100644 --- a/programs/DGStandard/gimbal/include/referee_task.h +++ b/programs/DGStandard/gimbal/include/referee_task.h @@ -22,7 +22,7 @@ #include "bsp_print.h" #include "bsp_uart.h" #include "cmsis_os2.h" -#include "dji_dbus.h" +#include "refereerc.h" #include "main.h" #include "protocol.h" @@ -30,8 +30,7 @@ extern bsp::UART* referee_uart; extern communication::Referee* referee; -extern bsp::UART* refereerc_uart; -extern communication::Referee* refereerc; +extern controller::RefereeRC* refereerc; extern bsp::UART* minipc_uart; extern communication::Host* minipc; diff --git a/programs/DGStandard/gimbal/include/remote_task.h b/programs/DGStandard/gimbal/include/remote_task.h index a409c001..b2c4d2d5 100644 --- a/programs/DGStandard/gimbal/include/remote_task.h +++ b/programs/DGStandard/gimbal/include/remote_task.h @@ -20,12 +20,12 @@ #pragma once #include "cmsis_os2.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #include "referee_task.h" #include "user_define.h" #include "utils.h" -extern remote::DBUS* dbus; +extern controller::DBUS* dbus; /** * @brief Dbus Init */ diff --git a/programs/DGStandard/gimbal/src/chassis_task.cpp b/programs/DGStandard/gimbal/src/chassis_task.cpp index 7fd7ed0c..a31c47cf 100644 --- a/programs/DGStandard/gimbal/src/chassis_task.cpp +++ b/programs/DGStandard/gimbal/src/chassis_task.cpp @@ -52,6 +52,13 @@ void chassisTask(void* arg) { chassis->Enable(); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + if (remote_mode == REMOTE_MODE_KILL) { kill_chassis(); while (remote_mode == REMOTE_MODE_KILL) { @@ -61,11 +68,11 @@ void chassisTask(void* arg) { continue; } - remote::keyboard_t keyboard; + controller::KeyboardState keyboard{}; if (dbus->IsOnline()) { - keyboard = dbus->keyboard; - } else if (refereerc->IsOnline()) { - keyboard = refereerc->vt13_packet.keyboard; + keyboard = dbus_state.keyboard; + } else if ((refereerc != nullptr && refereerc->IsOnline())) { + keyboard = refereerc_state.keyboard; } // 以云台为基准的(整车的)运动速度,范围为[-1, 1] @@ -75,23 +82,20 @@ void chassisTask(void* arg) { // car_vy = 0; // car_vt = 0; // } else - if (dbus->ch0 || dbus->ch1 || dbus->ch2 || dbus->ch3 || dbus->ch4) { + if (dbus_state.channels[0] || dbus_state.channels[1] || dbus_state.channels[2] || dbus_state.channels[3] || + dbus_state.channels[4]) { // 优先使用遥控器 const float speed_scale = 0.5; - car_vx = (float)dbus->ch0 / dbus->ROCKER_MAX * speed_scale; - car_vy = (float)dbus->ch1 / dbus->ROCKER_MAX * speed_scale; - car_vt = (float)dbus->ch4 / dbus->ROCKER_MAX * speed_scale; - } else if (refereerc->vt13_packet.remote.ch0 != remote::vt13_remote_t::ROCKER_MID || - refereerc->vt13_packet.remote.ch1 != remote::vt13_remote_t::ROCKER_MID || - refereerc->vt13_packet.remote.ch4 != remote::vt13_remote_t::ROCKER_MID) { + car_vx = (float)dbus_state.channels[0] / 660.0f * speed_scale; + car_vy = (float)dbus_state.channels[1] / 660.0f * speed_scale; + car_vt = (float)dbus_state.channels[4] / 660.0f * speed_scale; + } else if (refereerc_state.channels[0] != 0 || refereerc_state.channels[1] != 0 || + refereerc_state.channels[4] != 0) { // 使用VT13遥控器 const float speed_scale = 0.5; - car_vx = (float)(refereerc->vt13_packet.remote.ch0 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE * speed_scale; - car_vy = (float)(refereerc->vt13_packet.remote.ch1 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE * speed_scale; - car_vt = (float)(refereerc->vt13_packet.remote.ch4 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE * speed_scale; + car_vx = (float)(refereerc_state.channels[0]) / 660.0f * speed_scale; + car_vy = (float)(refereerc_state.channels[1]) / 660.0f * speed_scale; + car_vt = (float)(refereerc_state.channels[4]) / 660.0f * speed_scale; } else { // 使用键盘 const float keyboard_speed = keyboard.bit.SHIFT ? 1 : 0.5; diff --git a/programs/DGStandard/gimbal/src/gimbal_task.cpp b/programs/DGStandard/gimbal/src/gimbal_task.cpp index da2d555a..7a348288 100644 --- a/programs/DGStandard/gimbal/src/gimbal_task.cpp +++ b/programs/DGStandard/gimbal/src/gimbal_task.cpp @@ -21,7 +21,7 @@ #include "gimbal_task.h" #include "chassis_task.h" -#include "dji_remote.h" +#include "dbus.h" #include "minipc_task.h" osThreadId_t gimbalTaskHandle; @@ -81,6 +81,13 @@ void gimbalTask(void* arg) { float pitch_target = 0, yaw_target = 0; while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + // 如果遥控器处于关闭状态,关闭两个电机 check_kill(); @@ -89,7 +96,7 @@ void gimbalTask(void* arg) { INS_Angle.yaw = ahrs->INS_angle[0]; // pitch_curr = witimu->INS_angle[0]; // yaw_curr = wrap(witimu->INS_angle[2]-yaw_offset, -PI, PI); - // if (dbus->swr == remote::UP) { + // if (dbus_state.right_switch == controller::ThreePositionSwitch::Up) { // gimbal->TargetAbs(0, 0); // gimbal->Update(); // pitch_target = pitch_curr; @@ -102,27 +109,24 @@ void gimbalTask(void* arg) { const float mouse_ratio = 1; const float remote_ratio = 0.005; if (dbus->IsOnline()) { - if (dbus->mouse.x != 0 || dbus->mouse.y != 0) { - pitch_ratio = (float)dbus->mouse.y / mouse_xy_max * mouse_ratio; - yaw_ratio = (float)dbus->mouse.x / mouse_xy_max * mouse_ratio; - } else if (refereerc->IsOnline() && - (refereerc->vt13_packet.mouse.x != 0 || refereerc->vt13_packet.mouse.y != 0)) { - pitch_ratio = (float)refereerc->remote_control.mouse.y / mouse_xy_max * mouse_ratio; - yaw_ratio = (float)refereerc->remote_control.mouse.x / mouse_xy_max * mouse_ratio; + if (dbus_state.mouse.x != 0 || dbus_state.mouse.y != 0) { + pitch_ratio = (float)dbus_state.mouse.y / 32767.0 * mouse_ratio; + yaw_ratio = (float)dbus_state.mouse.x / 32767.0 * mouse_ratio; + } else if ((refereerc != nullptr && refereerc->IsOnline()) && + (refereerc_state.mouse.x != 0 || refereerc_state.mouse.y != 0)) { + pitch_ratio = (float)refereerc_state.mouse.y / 32767.0 * mouse_ratio; + yaw_ratio = (float)refereerc_state.mouse.x / 32767.0 * mouse_ratio; } else { - pitch_ratio = (float)dbus->ch3 / dbus->ROCKER_MAX * remote_ratio; - yaw_ratio = (float)dbus->ch2 / dbus->ROCKER_MAX * remote_ratio; + pitch_ratio = (float)dbus_state.channels[3] / 660.0f * remote_ratio; + yaw_ratio = (float)dbus_state.channels[2] / 660.0f * remote_ratio; } - } else if (refereerc->IsOnline()) { - if (refereerc->vt13_packet.remote.ch3 != remote::vt13_remote_t::ROCKER_MID || - refereerc->vt13_packet.remote.ch2 != remote::vt13_remote_t::ROCKER_MID) { - pitch_ratio = (float)(refereerc->vt13_packet.remote.ch2 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE * remote_ratio; - yaw_ratio = (float)(refereerc->vt13_packet.remote.ch3 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE * remote_ratio; + } else if ((refereerc != nullptr && refereerc->IsOnline())) { + if (refereerc_state.channels[3] != 0 || refereerc_state.channels[2] != 0) { + pitch_ratio = (float)(refereerc_state.channels[2]) / 660.0f * remote_ratio; + yaw_ratio = (float)(refereerc_state.channels[3]) / 660.0f * remote_ratio; } else { - pitch_ratio = -refereerc->vt13_packet.mouse.y / mouse_xy_max * mouse_ratio; - yaw_ratio = refereerc->vt13_packet.mouse.x / mouse_xy_max * mouse_ratio; + pitch_ratio = -refereerc_state.mouse.y / 32767.0 * mouse_ratio; + yaw_ratio = refereerc_state.mouse.x / 32767.0 * mouse_ratio; } } else { pitch_ratio = 0; diff --git a/programs/DGStandard/gimbal/src/main.cpp b/programs/DGStandard/gimbal/src/main.cpp index 94fe6577..1f5b1dd3 100644 --- a/programs/DGStandard/gimbal/src/main.cpp +++ b/programs/DGStandard/gimbal/src/main.cpp @@ -105,6 +105,13 @@ void RM_RTOS_Default_Task(const void* arg) { // } while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + if (referee->game_robot_status.mains_power_gimbal_output) { gimbal_power->High(); } else { @@ -124,17 +131,17 @@ void RM_RTOS_Default_Task(const void* arg) { // DBUS info print( - "DBUS [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [TWL: %d] [SWL: %d] [SWR: %d]" + "DBUS [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [TWL: %d] [SWL: %s] [SWR: %s]" "@ %d " "ms\r\n", - dbus->ch0, - dbus->ch1, - dbus->ch2, - dbus->ch3, - dbus->ch4, - dbus->swl, - dbus->swr, - dbus->GetLastUptime() + dbus_state.channels[0], + dbus_state.channels[1], + dbus_state.channels[2], + dbus_state.channels[3], + dbus_state.channels[4], + controller::SwitchName(dbus_state.left_switch), + controller::SwitchName(dbus_state.right_switch), + dbus->GetLastValidTimeMs() ); print("\r\n"); @@ -142,26 +149,26 @@ void RM_RTOS_Default_Task(const void* arg) { print( "VT13 [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [CH4: %-4d]" " [Mode: %d] [SWL: %d] [SWR: %d] [Trig: %d]\r\n", - refereerc->vt13_packet.remote.ch0, - refereerc->vt13_packet.remote.ch1, - refereerc->vt13_packet.remote.ch2, - refereerc->vt13_packet.remote.ch3, - refereerc->vt13_packet.remote.ch4, - refereerc->vt13_packet.remote.mode_sw, - (int)refereerc->vt13_packet.remote.swl, - (int)refereerc->vt13_packet.remote.swr ? 1 : 0, - (int)refereerc->vt13_packet.remote.trigger ? 1 : 0 + refereerc_state.channels[0], + refereerc_state.channels[1], + refereerc_state.channels[2], + refereerc_state.channels[3], + refereerc_state.channels[4], + static_cast(refereerc_state.mode), + (int)refereerc_state.left_button, + (int)refereerc_state.right_button ? 1 : 0, + (int)refereerc_state.trigger ? 1 : 0 ); print("\r\n"); - auto& mouse = refereerc->vt13_packet.mouse; + const auto& mouse = refereerc_state.mouse; print( "Mouse: [X: %d] [Y: %d] [ROLL: %d] [L %d] [R %d] [MID %d]", mouse.x, mouse.y, - mouse.roll, - mouse.l, - mouse.r, - mouse.mid + mouse.z, + mouse.left, + mouse.right, + mouse.middle ); print("\r\n"); @@ -202,7 +209,7 @@ void RM_RTOS_Default_Task(const void* arg) { print("Comm Stat: "); print_enabled("DBUS", dbus->IsOnline()); print_enabled("Referee", referee->IsOnline()); - print_enabled("Referee RC", refereerc->IsOnline()); + print_enabled("Referee RC", (refereerc != nullptr && refereerc->IsOnline())); print("\r\n"); print("Motor Stat: "); print_enabled("Yaw", yaw_motor->IsOnline()); diff --git a/programs/DGStandard/gimbal/src/referee_task.cpp b/programs/DGStandard/gimbal/src/referee_task.cpp index e08e48b3..52d776a6 100644 --- a/programs/DGStandard/gimbal/src/referee_task.cpp +++ b/programs/DGStandard/gimbal/src/referee_task.cpp @@ -21,9 +21,8 @@ #include "referee_task.h" bsp::UART* referee_uart = nullptr; -bsp::UART* refereerc_uart = nullptr; communication::Referee* referee = nullptr; -communication::Referee* refereerc = nullptr; +controller::RefereeRC* refereerc = nullptr; void init_referee() { // 启动裁判系统 @@ -33,10 +32,5 @@ void init_referee() { referee = new communication::Referee(referee_uart); // 启动裁判系统图传链路 - refereerc_uart = new bsp::UART(&huart7); - refereerc_uart->SetBaudrate(921600); - refereerc_uart->SetupRx(300); - // UART7没有打开DMA发送,所以这里需要将DMA发送关闭 - refereerc_uart->SetupTx(300, false); - refereerc = new communication::Referee(refereerc_uart); + refereerc = new controller::RefereeRC(&huart7); } diff --git a/programs/DGStandard/gimbal/src/remote_task.cpp b/programs/DGStandard/gimbal/src/remote_task.cpp index 73855c25..08a23115 100644 --- a/programs/DGStandard/gimbal/src/remote_task.cpp +++ b/programs/DGStandard/gimbal/src/remote_task.cpp @@ -25,7 +25,7 @@ #include "gimbal_task.h" #include "imu_task.h" -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; RemoteMode remote_mode = REMOTE_MODE_FOLLOW; RemoteMode last_remote_mode = REMOTE_MODE_FOLLOW; RemoteMode available_remote_mode[] = {REMOTE_MODE_FOLLOW, REMOTE_MODE_SPIN, REMOTE_MODE_ADVANCED, REMOTE_MODE_AUTOAIM}; @@ -44,24 +44,24 @@ bool is_autoaim = false; void init_dbus() { // 初始化遥控器 - dbus = new remote::DBUS(&huart1); + dbus = new controller::DBUS(&huart1); } osThreadId_t remoteTaskHandle; // #define HAS_REFEREE void remoteTask(void* arg) { + using enum controller::ThreePositionSwitch; + UNUSED(arg); osDelay(1000); uint32_t shoot_burst_timestamp = 0; - remote::switch_t state_r = remote::MID; - remote::switch_t state_l = remote::MID; - remote::keyboard_t keyboard; - remote::mouse_t mouse; + controller::ThreePositionSwitch state_r = Mid; + controller::ThreePositionSwitch state_l = Mid; + controller::KeyboardState keyboard{}; + controller::MouseState mouse{}; - memset(&keyboard, 0, sizeof(keyboard)); - memset(&mouse, 0, sizeof(mouse)); bool is_dbus_offline; bool is_vt13_offline; bool is_robot_dead; @@ -79,10 +79,17 @@ void remoteTask(void* arg) { BoolEdgeDetector* vt13_trigger_edge = new BoolEdgeDetector(false); while (1) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + // 检测遥控器是否离线,或者遥控器是否在安全模式下 - is_dbus_offline = (!dbus->IsOnline()) || dbus->swr == remote::DOWN; - is_vt13_offline = - (!refereerc->IsOnline()) || refereerc->vt13_packet.remote.mode_sw != remote::vt13_remote_t::MODE_C; + is_dbus_offline = (!dbus->IsOnline()) || dbus_state.right_switch == Down; + is_vt13_offline = (!(refereerc != nullptr && refereerc->IsOnline())) || + refereerc_state.mode != controller::RefereeRcMode::C; #ifdef HAS_REFEREE // Kill Detection is_robot_dead = referee->game_robot_status.remain_HP == 0; @@ -119,28 +126,28 @@ void remoteTask(void* arg) { } if (dbus->IsOnline()) { - state_r = dbus->swr; - state_l = dbus->swl; - keyboard = dbus->keyboard; - mouse = dbus->mouse; - } else if (refereerc->IsOnline()) { - keyboard = refereerc->vt13_packet.keyboard; - mouse = (remote::mouse_t)refereerc->vt13_packet.mouse; + state_r = dbus_state.right_switch; + state_l = dbus_state.left_switch; + keyboard = dbus_state.keyboard; + mouse = dbus_state.mouse; + } else if ((refereerc != nullptr && refereerc->IsOnline())) { + keyboard = refereerc_state.keyboard; + mouse = refereerc_state.mouse; } - mouse_left_edge->input(mouse.l); - mouse_right_edge->input(mouse.r); + mouse_left_edge->input(mouse.left); + mouse_right_edge->input(mouse.right); keyboard_G_edge->input(keyboard.bit.G); keyboard_B_edge->input(keyboard.bit.B); // DT7遥控器 右摇杆切换模式 static BoolEdgeDetector* mode_switch_edge = new BoolEdgeDetector(false); - mode_switch_edge->input(state_r == remote::UP); + mode_switch_edge->input(state_r == Up); // 键盘 左CTRL切换模式 keyboard_ctrl_edge->input(keyboard.bit.CTRL); // VT13 暂停键切换模式 - vt13_pause_edge->input(refereerc->vt13_packet.remote.pause); + vt13_pause_edge->input(refereerc_state.pause); if (mode_switch_edge->posEdge() || keyboard_ctrl_edge->posEdge() || vt13_pause_edge->posEdge()) { RemoteMode next_mode = (RemoteMode)(remote_mode + 1); @@ -165,7 +172,7 @@ void remoteTask(void* arg) { // } static BoolEdgeDetector remote_swr; - remote_swr.input(refereerc->vt13_packet.remote.swr || mouse.r); + remote_swr.input(refereerc_state.right_button || mouse.right); if (remote_swr.posEdge()) { is_autoaim = true; } @@ -176,7 +183,7 @@ void remoteTask(void* arg) { /* 测试PID,摩擦轮关闭时,左摇杆下拨测试云台转动 if (shoot_flywheel_mode == SHOOT_FRIC_MODE_STOP) { static BoolEdgeDetector* test_edge = new BoolEdgeDetector(false); - test_edge->input(state_l == remote::DOWN); + test_edge->input(state_l == Down); if (test_edge->posEdge()) { gimbal->TargetReal(0, PI / 1.5); } @@ -198,11 +205,11 @@ void remoteTask(void* arg) { // DT7 左摇杆上拨 切换摩擦轮 static BoolEdgeDetector* flywheel_switch_edge = new BoolEdgeDetector(false); - flywheel_switch_edge->input(state_l == remote::UP); + flywheel_switch_edge->input(state_l == Up); // 键盘 Z键 切换摩擦轮 keyboard_Z_edge->input(keyboard.bit.Z); // VT13 左键 切换摩擦轮 - vt13_left_edge->input(refereerc->vt13_packet.remote.swl); + vt13_left_edge->input(refereerc_state.left_button); if (flywheel_switch_edge->posEdge() || keyboard_Z_edge->posEdge() || vt13_left_edge->posEdge()) { if (shoot_flywheel_mode == SHOOT_FRIC_MODE_STOP) { // 原来停止则开始转 @@ -217,9 +224,9 @@ void remoteTask(void* arg) { // DT7 左摇杆下拨 static BoolEdgeDetector* shoot_switch_edge = new BoolEdgeDetector(false); - shoot_switch_edge->input(state_l == remote::DOWN); + shoot_switch_edge->input(state_l == Down); // VT13 扳机键 - vt13_trigger_edge->input(refereerc->vt13_packet.remote.trigger); + vt13_trigger_edge->input(refereerc_state.trigger); if (shoot_switch_edge->posEdge() || mouse_left_edge->posEdge() || vt13_trigger_edge->posEdge()) { shoot_load_mode = SHOOT_MODE_SINGLE; @@ -227,7 +234,7 @@ void remoteTask(void* arg) { } // 连发 - if (state_l == remote::DOWN || mouse.l || refereerc->vt13_packet.remote.trigger) { + if (state_l == Down || mouse.left || refereerc_state.trigger) { shoot_burst_timestamp++; } static BoolEdgeDetector* shoot_burst_switch_edge = new BoolEdgeDetector(false); diff --git a/programs/DGStandard/gimbal/src/ui_task.cpp b/programs/DGStandard/gimbal/src/ui_task.cpp index 1c0dd60f..8da09158 100644 --- a/programs/DGStandard/gimbal/src/ui_task.cpp +++ b/programs/DGStandard/gimbal/src/ui_task.cpp @@ -152,6 +152,13 @@ void uiTask(void* arg) { BoolEdgeDetector* shoot_jam_edge = new BoolEdgeDetector(false); BoolEdgeDetector* bullet_edge = new BoolEdgeDetector(false); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + // Update chassis GUI // 通过两个云台电机的角度 float relative_angle = yaw_motor->GetThetaDelta(gimbal_param->yaw_offset_); @@ -351,9 +358,9 @@ void uiTask(void* arg) { // v键清理UI if (dbus->IsOnline()) - v_edge->input(dbus->keyboard.bit.V); + v_edge->input(dbus_state.keyboard.bit.V); else - v_edge->input(refereerc->vt13_packet.keyboard.bit.V); + v_edge->input(refereerc_state.keyboard.bit.V); if (v_edge->posEdge()) { osDelay(110); @@ -429,9 +436,9 @@ void uiTask(void* arg) { // c键清理消息 if (dbus->IsOnline()) - c_edge->input(dbus->keyboard.bit.C); + c_edge->input(dbus_state.keyboard.bit.C); else - c_edge->input(refereerc->vt13_packet.keyboard.bit.C); + c_edge->input(refereerc_state.keyboard.bit.C); if (c_edge->posEdge()) { diagGUI->Clear(UI_Delay); } From a11eb23201ca8f558354b0e970ce9a08fd9e8933 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:22 +0800 Subject: [PATCH 07/17] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=20Cakey=20?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E8=87=B3=20controller=20=E9=81=A5=E6=8E=A7?= =?UTF-8?q?=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- programs/Cakey/include/referee_task.h | 5 +-- programs/Cakey/include/remote_task.h | 4 +- programs/Cakey/src/chassis_task.cpp | 24 +++++++---- programs/Cakey/src/gimbal_task.cpp | 27 +++++++----- programs/Cakey/src/main.cpp | 21 ++++++---- programs/Cakey/src/referee_task.cpp | 9 +--- programs/Cakey/src/remote_task.cpp | 59 +++++++++++++++------------ programs/Cakey/src/ui_task.cpp | 15 +++++-- 8 files changed, 95 insertions(+), 69 deletions(-) diff --git a/programs/Cakey/include/referee_task.h b/programs/Cakey/include/referee_task.h index 1caa3466..5618d212 100644 --- a/programs/Cakey/include/referee_task.h +++ b/programs/Cakey/include/referee_task.h @@ -22,7 +22,7 @@ #include "bsp_print.h" #include "bsp_uart.h" #include "cmsis_os2.h" -#include "dji_dbus.h" +#include "refereerc.h" #include "main.h" #include "protocol.h" @@ -30,8 +30,7 @@ extern bsp::UART* referee_uart; extern communication::Referee* referee; -extern bsp::UART* refereerc_uart; -extern communication::Referee* refereerc; +extern controller::RefereeRC* refereerc; extern bsp::UART* minipc_uart; extern communication::Host* minipc; diff --git a/programs/Cakey/include/remote_task.h b/programs/Cakey/include/remote_task.h index a409c001..b2c4d2d5 100644 --- a/programs/Cakey/include/remote_task.h +++ b/programs/Cakey/include/remote_task.h @@ -20,12 +20,12 @@ #pragma once #include "cmsis_os2.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #include "referee_task.h" #include "user_define.h" #include "utils.h" -extern remote::DBUS* dbus; +extern controller::DBUS* dbus; /** * @brief Dbus Init */ diff --git a/programs/Cakey/src/chassis_task.cpp b/programs/Cakey/src/chassis_task.cpp index d6e8f515..d6e94517 100644 --- a/programs/Cakey/src/chassis_task.cpp +++ b/programs/Cakey/src/chassis_task.cpp @@ -55,6 +55,13 @@ void chassisTask(void* arg) { chassis->Enable(); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + if (remote_mode == REMOTE_MODE_KILL) { kill_chassis(); while (remote_mode == REMOTE_MODE_KILL) { @@ -64,21 +71,22 @@ void chassisTask(void* arg) { continue; } - remote::keyboard_t keyboard; + controller::KeyboardState keyboard{}; if (dbus->IsOnline()) { - keyboard = dbus->keyboard; - } else if (refereerc->IsOnline()) { - keyboard = refereerc->remote_control.keyboard; + keyboard = dbus_state.keyboard; + } else if ((refereerc != nullptr && refereerc->IsOnline())) { + keyboard = refereerc_state.keyboard; } // 以云台为基准的(整车的)运动速度,范围为[-1, 1] float car_vx, car_vy, car_vt; - if (dbus->ch0 || dbus->ch1 || dbus->ch2 || dbus->ch3 || dbus->ch4) { + if (dbus_state.channels[0] || dbus_state.channels[1] || dbus_state.channels[2] || dbus_state.channels[3] || + dbus_state.channels[4]) { // 优先使用遥控器 const float speed_scale = 0.5; - car_vx = (float)dbus->ch0 / dbus->ROCKER_MAX * speed_scale; - car_vy = (float)dbus->ch1 / dbus->ROCKER_MAX * speed_scale; - car_vt = (float)dbus->ch4 / dbus->ROCKER_MAX * speed_scale; + car_vx = (float)dbus_state.channels[0] / 660.0f * speed_scale; + car_vy = (float)dbus_state.channels[1] / 660.0f * speed_scale; + car_vt = (float)dbus_state.channels[4] / 660.0f * speed_scale; } else { // 使用键盘 const float keyboard_speed = keyboard.bit.SHIFT ? 1 : 0.5; diff --git a/programs/Cakey/src/gimbal_task.cpp b/programs/Cakey/src/gimbal_task.cpp index a368585c..1ee7fe33 100644 --- a/programs/Cakey/src/gimbal_task.cpp +++ b/programs/Cakey/src/gimbal_task.cpp @@ -21,7 +21,7 @@ #include "gimbal_task.h" #include "chassis_task.h" -#include "dji_remote.h" +#include "dbus.h" #include "minipc_task.h" osThreadId_t gimbalTaskHandle; @@ -80,6 +80,13 @@ void gimbalTask(void* arg) { float pitch_target = 0, yaw_target = 0; while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + // 如果遥控器处于关闭状态,关闭两个电机 check_kill(); @@ -88,7 +95,7 @@ void gimbalTask(void* arg) { INS_Angle.yaw = ahrs->INS_angle[0]; // pitch_curr = witimu->INS_angle[0]; // yaw_curr = wrap(witimu->INS_angle[2]-yaw_offset, -PI, PI); - // if (dbus->swr == remote::UP) { + // if (dbus_state.right_switch == controller::ThreePositionSwitch::Up) { // gimbal->TargetAbs(0, 0); // gimbal->Update(); // pitch_target = pitch_curr; @@ -101,16 +108,16 @@ void gimbalTask(void* arg) { const float mouse_ratio = 0.5; const float remote_ratio = 0.005; if (dbus->IsOnline()) { - if (dbus->mouse.x != 0 || dbus->mouse.y != 0) { - pitch_ratio = (float)dbus->mouse.y / mouse_xy_max * mouse_ratio; - yaw_ratio = (float)dbus->mouse.x / mouse_xy_max * mouse_ratio; + if (dbus_state.mouse.x != 0 || dbus_state.mouse.y != 0) { + pitch_ratio = (float)dbus_state.mouse.y / 32767.0 * mouse_ratio; + yaw_ratio = (float)dbus_state.mouse.x / 32767.0 * mouse_ratio; } else { - pitch_ratio = (float)dbus->ch3 / dbus->ROCKER_MAX * remote_ratio; - yaw_ratio = (float)dbus->ch2 / dbus->ROCKER_MAX * remote_ratio; + pitch_ratio = (float)dbus_state.channels[3] / 660.0f * remote_ratio; + yaw_ratio = (float)dbus_state.channels[2] / 660.0f * remote_ratio; } - } else if (refereerc->IsOnline()) { - pitch_ratio = -refereerc->remote_control.mouse.y / mouse_xy_max * mouse_ratio; - yaw_ratio = -refereerc->remote_control.mouse.x / mouse_xy_max * mouse_ratio; + } else if ((refereerc != nullptr && refereerc->IsOnline())) { + pitch_ratio = -refereerc_state.mouse.y / 32767.0 * mouse_ratio; + yaw_ratio = -refereerc_state.mouse.x / 32767.0 * mouse_ratio; } else { pitch_ratio = 0; yaw_ratio = 0; diff --git a/programs/Cakey/src/main.cpp b/programs/Cakey/src/main.cpp index 0635467e..c5215faf 100644 --- a/programs/Cakey/src/main.cpp +++ b/programs/Cakey/src/main.cpp @@ -101,6 +101,9 @@ void RM_RTOS_Default_Task(const void* arg) { // } while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + if (referee->game_robot_status.mains_power_gimbal_output) { gimbal_power->High(); } else { @@ -119,17 +122,17 @@ void RM_RTOS_Default_Task(const void* arg) { // DBUS info print( - "DBUS [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [TWL: %d] [SWL: %d] [SWR: %d]" + "DBUS [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [TWL: %d] [SWL: %s] [SWR: %s]" "@ %d " "ms\r\n", - dbus->ch0, - dbus->ch1, - dbus->ch2, - dbus->ch3, - dbus->ch4, - dbus->swl, - dbus->swr, - dbus->GetLastUptime() + dbus_state.channels[0], + dbus_state.channels[1], + dbus_state.channels[2], + dbus_state.channels[3], + dbus_state.channels[4], + controller::SwitchName(dbus_state.left_switch), + controller::SwitchName(dbus_state.right_switch), + dbus->GetLastValidTimeMs() ); print("\r\n"); diff --git a/programs/Cakey/src/referee_task.cpp b/programs/Cakey/src/referee_task.cpp index 39552af3..95a66986 100644 --- a/programs/Cakey/src/referee_task.cpp +++ b/programs/Cakey/src/referee_task.cpp @@ -21,9 +21,8 @@ #include "referee_task.h" bsp::UART* referee_uart = nullptr; -bsp::UART* refereerc_uart = nullptr; communication::Referee* referee = nullptr; -communication::Referee* refereerc = nullptr; +controller::RefereeRC* refereerc = nullptr; void init_referee() { // 启动裁判系统 @@ -33,9 +32,5 @@ void init_referee() { referee = new communication::Referee(referee_uart); // 启动裁判系统图传链路 - refereerc_uart = new bsp::UART(&huart2); - refereerc_uart->SetupRx(300); - // UART7没有打开DMA发送,所以这里需要将DMA发送关闭 - refereerc_uart->SetupTx(300, false); - refereerc = new communication::Referee(refereerc_uart); + refereerc = new controller::RefereeRC(&huart2); } diff --git a/programs/Cakey/src/remote_task.cpp b/programs/Cakey/src/remote_task.cpp index f3ab94af..080775c2 100644 --- a/programs/Cakey/src/remote_task.cpp +++ b/programs/Cakey/src/remote_task.cpp @@ -25,7 +25,7 @@ #include "gimbal_task.h" #include "imu_task.h" -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; RemoteMode remote_mode = REMOTE_MODE_FOLLOW; RemoteMode last_remote_mode = REMOTE_MODE_FOLLOW; RemoteMode available_remote_mode[] = {REMOTE_MODE_FOLLOW, REMOTE_MODE_SPIN, REMOTE_MODE_ADVANCED, REMOTE_MODE_AUTOAIM}; @@ -44,24 +44,24 @@ bool is_autoaim = false; void init_dbus() { // 初始化遥控器 - dbus = new remote::DBUS(&huart1); + dbus = new controller::DBUS(&huart1); } osThreadId_t remoteTaskHandle; // #define HAS_REFEREE void remoteTask(void* arg) { + using enum controller::ThreePositionSwitch; + UNUSED(arg); osDelay(1000); uint32_t shoot_burst_timestamp = 0; - remote::switch_t state_r = remote::MID; - remote::switch_t state_l = remote::MID; - remote::keyboard_t keyboard; - remote::mouse_t mouse; + controller::ThreePositionSwitch state_r = Mid; + controller::ThreePositionSwitch state_l = Mid; + controller::KeyboardState keyboard{}; + controller::MouseState mouse{}; - memset(&keyboard, 0, sizeof(keyboard)); - memset(&mouse, 0, sizeof(mouse)); bool is_dbus_offline; bool is_robot_dead; bool is_shoot_available; @@ -74,8 +74,15 @@ void remoteTask(void* arg) { BoolEdgeDetector* keyboard_B_edge = new BoolEdgeDetector(false); while (1) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + // 检测遥控器是否离线,或者遥控器是否在安全模式下 - is_dbus_offline = (!dbus->IsOnline()) || dbus->swr == remote::DOWN; + is_dbus_offline = (!dbus->IsOnline()) || dbus_state.right_switch == Down; #ifdef HAS_REFEREE // Kill Detection is_robot_dead = referee->game_robot_status.remain_HP == 0; @@ -112,20 +119,20 @@ void remoteTask(void* arg) { } if (dbus->IsOnline()) { - state_r = dbus->swr; - state_l = dbus->swl; - keyboard = dbus->keyboard; - mouse = dbus->mouse; - } else if (refereerc->IsOnline()) { - state_r = remote::MID; - state_l = remote::MID; - keyboard = refereerc->remote_control.keyboard; - mouse = refereerc->remote_control.mouse; + state_r = dbus_state.right_switch; + state_l = dbus_state.left_switch; + keyboard = dbus_state.keyboard; + mouse = dbus_state.mouse; + } else if ((refereerc != nullptr && refereerc->IsOnline())) { + state_r = Mid; + state_l = Mid; + keyboard = refereerc_state.keyboard; + mouse = refereerc_state.mouse; } // Update Timestamp - mouse_left_edge->input(mouse.l); - mouse_right_edge->input(mouse.r); + mouse_left_edge->input(mouse.left); + mouse_right_edge->input(mouse.right); keyboard_ctrl_edge->input(keyboard.bit.CTRL); keyboard_G_edge->input(keyboard.bit.G); @@ -133,7 +140,7 @@ void remoteTask(void* arg) { // remote mode switch static BoolEdgeDetector* mode_switch_edge = new BoolEdgeDetector(false); - mode_switch_edge->input(state_r == remote::UP); + mode_switch_edge->input(state_r == Up); if (mode_switch_edge->posEdge() || keyboard_ctrl_edge->posEdge()) { RemoteMode next_mode = (RemoteMode)(remote_mode + 1); @@ -158,7 +165,7 @@ void remoteTask(void* arg) { if (shoot_flywheel_mode == SHOOT_FRIC_MODE_STOP) { static BoolEdgeDetector* test_edge = new BoolEdgeDetector(false); - test_edge->input(state_l == remote::DOWN); + test_edge->input(state_l == Down); if (test_edge->posEdge()) { gimbal->TargetReal(0, PI / 1.5); } @@ -180,7 +187,7 @@ void remoteTask(void* arg) { // 切换摩擦轮 static BoolEdgeDetector* flywheel_switch_edge = new BoolEdgeDetector(false); - flywheel_switch_edge->input(state_l == remote::UP); + flywheel_switch_edge->input(state_l == Up); keyboard_Z_edge->input(keyboard.bit.Z); if (flywheel_switch_edge->posEdge() || keyboard_Z_edge->posEdge()) { if (shoot_flywheel_mode == SHOOT_FRIC_MODE_STOP) { // 原来停止则开始转 @@ -196,7 +203,7 @@ void remoteTask(void* arg) { if (!is_autoaim || !minipc->IsOnline()) { // 单发 static BoolEdgeDetector* shoot_switch_edge = new BoolEdgeDetector(false); - shoot_switch_edge->input(state_l == remote::DOWN); + shoot_switch_edge->input(state_l == Down); if (shoot_switch_edge->posEdge() || mouse_left_edge->posEdge()) { shoot_load_mode = SHOOT_MODE_SINGLE; @@ -204,7 +211,7 @@ void remoteTask(void* arg) { } // 连发 - if (state_l == remote::DOWN || mouse.l) { + if (state_l == Down || mouse.left) { shoot_burst_timestamp++; } static BoolEdgeDetector* shoot_burst_switch_edge = new BoolEdgeDetector(false); @@ -221,7 +228,7 @@ void remoteTask(void* arg) { } else { // 自喵模式下只有连发 if (minipc->IsOnline()) { - if (minipc->target_angle.shoot_cmd != 0 && mouse.l) { + if (minipc->target_angle.shoot_cmd != 0 && mouse.left) { shoot_load_mode = SHOOT_MODE_BURST; } else { shoot_load_mode = SHOOT_MODE_STOP; diff --git a/programs/Cakey/src/ui_task.cpp b/programs/Cakey/src/ui_task.cpp index dd6f29c4..1e86a3a1 100644 --- a/programs/Cakey/src/ui_task.cpp +++ b/programs/Cakey/src/ui_task.cpp @@ -144,6 +144,13 @@ void uiTask(void* arg) { BoolEdgeDetector* imu_temp_edge = new BoolEdgeDetector(false); BoolEdgeDetector* shoot_jam_edge = new BoolEdgeDetector(false); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + // Update chassis GUI // 通过两个云台电机的角度 relative_angle = yaw_motor->GetThetaDelta(gimbal_param->yaw_offset_); @@ -302,9 +309,9 @@ void uiTask(void* arg) { // v键清理UI if (dbus->IsOnline()) { - v_edge->input(dbus->keyboard.bit.V); + v_edge->input(dbus_state.keyboard.bit.V); } else { - v_edge->input(refereerc->remote_control.keyboard.bit.V); + v_edge->input(refereerc_state.keyboard.bit.V); } if (v_edge->posEdge()) { @@ -373,9 +380,9 @@ void uiTask(void* arg) { } // c键清理消息 if (dbus->IsOnline()) { - c_edge->input(dbus->keyboard.bit.C); + c_edge->input(dbus_state.keyboard.bit.C); } else { - c_edge->input(refereerc->remote_control.keyboard.bit.C); + c_edge->input(refereerc_state.keyboard.bit.C); } if (c_edge->posEdge()) { diagGUI->Clear(UI_Delay); From b60ced204aa88d3a27b2523748fb28a072517187 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:22 +0800 Subject: [PATCH 08/17] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=20Ares=20?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E8=87=B3=20controller=20=E9=81=A5=E6=8E=A7?= =?UTF-8?q?=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- programs/Ares/chassis/src/chassis_example.cpp | 17 ++- programs/Ares/gimbal/include/referee_task.h | 5 +- programs/Ares/gimbal/include/remote_task.h | 4 +- programs/Ares/gimbal/src/chassis_task.cpp | 44 ++++---- programs/Ares/gimbal/src/gimbal_task.cpp | 36 +++--- programs/Ares/gimbal/src/main.cpp | 31 ++++-- programs/Ares/gimbal/src/referee_task.cpp | 9 +- programs/Ares/gimbal/src/remote_task.cpp | 105 +++++++++--------- .../Ares/gimbal/src/remote_task_automata.cpp | 79 +++++++------ programs/Ares/gimbal/src/shoot_task.cpp | 4 +- programs/Ares/gimbal/src/ui_task.cpp | 17 ++- 11 files changed, 198 insertions(+), 153 deletions(-) diff --git a/programs/Ares/chassis/src/chassis_example.cpp b/programs/Ares/chassis/src/chassis_example.cpp index 30cd208d..3d146fa6 100644 --- a/programs/Ares/chassis/src/chassis_example.cpp +++ b/programs/Ares/chassis/src/chassis_example.cpp @@ -21,7 +21,7 @@ #include "bsp_print.h" #include "chassis.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" bsp::CAN* can = nullptr; driver::DjiMotorBase* fl_motor = nullptr; @@ -30,7 +30,7 @@ driver::DjiMotorBase* bl_motor = nullptr; driver::DjiMotorBase* br_motor = nullptr; control::Chassis* chassis = nullptr; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; void RM_RTOS_Init() { HAL_Delay(200); @@ -89,21 +89,28 @@ void RM_RTOS_Init() { chassis_data.model = control::CHASSIS_MECANUM_WHEEL; chassis = new control::Chassis(chassis_data); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); HAL_Delay(300); } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); osDelay(500); // DBUS initialization needs time while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + const float ratio = 1.0f / 660.0f * 6 * PI; - chassis->SetSpeed(dbus->ch0 * ratio, dbus->ch1 * ratio, dbus->ch2 * ratio); + chassis + ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus->swl == remote::UP || dbus->swl == remote::DOWN) { + if (dbus_state.left_switch == Up || + dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/programs/Ares/gimbal/include/referee_task.h b/programs/Ares/gimbal/include/referee_task.h index 0446d82f..bb008599 100644 --- a/programs/Ares/gimbal/include/referee_task.h +++ b/programs/Ares/gimbal/include/referee_task.h @@ -22,7 +22,7 @@ #include "bsp_print.h" #include "bsp_uart.h" #include "cmsis_os2.h" -#include "dji_dbus.h" +#include "refereerc.h" #include "main.h" #include "protocol.h" @@ -30,7 +30,6 @@ extern bsp::UART* referee_uart; extern communication::Referee* referee; -extern bsp::UART* refereerc_uart; -extern communication::Referee* refereerc; +extern controller::RefereeRC* refereerc; void init_referee(); \ No newline at end of file diff --git a/programs/Ares/gimbal/include/remote_task.h b/programs/Ares/gimbal/include/remote_task.h index 61c0a8c6..99e17f17 100644 --- a/programs/Ares/gimbal/include/remote_task.h +++ b/programs/Ares/gimbal/include/remote_task.h @@ -20,12 +20,12 @@ #pragma once #include "cmsis_os2.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #include "referee_task.h" #include "user_define.h" #include "utils.h" -extern remote::DBUS* dbus; +extern controller::DBUS* dbus; extern bool turbo_shoot; /** * @brief Dbus Init diff --git a/programs/Ares/gimbal/src/chassis_task.cpp b/programs/Ares/gimbal/src/chassis_task.cpp index bc9a67fc..0625bbf0 100644 --- a/programs/Ares/gimbal/src/chassis_task.cpp +++ b/programs/Ares/gimbal/src/chassis_task.cpp @@ -51,6 +51,13 @@ void chassisTask(void* arg) { chassis->Enable(); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + if (remote_mode == REMOTE_MODE_KILL) { kill_chassis(); while (remote_mode == REMOTE_MODE_KILL) { @@ -61,13 +68,13 @@ void chassisTask(void* arg) { } const bool vt13_c_mode = (refereerc != nullptr) && refereerc->IsOnline() && - (refereerc->vt13_packet.remote.mode_sw == remote::vt13_remote_t::MODE_C); + (refereerc_state.mode == controller::RefereeRcMode::C); - remote::keyboard_t keyboard{}; + controller::KeyboardState keyboard{}; if (dbus->IsOnline()) { - keyboard = dbus->keyboard; + keyboard = dbus_state.keyboard; } else if (vt13_c_mode) { - keyboard = refereerc->vt13_packet.keyboard; + keyboard = refereerc_state.keyboard; } // 以云台为基准的(整车的)运动速度,范围为[-1, 1] @@ -80,26 +87,21 @@ void chassisTask(void* arg) { // car_vy = 0; // car_vt = 0; // } else - if (dbus->IsOnline() && (abs(dbus->ch0) > dbus_rocker_deadband || abs(dbus->ch1) > dbus_rocker_deadband || - abs(dbus->ch4) > dbus_rocker_deadband)) { + if (dbus->IsOnline() && + (abs(dbus_state.channels[0]) > dbus_rocker_deadband || abs(dbus_state.channels[1]) > dbus_rocker_deadband || + abs(dbus_state.channels[4]) > dbus_rocker_deadband)) { // 优先使用遥控器 const float speed_scale = 0.5; - car_vx = (float)dbus->ch0 / dbus->ROCKER_MAX * speed_scale; - car_vy = (float)dbus->ch1 / dbus->ROCKER_MAX * speed_scale; - car_vt = (float)dbus->ch4 / dbus->ROCKER_MAX * speed_scale; - } else if (vt13_c_mode && (abs((int)refereerc->vt13_packet.remote.ch0 - remote::vt13_remote_t::ROCKER_MID) > - vt13_rocker_deadband || - abs((int)refereerc->vt13_packet.remote.ch1 - remote::vt13_remote_t::ROCKER_MID) > - vt13_rocker_deadband || - abs((int)refereerc->vt13_packet.remote.ch4 - remote::vt13_remote_t::ROCKER_MID) > - vt13_rocker_deadband)) { + car_vx = (float)dbus_state.channels[0] / 660.0f * speed_scale; + car_vy = (float)dbus_state.channels[1] / 660.0f * speed_scale; + car_vt = (float)dbus_state.channels[4] / 660.0f * speed_scale; + } else if (vt13_c_mode && (abs((int)refereerc_state.channels[0]) > vt13_rocker_deadband || + abs((int)refereerc_state.channels[1]) > vt13_rocker_deadband || + abs((int)refereerc_state.channels[4]) > vt13_rocker_deadband)) { const float speed_scale = 0.5; - car_vx = (float)((int)refereerc->vt13_packet.remote.ch0 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE * speed_scale; - car_vy = (float)((int)refereerc->vt13_packet.remote.ch1 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE * speed_scale; - car_vt = (float)((int)refereerc->vt13_packet.remote.ch4 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE * speed_scale; + car_vx = (float)((int)refereerc_state.channels[0]) / 660.0f * speed_scale; + car_vy = (float)((int)refereerc_state.channels[1]) / 660.0f * speed_scale; + car_vt = (float)((int)refereerc_state.channels[4]) / 660.0f * speed_scale; } else { // 使用键盘 const float keyboard_speed = keyboard.bit.SHIFT ? 1 : 0.5; diff --git a/programs/Ares/gimbal/src/gimbal_task.cpp b/programs/Ares/gimbal/src/gimbal_task.cpp index 522e5810..8c8b8413 100644 --- a/programs/Ares/gimbal/src/gimbal_task.cpp +++ b/programs/Ares/gimbal/src/gimbal_task.cpp @@ -18,7 +18,7 @@ #include "gimbal_task.h" #include "chassis_task.h" -#include "dji_remote.h" +#include "dbus.h" // #include "minipc_task.h" osThreadId_t gimbalTaskHandle; @@ -77,6 +77,13 @@ void gimbalTask(void* arg) { // float pitch_target, yaw_target; while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + // 如果遥控器处于关闭状态,关闭两个电机 check_kill(); @@ -85,7 +92,7 @@ void gimbalTask(void* arg) { yaw_curr = imu->INS_angle[0]; // pitch_curr = witimu->INS_angle[0]; // yaw_curr = wrap(witimu->INS_angle[2]-yaw_offset, -PI, PI); - // if (dbus->swr == remote::UP) { + // if (dbus_state.right_switch == controller::ThreePositionSwitch::Up) { // gimbal->TargetAbs(0, 0); // gimbal->Update(); // pitch_target = pitch_curr; @@ -99,27 +106,24 @@ void gimbalTask(void* arg) { const float remote_ratio = 0.005; const bool vt13_c_mode = (refereerc != nullptr) && refereerc->IsOnline() && - (refereerc->vt13_packet.remote.mode_sw == remote::vt13_remote_t::MODE_C); + (refereerc_state.mode == controller::RefereeRcMode::C); if (dbus->IsOnline()) { - if (dbus->mouse.x != 0 || dbus->mouse.y != 0) { - pitch_ratio = (float)dbus->mouse.y / mouse_xy_max * mouse_ratio; - yaw_ratio = (float)dbus->mouse.x / mouse_xy_max * mouse_ratio; + if (dbus_state.mouse.x != 0 || dbus_state.mouse.y != 0) { + pitch_ratio = (float)dbus_state.mouse.y / 32767.0 * mouse_ratio; + yaw_ratio = (float)dbus_state.mouse.x / 32767.0 * mouse_ratio; } else { - pitch_ratio = (float)dbus->ch3 / dbus->ROCKER_MAX * remote_ratio; - yaw_ratio = (float)dbus->ch2 / dbus->ROCKER_MAX * remote_ratio; + pitch_ratio = (float)dbus_state.channels[3] / 660.0f * remote_ratio; + yaw_ratio = (float)dbus_state.channels[2] / 660.0f * remote_ratio; } } else if (vt13_c_mode) { // DBUS离线时使用VT13:优先摇杆,否则鼠标 - if (refereerc->vt13_packet.remote.ch3 != remote::vt13_remote_t::ROCKER_MID || - refereerc->vt13_packet.remote.ch2 != remote::vt13_remote_t::ROCKER_MID) { - pitch_ratio = (float)(refereerc->vt13_packet.remote.ch2 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE / 18000.0 * 660.0 / 7.0; - yaw_ratio = (float)(refereerc->vt13_packet.remote.ch3 - remote::vt13_remote_t::ROCKER_MID) / - remote::vt13_remote_t::ROCKER_RANGE / 18000.0 * 660.0 / 7.0; + if (refereerc_state.channels[3] != 0 || refereerc_state.channels[2] != 0) { + pitch_ratio = (float)(refereerc_state.channels[2]) / 660.0f / 18000.0 * 660.0 / 7.0; + yaw_ratio = (float)(refereerc_state.channels[3]) / 660.0f / 18000.0 * 660.0 / 7.0; } else { - pitch_ratio = -refereerc->vt13_packet.mouse.y / 32767.0 * 7.5 / 7.0; - yaw_ratio = refereerc->vt13_packet.mouse.x / 32767.0 * 7.5 / 7.0; + pitch_ratio = -refereerc_state.mouse.y / 32767.0 * 7.5 / 7.0; + yaw_ratio = refereerc_state.mouse.x / 32767.0 * 7.5 / 7.0; } } else { pitch_ratio = 0; diff --git a/programs/Ares/gimbal/src/main.cpp b/programs/Ares/gimbal/src/main.cpp index ea4f0205..8e67551f 100644 --- a/programs/Ares/gimbal/src/main.cpp +++ b/programs/Ares/gimbal/src/main.cpp @@ -76,6 +76,11 @@ void RM_RTOS_Default_Task(const void* arg) { // } char s[50]; while (true) { + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + set_cursor(0, 0); clear_screen(); switch (remote_mode) { @@ -143,7 +148,7 @@ void RM_RTOS_Default_Task(const void* arg) { // } print("[UI] "); - if (refereerc->vt13_packet.keyboard.bit.V) { + if (refereerc_state.keyboard.bit.V) { print("UI refresh success"); } print("\n"); @@ -164,20 +169,24 @@ void RM_RTOS_Default_Task(const void* arg) { print( "VT13 [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [CH4: %-4d] [Mode: %d] [SWL: %d] " "[SWR: %d] [Trig: %d]\r\n", - refereerc->vt13_packet.remote.ch0, - refereerc->vt13_packet.remote.ch1, - refereerc->vt13_packet.remote.ch2, - refereerc->vt13_packet.remote.ch3, - refereerc->vt13_packet.remote.ch4, - refereerc->vt13_packet.remote.mode_sw, - refereerc->vt13_packet.remote.swl, - refereerc->vt13_packet.remote.swr, - refereerc->vt13_packet.remote.trigger + refereerc_state.channels[0], + refereerc_state.channels[1], + refereerc_state.channels[2], + refereerc_state.channels[3], + refereerc_state.channels[4], + static_cast(refereerc_state.mode), + refereerc_state.left_button, + refereerc_state.right_button, + refereerc_state.trigger ); print("\r\n"); print("[Referee %s] ", referee->IsOnline() ? "\033[32mOnline\033[0m" : "\033[31mOffline\033[0m"); print("\r\n"); - print("[Referee RC %s] ", refereerc->IsOnline() ? "\033[32mOnline\033[0m" : "\033[31mOffline\033[0m"); + print( + "[Referee RC %s] ", + (refereerc != nullptr && refereerc->IsOnline()) ? "\033[32mOnline\033[0m" : + "\033[31mOffline\033[0m" + ); print("\r\n"); // Gimbal info diff --git a/programs/Ares/gimbal/src/referee_task.cpp b/programs/Ares/gimbal/src/referee_task.cpp index 8f947c39..a44a83e7 100644 --- a/programs/Ares/gimbal/src/referee_task.cpp +++ b/programs/Ares/gimbal/src/referee_task.cpp @@ -21,9 +21,8 @@ #include "referee_task.h" bsp::UART* referee_uart = nullptr; -bsp::UART* refereerc_uart = nullptr; communication::Referee* referee = nullptr; -communication::Referee* refereerc = nullptr; +controller::RefereeRC* refereerc = nullptr; void init_referee() { referee_uart = new bsp::UART(&huart6); @@ -31,9 +30,5 @@ void init_referee() { referee_uart->SetupTx(300); referee = new communication::Referee(referee_uart); - refereerc_uart = new bsp::UART(&huart1); - refereerc_uart->SetBaudrate(921600); - refereerc_uart->SetupRx(300); - refereerc_uart->SetupTx(300, false); - refereerc = new communication::Referee(refereerc_uart); + refereerc = new controller::RefereeRC(&huart1); } diff --git a/programs/Ares/gimbal/src/remote_task.cpp b/programs/Ares/gimbal/src/remote_task.cpp index 710534a6..d4ffeb23 100644 --- a/programs/Ares/gimbal/src/remote_task.cpp +++ b/programs/Ares/gimbal/src/remote_task.cpp @@ -24,7 +24,7 @@ #include "imu_task.h" -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; RemoteMode remote_mode = REMOTE_MODE_FOLLOW; RemoteMode last_remote_mode = REMOTE_MODE_FOLLOW; RemoteMode available_remote_mode[] = {REMOTE_MODE_FOLLOW, REMOTE_MODE_SPIN, REMOTE_MODE_ADVANCED}; @@ -41,13 +41,15 @@ bool turbo_shoot = false; // dbus void init_dbus() { - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); } osThreadId_t remoteTaskHandle; // main loop void remoteTask(void* arg) { + using enum controller::ThreePositionSwitch; + // 接口转换 UNUSED(arg); osDelay(1000); @@ -60,20 +62,16 @@ void remoteTask(void* arg) { bool shoot_stop_switch = false; // uint32_t shoot_burst_timestamp = 0; - remote::switch_t last_state_r = remote::MID; - remote::switch_t last_state_l = remote::MID; - remote::keyboard_t last_keyboard; - remote::mouse_t last_mouse; - remote::switch_t state_r = remote::MID; - remote::switch_t state_l = remote::MID; - remote::keyboard_t keyboard; - remote::mouse_t mouse; + controller::ThreePositionSwitch last_state_r = Mid; + controller::ThreePositionSwitch last_state_l = Mid; + controller::KeyboardState last_keyboard{}; + controller::MouseState last_mouse{}; + controller::ThreePositionSwitch state_r = Mid; + controller::ThreePositionSwitch state_l = Mid; + controller::KeyboardState keyboard{}; + controller::MouseState mouse{}; // 键鼠状态清零 - memset(&keyboard, 0, sizeof(keyboard)); - memset(&mouse, 0, sizeof(mouse)); - memset(&last_keyboard, 0, sizeof(last_keyboard)); - memset(&last_mouse, 0, sizeof(last_mouse)); // bool is_dbus_offline; @@ -93,11 +91,18 @@ void remoteTask(void* arg) { BoolEdgeDetector* vt13_trigger_edge = new BoolEdgeDetector(false); while (1) { - const bool vt13_c_mode = - refereerc->IsOnline() && (refereerc->vt13_packet.remote.mode_sw == remote::vt13_remote_t::MODE_C); + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + + const bool vt13_c_mode = (refereerc != nullptr && refereerc->IsOnline()) && + (refereerc_state.mode == controller::RefereeRcMode::C); // Offline Detection && Security Check - is_dbus_offline = (!dbus->IsOnline()) || dbus->swr == remote::DOWN; + is_dbus_offline = (!dbus->IsOnline()) || dbus_state.right_switch == Down; // VT13必须在线且处于C模式才算可控 is_vt13_offline = !vt13_c_mode; #ifdef HAS_REFEREE @@ -137,30 +142,30 @@ void remoteTask(void* arg) { last_state_l = state_l; last_keyboard = keyboard; last_mouse = mouse; - state_r = remote::MID; - state_l = remote::MID; - memset(&keyboard, 0, sizeof(keyboard)); - memset(&mouse, 0, sizeof(mouse)); + state_r = Mid; + state_l = Mid; + keyboard = {}; + mouse = {}; // Update State if (dbus->IsOnline()) { // DBUS - state_r = dbus->swr; - state_l = dbus->swl; - keyboard = dbus->keyboard; - mouse = dbus->mouse; + state_r = dbus_state.right_switch; + state_l = dbus_state.left_switch; + keyboard = dbus_state.keyboard; + mouse = dbus_state.mouse; } else if (vt13_c_mode) { // referee control use keyboard & mouse - state_r = remote::MID; - state_l = remote::MID; - keyboard = refereerc->vt13_packet.keyboard; - mouse = (remote::mouse_t)refereerc->vt13_packet.mouse; + state_r = Mid; + state_l = Mid; + keyboard = refereerc_state.keyboard; + mouse = refereerc_state.mouse; } // Update Timestamp z_edge->input(keyboard.bit.Z); shift_edge->input(keyboard.bit.SHIFT); - mouse_left_edge->input(mouse.l); - mouse_right_edge->input(mouse.r); + mouse_left_edge->input(mouse.left); + mouse_right_edge->input(mouse.right); shoot_burst_edge->input(keyboard.bit.F); @@ -169,25 +174,25 @@ void remoteTask(void* arg) { } // VT13 边沿检测(仅在VT13可控时有效,避免离线脏数据触发) - vt13_pause_edge->input(vt13_c_mode && refereerc->vt13_packet.remote.pause); - vt13_left_edge->input(vt13_c_mode && refereerc->vt13_packet.remote.swl); - vt13_trigger_edge->input(vt13_c_mode && refereerc->vt13_packet.remote.trigger); + vt13_pause_edge->input(vt13_c_mode && refereerc_state.pause); + vt13_left_edge->input(vt13_c_mode && refereerc_state.left_button); + vt13_trigger_edge->input(vt13_c_mode && refereerc_state.trigger); // ========== 模式切换 ========== // DT7 右摇杆上拨 switch (state_r) { - case remote::UP: - if (last_state_r == remote::MID && dbus->IsOnline()) { + case Up: + if (last_state_r == Mid && dbus->IsOnline()) { mode_switch = true; } break; - case remote::MID: + case Mid: // 键盘 SHIFT 切换模式 if (shift_edge->posEdge()) { mode_switch = true; } break; - case remote::DOWN: + case Down: break; } // VT13 暂停键切换模式 @@ -205,31 +210,31 @@ void remoteTask(void* arg) { // shoot mode switch switch (state_l) { - case remote::UP: - if (last_state_l == remote::MID && dbus->IsOnline()) { + case Up: + if (last_state_l == Mid && dbus->IsOnline()) { shoot_fric_switch = true; } break; - case remote::DOWN: - if (last_state_l == remote::MID && dbus->IsOnline()) { + case Down: + if (last_state_l == Mid && dbus->IsOnline()) { shoot_switch = true; // shoot_burst_timestamp = 0; } - // else if (last_state_l == remote::DOWN && selftest.dbus) { + // else if (last_state_l == Down && selftest.dbus) { // shoot_burst_timestamp++; // if (shoot_burst_timestamp > 500 * REMOTE_OS_DELAY) { // shoot_burst_switch = true; // } // } break; - case remote::MID: + case Mid: switch (last_state_l) { - case remote::DOWN: + case Down: shoot_stop_switch = true; break; - case remote::UP: + case Up: break; - case remote::MID: + case Mid: // 键盘 Z键 切换摩擦轮 if (z_edge->posEdge()) { shoot_fric_switch = true; @@ -281,12 +286,12 @@ void remoteTask(void* arg) { } if (shoot_flywheel_mode == SHOOT_FRIC_MODE_STOP && vt13_c_mode) { - if (refereerc->vt13_packet.remote.ch4 < 424) { + if (refereerc_state.channels[4] < -600) { shoot_load_mode = SHOOT_MODE_UNLOAD; - } else if (refereerc->vt13_packet.remote.ch4 > 1624) { + } else if (refereerc_state.channels[4] > 600) { shoot_load_mode = SHOOT_MODE_STOP; } else { - if (refereerc->vt13_packet.remote.ch4 > 800 && refereerc->vt13_packet.remote.ch4 < 1248) { + if (refereerc_state.channels[4] > -224 && refereerc_state.channels[4] < 224) { shoot_load_mode = SHOOT_MODE_STOP; } } diff --git a/programs/Ares/gimbal/src/remote_task_automata.cpp b/programs/Ares/gimbal/src/remote_task_automata.cpp index 088ba797..5a4df6dc 100644 --- a/programs/Ares/gimbal/src/remote_task_automata.cpp +++ b/programs/Ares/gimbal/src/remote_task_automata.cpp @@ -25,23 +25,28 @@ #include "AutomataSystem.h" #include "imu_task.h" -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; RemoteMode remote_mode = REMOTE_MODE_FOLLOW; ShootFricMode shoot_flywheel_mode = SHOOT_FRIC_MODE_STOP; ShootMode shoot_load_mode = SHOOT_MODE_STOP; bool turbo_shoot = false; void init_dbus() { - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); } osThreadId_t remoteTaskHandle; void remoteTask(void* arg) { + using enum controller::ThreePositionSwitch; + // 接口转换 UNUSED(arg); osDelay(1000); + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + // 遥控器是否在线 bool is_controller_online = false; // 裁判系统端机器人是否阵亡 @@ -49,21 +54,24 @@ void remoteTask(void* arg) { // 裁判系统端是否允许射击 bool is_referee_shoot_available = false; - remote::switch_t state_r = remote::MID; - remote::switch_t state_l = remote::MID; - remote::keyboard_t keyboard{}; - remote::mouse_t mouse{}; + controller::ThreePositionSwitch state_r = Mid; + controller::ThreePositionSwitch state_l = Mid; + controller::KeyboardState keyboard{}; + controller::MouseState mouse{}; BoolEdgeDetector turbo_edge{false}; // clang-format off // 使/失能(上/下电) auto tranlogic_active_condition = TRANLOGIC { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + const auto& referee_cmd_dead = COMPONENT(0); const auto& control_online = COMPONENT(1); // 遥控器在线 && 右摇杆不在最下档 && 裁判系统反馈 未阵亡 return control_online.get() - && (!dbus->IsOnline() || dbus->swr != remote::DOWN) + && (!dbus->IsOnline() || dbus_state.right_switch != Down) && !referee_cmd_dead.get(); }; auto activate_aut = control::AutomataBuilder() @@ -79,12 +87,12 @@ void remoteTask(void* arg) { const auto& swr = COMPONENT(0); const auto& mode_change_key = COMPONENT(1); const auto& vt13_change_button = COMPONENT(2); - return (swr.downEdge() && swr.get() == remote::UP) + return (swr.downEdge() && swr.get() == Up) || mode_change_key.upEdge() || vt13_change_button.upEdge(); }; auto remote_mode_aut = control::AutomataBuilder() - .item(dbus->swr) + .item(dbus_state.right_switch) .item(bool{}) // mode_change_key .item(bool{}) // vt13_change_button .transition(tranlogic_next_remote_mode_trigger) @@ -97,12 +105,12 @@ void remoteTask(void* arg) { const auto& swl = COMPONENT(0); const auto& fric_key = COMPONENT(1); const auto& vt13_fric_button = COMPONENT(2); - return (swl.downEdge() && swl.get() == remote::UP) + return (swl.downEdge() && swl.get() == Up) || fric_key.upEdge() || vt13_fric_button.upEdge(); }; auto fric_wheel_aut = control::AutomataBuilder() - .item(dbus->swl) + .item(dbus_state.left_switch) .item(bool{}) // friction_key .item(bool{}) // vt13_fric_button // 加速中 → 停 @@ -125,12 +133,12 @@ void remoteTask(void* arg) { const auto& referee_permit = COMPONENT(2); const auto& shoot_key = COMPONENT(3); const auto& vt13_shoot_button = COMPONENT(4); - return (swl.get() == remote::DOWN || shoot_key.get() || vt13_shoot_button.get()) && + return (swl.get() == Down || shoot_key.get() || vt13_shoot_button.get()) && fric_state.get() == SHOOT_FRIC_MODE_PREPARED && referee_permit.get(); }; auto shoot_aut = control::AutomataBuilder() - .item(dbus->swl) + .item(dbus_state.left_switch) .item(SHOOT_FRIC_MODE_STOP) .item(is_referee_shoot_available) .item(bool{}) // shoot_key @@ -142,10 +150,19 @@ void remoteTask(void* arg) { // clang-format on while (true) { - const bool is_dbus_offline = (!dbus->IsOnline()) || (dbus->swr == remote::DOWN); + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + + const bool is_dbus_offline = + (!dbus->IsOnline()) || (dbus_state.right_switch == Down); // VT13必须在线且处于C模式才算可控 const bool is_vt13_offline = - !(refereerc->IsOnline() && (refereerc->vt13_packet.remote.mode_sw == remote::vt13_remote_t::MODE_C)); + !((refereerc != nullptr && refereerc->IsOnline()) && + (refereerc_state.mode == controller::RefereeRcMode::C)); is_controller_online = !is_dbus_offline || !is_vt13_offline; #ifdef HAS_REFEREE @@ -172,22 +189,22 @@ void remoteTask(void* arg) { } // 每帧先清零,再按当前在线的控制源更新,避免残留上一帧键鼠输入 - state_r = remote::MID; - state_l = remote::MID; - memset(&keyboard, 0, sizeof(keyboard)); - memset(&mouse, 0, sizeof(mouse)); + state_r = Mid; + state_l = Mid; + keyboard = {}; + mouse = {}; - const bool vt13_c_mode = - refereerc->IsOnline() && (refereerc->vt13_packet.remote.mode_sw == remote::vt13_remote_t::MODE_C); + const bool vt13_c_mode = (refereerc != nullptr && refereerc->IsOnline()) && + (refereerc_state.mode == controller::RefereeRcMode::C); if (dbus->IsOnline()) { // DBUS - state_r = dbus->swr; - state_l = dbus->swl; - keyboard = dbus->keyboard; - mouse = dbus->mouse; + state_r = dbus_state.right_switch; + state_l = dbus_state.left_switch; + keyboard = dbus_state.keyboard; + mouse = dbus_state.mouse; } else if (vt13_c_mode) { - keyboard = refereerc->vt13_packet.keyboard; - mouse = (remote::mouse_t)refereerc->vt13_packet.mouse; + keyboard = refereerc_state.keyboard; + mouse = refereerc_state.mouse; } turbo_edge.input(keyboard.bit.F); @@ -200,14 +217,14 @@ void remoteTask(void* arg) { remote_mode_aut.input(std::make_tuple( state_r, static_cast(keyboard.bit.SHIFT), - vt13_c_mode && static_cast(refereerc->vt13_packet.remote.pause) + vt13_c_mode && static_cast(refereerc_state.pause) )); remote_mode = remote_mode_aut.state(); fric_wheel_aut.input(std::make_tuple( state_l, static_cast(keyboard.bit.Z), - vt13_c_mode && static_cast(refereerc->vt13_packet.remote.swl) + vt13_c_mode && static_cast(refereerc_state.left_button) )); shoot_flywheel_mode = fric_wheel_aut.state(); @@ -215,8 +232,8 @@ void remoteTask(void* arg) { state_l, shoot_flywheel_mode, shoot_permitted, - static_cast(mouse.l), - vt13_c_mode && static_cast(refereerc->vt13_packet.remote.trigger) + static_cast(mouse.left), + vt13_c_mode && static_cast(refereerc_state.trigger) )); shoot_load_mode = shoot_aut.state(); diff --git a/programs/Ares/gimbal/src/shoot_task.cpp b/programs/Ares/gimbal/src/shoot_task.cpp index 5e3f2624..f9f02062 100644 --- a/programs/Ares/gimbal/src/shoot_task.cpp +++ b/programs/Ares/gimbal/src/shoot_task.cpp @@ -60,8 +60,8 @@ void shootTask(void* arg) { while (!imu->DataReady() || !imu->CaliDone()) { osDelay(SHOOT_OS_DELAY); } - // int last_state = remote::MID; - // int last_state_2 = remote::MID; + // auto last_state = controller::ThreePositionSwitch::Mid; + // auto last_state_2 = controller::ThreePositionSwitch::Mid; // uint8_t shoot_state = 0; // int shoot_flywheel_offset = 0; // uint8_t shoot_state_2 = 0; diff --git a/programs/Ares/gimbal/src/ui_task.cpp b/programs/Ares/gimbal/src/ui_task.cpp index 9dc4051d..96423dd1 100644 --- a/programs/Ares/gimbal/src/ui_task.cpp +++ b/programs/Ares/gimbal/src/ui_task.cpp @@ -130,6 +130,13 @@ void uiTask(void* arg) { BoolEdgeDetector* shoot_jam_edge = new BoolEdgeDetector(false); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + controller::RefereeRcFrame refereerc_state{}; + if (refereerc != nullptr) { + refereerc->GetState(refereerc_state); + } + // Update chassis GUI // 通过两个云台电机的角度 relative_angle = yaw_motor->GetThetaDelta(gimbal_param->yaw_offset_); @@ -256,10 +263,10 @@ void uiTask(void* arg) { } // V key to refresh UI (via refereerc VT13 link) - if (refereerc->IsOnline()) { - v_edge->input(refereerc->vt13_packet.keyboard.bit.V); + if ((refereerc != nullptr && refereerc->IsOnline())) { + v_edge->input(refereerc_state.keyboard.bit.V); } else { - v_edge->input(dbus->keyboard.bit.V); + v_edge->input(dbus_state.keyboard.bit.V); } if (v_edge->posEdge()) { @@ -320,9 +327,9 @@ void uiTask(void* arg) { // C key to clear diagnostics messages if (dbus->IsOnline()) { - c_edge->input(dbus->keyboard.bit.C); + c_edge->input(dbus_state.keyboard.bit.C); } else { - c_edge->input(refereerc->vt13_packet.keyboard.bit.C); + c_edge->input(refereerc_state.keyboard.bit.C); } if (c_edge->posEdge()) { diagGUI->Clear(UI_Delay); From 9e20a0a67e8fce43c6bc3470a4b380625ace47a9 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:22 +0800 Subject: [PATCH 09/17] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20Automata?= =?UTF-8?q?=20=E9=81=A5=E6=8E=A7=E8=BE=93=E5=85=A5=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=E7=89=87=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\266\347\224\250\346\210\267\346\211\213\345\206\214.md" | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git "a/examples/Host/Automata/[Automata]\347\273\204\344\273\266\347\224\250\346\210\267\346\211\213\345\206\214.md" "b/examples/Host/Automata/[Automata]\347\273\204\344\273\266\347\224\250\346\210\267\346\211\213\345\206\214.md" index 4988feb7..0533e343 100644 --- "a/examples/Host/Automata/[Automata]\347\273\204\344\273\266\347\224\250\346\210\267\346\211\213\345\206\214.md" +++ "b/examples/Host/Automata/[Automata]\347\273\204\344\273\266\347\224\250\346\210\267\346\211\213\345\206\214.md" @@ -146,8 +146,10 @@ auto aut = control::AutomataBuilder() ```cpp // 射击(供弹轮) +controller::DbusFrame dbus_state{}; +dbus->GetState(dbus_state); auto shoot_builder_with_items = control::AutomataBuilder() - .item(dbus->swl) + .item(dbus_state.left_switch) .item(SHOOT_FRIC_MODE_STOP) .item(is_referee_shoot_available) .item(bool{}); // shoot_key @@ -157,7 +159,7 @@ auto tranlogic_shooting_condition = TRANLOGIC { const auto& fric_state = COMPONENT(1); const auto& referee_permit = COMPONENT(2); const auto& shoot_key = COMPONENT(3); - return (swl.get() == remote::DOWN || shoot_key.get()) && + return (swl.get() == controller::ThreePositionSwitch::Down || shoot_key.get()) && fric_state.get() == SHOOT_FRIC_MODE_PREPARED && referee_permit.get(); }; From 231eea88b039f6e1f61655bbd63047a4cfc8fb1d Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:22 +0800 Subject: [PATCH 10/17] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20F103=5FN?= =?UTF-8?q?ano=20=E7=A4=BA=E4=BE=8B=E8=87=B3=20controller=20=E9=81=A5?= =?UTF-8?q?=E6=8E=A7=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/F103_Nano_general/motor/m2305.cpp | 25 +++++++++++-------- .../F103_Nano_general/motor/servo_m2006.cpp | 25 +++++++++++-------- .../F103_Nano_general/motor/servo_m3508.cpp | 25 +++++++++++-------- 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/examples/F103_Nano_general/motor/m2305.cpp b/examples/F103_Nano_general/motor/m2305.cpp index 0d0bcec2..268303ab 100644 --- a/examples/F103_Nano_general/motor/m2305.cpp +++ b/examples/F103_Nano_general/motor/m2305.cpp @@ -22,7 +22,7 @@ #include "bsp_gpio.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #include "utils.h" @@ -38,10 +38,10 @@ driver::PWMMotorBase* motor1; driver::PWMMotorBase* motor2; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; void RM_RTOS_Init() { - dbus = new remote::DBUS(&huart2); + dbus = new controller::DBUS(&huart2); print_use_uart(&huart1); motor1 = new driver::PWMMotorBase(&htim1, LEFT_MOTOR_PWM_CHANNEL, TIM_CLOCK_FREQ, MOTOR_OUT_FREQ, SNAIL_IDLE_THROTTLE); @@ -54,20 +54,25 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); bsp::GPIO key(KEY_GPIO_GROUP, KEY_GPIO_PIN); RampSource ramp_1 = RampSource(0, 0, 450, 0.001); RampSource ramp_2 = RampSource(0, 0, 450, 0.001); int current = 0; int state = 0; - int8_t last_state = remote::MID; + auto last_state = Mid; while (true) { - if (dbus->swl == remote::UP) { - if (last_state == remote::MID) - last_state = remote::UP; - } else if (dbus->swl == remote::MID) { - if (last_state == remote::UP) { - last_state = remote::MID; + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.left_switch == Up) { + if (last_state == Mid) + last_state = Up; + } else if (dbus_state.left_switch == Mid) { + if (last_state == Up) { + last_state = Mid; if (state == 0) { state = 1; diff --git a/examples/F103_Nano_general/motor/servo_m2006.cpp b/examples/F103_Nano_general/motor/servo_m2006.cpp index ea632c09..0a40d9e6 100644 --- a/examples/F103_Nano_general/motor/servo_m2006.cpp +++ b/examples/F103_Nano_general/motor/servo_m2006.cpp @@ -23,20 +23,20 @@ #include "bsp_os.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" bsp::CAN* can2 = NULL; driver::DjiMotorBase* motor1 = NULL; driver::ServoMotor* load_servo = NULL; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; float load_step_angle = 2 * PI / 8; void RM_RTOS_Init() { bsp::SetHighresClockTimer(&htim1); HAL_Delay(200); print_use_uart(&huart1); - dbus = new remote::DBUS(&huart2); + dbus = new controller::DBUS(&huart2); can2 = new bsp::CAN(&hcan1, true); motor1 = new driver::Motor2006(can2, 0x201); driver::servo_t servo_data; @@ -56,27 +56,32 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); - int last_state = remote::MID; + auto last_state = Mid; while (true) { - if (last_state != dbus->swl && dbus->swl == remote::MID) { - if (last_state == remote::UP) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (last_state != dbus_state.left_switch && dbus_state.left_switch == Mid) { + if (last_state == Up) { load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); - } else if (last_state == remote::DOWN) { + } else if (last_state == Down) { load_servo->SetTarget(load_servo->GetTarget() - load_step_angle); } } else { - if (dbus->ch3 > 0) { + if (dbus_state.channels[3] > 0) { load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); - } else if (dbus->ch3 < 0) { + } else if (dbus_state.channels[3] < 0) { load_servo->SetTarget(load_servo->GetTarget() - load_step_angle); } } load_servo->CalcOutput(); - last_state = dbus->swl; + last_state = dbus_state.left_switch; osDelay(1); } } diff --git a/examples/F103_Nano_general/motor/servo_m3508.cpp b/examples/F103_Nano_general/motor/servo_m3508.cpp index 51dfcb21..ef7ac9f5 100644 --- a/examples/F103_Nano_general/motor/servo_m3508.cpp +++ b/examples/F103_Nano_general/motor/servo_m3508.cpp @@ -23,20 +23,20 @@ #include "bsp_os.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" bsp::CAN* can1 = NULL; driver::DjiMotorBase* motor1 = NULL; driver::ServoMotor* load_servo = NULL; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; float load_step_angle = 2 * PI / 8; void RM_RTOS_Init() { bsp::SetHighresClockTimer(&htim1); HAL_Delay(200); print_use_uart(&huart1); - dbus = new remote::DBUS(&huart2); + dbus = new controller::DBUS(&huart2); can1 = new bsp::CAN(&hcan1, true); motor1 = new driver::Motor2006(can1, 0x201); @@ -56,17 +56,22 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); - int last_state = remote::MID; + auto last_state = Mid; int state = 0; while (true) { - if (dbus->swl == remote::UP) { - if (last_state == remote::MID) - last_state = remote::UP; - } else if (dbus->swl == remote::MID) { - if (last_state == remote::UP) { - last_state = remote::MID; + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.left_switch == Up) { + if (last_state == Mid) + last_state = Up; + } else if (dbus_state.left_switch == Mid) { + if (last_state == Up) { + last_state = Mid; load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); if (state == 0) { state = 1; From bdca51792b5949524b5d253167bf57b89b5ea9a2 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:21 +0800 Subject: [PATCH 11/17] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20DM=5FMC0?= =?UTF-8?q?2=20=E7=A4=BA=E4=BE=8B=E8=87=B3=20controller=20=E9=81=A5?= =?UTF-8?q?=E6=8E=A7=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/DM_MC02_general/CMakeLists.txt | 1 - examples/DM_MC02_general/can_bridge/host.cpp | 17 ++-- examples/DM_MC02_general/dbus/CMakeLists.txt | 6 -- examples/DM_MC02_general/dbus/main.cpp | 91 ------------------- examples/DM_MC02_general/motor/m2305.cpp | 25 +++-- .../DM_MC02_general/motor/servo_m2006.cpp | 25 +++-- .../DM_MC02_general/motor/servo_m3508.cpp | 25 +++-- 7 files changed, 55 insertions(+), 135 deletions(-) delete mode 100644 examples/DM_MC02_general/dbus/CMakeLists.txt delete mode 100644 examples/DM_MC02_general/dbus/main.cpp diff --git a/examples/DM_MC02_general/CMakeLists.txt b/examples/DM_MC02_general/CMakeLists.txt index 15988480..168051e1 100644 --- a/examples/DM_MC02_general/CMakeLists.txt +++ b/examples/DM_MC02_general/CMakeLists.txt @@ -3,7 +3,6 @@ set(BOARD_NAME ${CURRENT_DIR_NAME}) add_subdirectory(BMI088) add_subdirectory(buzzer) add_subdirectory(can_bridge) -add_subdirectory(dbus) add_subdirectory(led) add_subdirectory(motor) add_subdirectory(uart) diff --git a/examples/DM_MC02_general/can_bridge/host.cpp b/examples/DM_MC02_general/can_bridge/host.cpp index c5978933..d8b72f07 100644 --- a/examples/DM_MC02_general/can_bridge/host.cpp +++ b/examples/DM_MC02_general/can_bridge/host.cpp @@ -24,13 +24,13 @@ #include "bsp_uart.h" #include "can_bridge.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" static bsp::CAN* can1 = nullptr; static communication::CanBridge* can_bridge = nullptr; -static remote::DBUS* dbus = nullptr; +static controller::DBUS* dbus = nullptr; void RM_RTOS_Init(void) { print_use_usb(); @@ -38,18 +38,21 @@ void RM_RTOS_Init(void) { can1 = new bsp::CAN(&hfdcan1, true, 8); can_bridge = new communication::CanBridge(can1, 0x02); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); } void RM_RTOS_Default_Task(const void* argument) { UNUSED(argument); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + communication::can_bridge_data_t data; - data.data_four_int16.data[0] = dbus->ch0; - data.data_four_int16.data[1] = dbus->ch1; - data.data_four_int16.data[2] = dbus->ch2; - data.data_four_int16.data[3] = dbus->ch3; + data.data_four_int16.data[0] = dbus_state.channels[0]; + data.data_four_int16.data[1] = dbus_state.channels[1]; + data.data_four_int16.data[2] = dbus_state.channels[2]; + data.data_four_int16.data[3] = dbus_state.channels[3]; communication::can_bridge_ext_id_t ext_id; ext_id.data.rx_id = 0x01; ext_id.data.type = communication::CAN_BRIDGE_TYPE_FOUR_INT16; diff --git a/examples/DM_MC02_general/dbus/CMakeLists.txt b/examples/DM_MC02_general/dbus/CMakeLists.txt deleted file mode 100644 index 45816a8d..00000000 --- a/examples/DM_MC02_general/dbus/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -project(example_dbus_${BOARD_NAME} ASM C CXX) - -uicrm_add_arm_executable(${PROJECT_NAME} - TARGET ${BOARD_NAME} - SOURCES main.cpp) - diff --git a/examples/DM_MC02_general/dbus/main.cpp b/examples/DM_MC02_general/dbus/main.cpp deleted file mode 100644 index 25af5d30..00000000 --- a/examples/DM_MC02_general/dbus/main.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "main.h" - -#include "bsp_print.h" -#include "cmsis_os.h" -#include "dji_dbus.h" - -static remote::DBUS* dbus; - -void RM_RTOS_Init(void) { - print_use_uart(&huart1); - dbus = new remote::DBUS(&huart5); -} - -void RM_RTOS_Default_Task(const void* arguments) { - UNUSED(arguments); - - // NOTE(alvin): print is split because of stack usage is almost reaching - // limits - while (true) { - set_cursor(0, 0); - clear_screen(); - print( - "CH0: %-4d CH1: %-4d CH2: %-4d CH3: %-4d \r\nSWL: %d SWR: %d " - "TWL: %d " - "@ %d " - "ms\r\n", - dbus->ch0, - dbus->ch1, - dbus->ch2, - dbus->ch3, - dbus->swl, - dbus->swr, - dbus->ch4, - dbus->GetLastUptime() - ); - print( - "W: %d A: %d S: %d D: %d\r\n", - dbus->keyboard.bit.W, - dbus->keyboard.bit.A, - dbus->keyboard.bit.S, - dbus->keyboard.bit.D - ); - print( - "Q: %d E: %d R: %d F: %d G: %d\r\n", - dbus->keyboard.bit.Q, - dbus->keyboard.bit.E, - dbus->keyboard.bit.R, - dbus->keyboard.bit.F, - dbus->keyboard.bit.G - ); - print( - "Z: %d X: %d C: %d V: %d B: %d\r\n", - dbus->keyboard.bit.Z, - dbus->keyboard.bit.X, - dbus->keyboard.bit.C, - dbus->keyboard.bit.V, - dbus->keyboard.bit.B - ); - print("SHIFT: %d CTRL: %d\r\n", dbus->keyboard.bit.SHIFT, dbus->keyboard.bit.CTRL); - print( - "Mouse: x: %d y: %d z: %d l: %d r: %d\r\n", - dbus->mouse.x, - dbus->mouse.y, - dbus->mouse.z, - dbus->mouse.l, - dbus->mouse.r - ); - - osDelay(50); - } -} diff --git a/examples/DM_MC02_general/motor/m2305.cpp b/examples/DM_MC02_general/motor/m2305.cpp index 415b235e..99446d1c 100644 --- a/examples/DM_MC02_general/motor/m2305.cpp +++ b/examples/DM_MC02_general/motor/m2305.cpp @@ -22,7 +22,7 @@ #include "bsp_gpio.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #include "utils.h" @@ -38,10 +38,10 @@ driver::PWMMotorBase* motor1; driver::PWMMotorBase* motor2; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; void RM_RTOS_Init() { - dbus = new remote::DBUS(&huart5); + dbus = new controller::DBUS(&huart5); print_use_uart(&huart1); motor1 = new driver::PWMMotorBase(&htim1, LEFT_MOTOR_PWM_CHANNEL, TIM_CLOCK_FREQ, MOTOR_OUT_FREQ, SNAIL_IDLE_THROTTLE); @@ -54,20 +54,25 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); bsp::GPIO key(KEY_GPIO_GROUP, KEY_GPIO_PIN); RampSource ramp_1 = RampSource(0, 0, 450, 0.001); RampSource ramp_2 = RampSource(0, 0, 450, 0.001); int current = 0; int state = 0; - int8_t last_state = remote::MID; + auto last_state = Mid; while (true) { - if (dbus->swl == remote::UP) { - if (last_state == remote::MID) - last_state = remote::UP; - } else if (dbus->swl == remote::MID) { - if (last_state == remote::UP) { - last_state = remote::MID; + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.left_switch == Up) { + if (last_state == Mid) + last_state = Up; + } else if (dbus_state.left_switch == Mid) { + if (last_state == Up) { + last_state = Mid; if (state == 0) { state = 1; diff --git a/examples/DM_MC02_general/motor/servo_m2006.cpp b/examples/DM_MC02_general/motor/servo_m2006.cpp index d1471ceb..eaba062b 100644 --- a/examples/DM_MC02_general/motor/servo_m2006.cpp +++ b/examples/DM_MC02_general/motor/servo_m2006.cpp @@ -23,20 +23,20 @@ #include "bsp_os.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" bsp::CAN* can2 = NULL; driver::DjiMotorBase* motor1 = NULL; driver::ServoMotor* load_servo = NULL; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; float load_step_angle = 2 * PI / 8; void RM_RTOS_Init() { bsp::SetHighresClockTimer(&htim24); HAL_Delay(200); print_use_uart(&huart1); - dbus = new remote::DBUS(&huart5); + dbus = new controller::DBUS(&huart5); can2 = new bsp::CAN(&hfdcan2, false); motor1 = new driver::Motor2006(can2, 0x207); driver::servo_t servo_data; @@ -56,17 +56,22 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); - int last_state = remote::MID; + auto last_state = Mid; int state = 0; while (true) { - if (dbus->swl == remote::UP) { - if (last_state == remote::MID) - last_state = remote::UP; - } else if (dbus->swl == remote::MID) { - if (last_state == remote::UP) { - last_state = remote::MID; + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.left_switch == Up) { + if (last_state == Mid) + last_state = Up; + } else if (dbus_state.left_switch == Mid) { + if (last_state == Up) { + last_state = Mid; load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); if (state == 0) { state = 1; diff --git a/examples/DM_MC02_general/motor/servo_m3508.cpp b/examples/DM_MC02_general/motor/servo_m3508.cpp index 41d2b98c..10057095 100644 --- a/examples/DM_MC02_general/motor/servo_m3508.cpp +++ b/examples/DM_MC02_general/motor/servo_m3508.cpp @@ -23,20 +23,20 @@ #include "bsp_os.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" bsp::CAN* can1 = NULL; driver::DjiMotorBase* motor1 = NULL; driver::ServoMotor* load_servo = NULL; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; float load_step_angle = 2 * PI / 8; void RM_RTOS_Init() { bsp::SetHighresClockTimer(&htim24); HAL_Delay(200); print_use_uart(&huart1); - dbus = new remote::DBUS(&huart5); + dbus = new controller::DBUS(&huart5); can1 = new bsp::CAN(&hfdcan1, true); motor1 = new driver::Motor2006(can1, 0x201); @@ -56,17 +56,22 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); - int last_state = remote::MID; + auto last_state = Mid; int state = 0; while (true) { - if (dbus->swl == remote::UP) { - if (last_state == remote::MID) - last_state = remote::UP; - } else if (dbus->swl == remote::MID) { - if (last_state == remote::UP) { - last_state = remote::MID; + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.left_switch == Up) { + if (last_state == Mid) + last_state = Up; + } else if (dbus_state.left_switch == Mid) { + if (last_state == Up) { + last_state = Mid; load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); if (state == 0) { state = 1; From f867dd48fda989bb5084f607ff589ff4fb8066f9 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:21 +0800 Subject: [PATCH 12/17] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20DM=5FMC0?= =?UTF-8?q?1=20=E7=A4=BA=E4=BE=8B=E8=87=B3=20controller=20=E9=81=A5?= =?UTF-8?q?=E6=8E=A7=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/DM_MC01_general/CMakeLists.txt | 3 +- examples/DM_MC01_general/can_bridge/host.cpp | 17 +-- .../DM_MC01_general/chassis/CMakeLists.txt | 4 - .../chassis/mecanum_example.cpp | 17 ++- .../DM_MC01_general/chassis/omni_example.cpp | 17 ++- examples/DM_MC01_general/chassis/sbus.cpp | 112 ------------------ examples/DM_MC01_general/dbus/CMakeLists.txt | 6 - examples/DM_MC01_general/dbus/main.cpp | 93 --------------- examples/DM_MC01_general/motor/m2305.cpp | 25 ++-- .../DM_MC01_general/motor/servo_m2006.cpp | 25 ++-- .../DM_MC01_general/motor/servo_m3508.cpp | 25 ++-- 11 files changed, 80 insertions(+), 264 deletions(-) delete mode 100644 examples/DM_MC01_general/chassis/sbus.cpp delete mode 100644 examples/DM_MC01_general/dbus/CMakeLists.txt delete mode 100644 examples/DM_MC01_general/dbus/main.cpp diff --git a/examples/DM_MC01_general/CMakeLists.txt b/examples/DM_MC01_general/CMakeLists.txt index f3af1263..c0b990b3 100644 --- a/examples/DM_MC01_general/CMakeLists.txt +++ b/examples/DM_MC01_general/CMakeLists.txt @@ -4,7 +4,6 @@ add_subdirectory(BMI088) add_subdirectory(buzzer) add_subdirectory(can_bridge) add_subdirectory(chassis) -add_subdirectory(dbus) add_subdirectory(led) add_subdirectory(motor) -add_subdirectory(onboard_temp) \ No newline at end of file +add_subdirectory(onboard_temp) diff --git a/examples/DM_MC01_general/can_bridge/host.cpp b/examples/DM_MC01_general/can_bridge/host.cpp index 93278398..3ade6dc1 100644 --- a/examples/DM_MC01_general/can_bridge/host.cpp +++ b/examples/DM_MC01_general/can_bridge/host.cpp @@ -24,13 +24,13 @@ #include "bsp_uart.h" #include "can_bridge.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" static bsp::CAN* can1 = nullptr; static communication::CanBridge* can_bridge = nullptr; -static remote::DBUS* dbus = nullptr; +static controller::DBUS* dbus = nullptr; void RM_RTOS_Init(void) { print_use_usb(); @@ -38,18 +38,21 @@ void RM_RTOS_Init(void) { can1 = new bsp::CAN(&hcan1, true, 8); can_bridge = new communication::CanBridge(can1, 0x02); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); } void RM_RTOS_Default_Task(const void* argument) { UNUSED(argument); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + communication::can_bridge_data_t data; - data.data_four_int16.data[0] = dbus->ch0; - data.data_four_int16.data[1] = dbus->ch1; - data.data_four_int16.data[2] = dbus->ch2; - data.data_four_int16.data[3] = dbus->ch3; + data.data_four_int16.data[0] = dbus_state.channels[0]; + data.data_four_int16.data[1] = dbus_state.channels[1]; + data.data_four_int16.data[2] = dbus_state.channels[2]; + data.data_four_int16.data[3] = dbus_state.channels[3]; communication::can_bridge_ext_id_t ext_id; ext_id.data.rx_id = 0x01; ext_id.data.type = communication::CAN_BRIDGE_TYPE_FOUR_INT16; diff --git a/examples/DM_MC01_general/chassis/CMakeLists.txt b/examples/DM_MC01_general/chassis/CMakeLists.txt index e56b178e..ddfd01bd 100644 --- a/examples/DM_MC01_general/chassis/CMakeLists.txt +++ b/examples/DM_MC01_general/chassis/CMakeLists.txt @@ -8,10 +8,6 @@ uicrm_add_arm_executable(${PROJECT_NAME}_omni TARGET ${BOARD_NAME} SOURCES omni_example.cpp) -uicrm_add_arm_executable(${PROJECT_NAME}_sbus - TARGET ${BOARD_NAME} - SOURCES sbus.cpp) - uicrm_add_arm_executable(${PROJECT_NAME}_can_bridge TARGET ${BOARD_NAME} SOURCES can_bridge_chassis.cpp) diff --git a/examples/DM_MC01_general/chassis/mecanum_example.cpp b/examples/DM_MC01_general/chassis/mecanum_example.cpp index 3a36e112..710b4d28 100644 --- a/examples/DM_MC01_general/chassis/mecanum_example.cpp +++ b/examples/DM_MC01_general/chassis/mecanum_example.cpp @@ -23,7 +23,7 @@ #include "bsp_print.h" #include "chassis.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" bsp::CAN* can = nullptr; driver::DjiMotorBase* fl_motor = nullptr; @@ -32,7 +32,7 @@ driver::DjiMotorBase* bl_motor = nullptr; driver::DjiMotorBase* br_motor = nullptr; control::Chassis* chassis = nullptr; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; void RM_RTOS_Init() { HAL_Delay(200); @@ -86,21 +86,28 @@ void RM_RTOS_Init() { chassis_data.model = control::CHASSIS_MECANUM_WHEEL; chassis = new control::Chassis(chassis_data); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); HAL_Delay(300); } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); osDelay(500); // DBUS initialization needs time while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + const float ratio = 1.0f / 660.0f * 6 * PI; - chassis->SetSpeed(dbus->ch0 * ratio, dbus->ch1 * ratio, dbus->ch2 * ratio); + chassis + ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus->swl == remote::UP || dbus->swl == remote::DOWN) { + if (dbus_state.left_switch == Up || + dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/examples/DM_MC01_general/chassis/omni_example.cpp b/examples/DM_MC01_general/chassis/omni_example.cpp index ba9e9f80..51e86c74 100644 --- a/examples/DM_MC01_general/chassis/omni_example.cpp +++ b/examples/DM_MC01_general/chassis/omni_example.cpp @@ -24,7 +24,7 @@ #include "bsp_print.h" #include "chassis.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" bsp::CAN* can = nullptr; driver::DjiMotorBase* fl_motor = nullptr; @@ -33,7 +33,7 @@ driver::DjiMotorBase* bl_motor = nullptr; driver::DjiMotorBase* br_motor = nullptr; control::Chassis* chassis = nullptr; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; void RM_RTOS_Init() { bsp::SetHighresClockTimer(&htim2); // TIM2 is configured with a 1 MHz counter. @@ -88,21 +88,28 @@ void RM_RTOS_Init() { chassis_data.model = control::CHASSIS_OMNI_WHEEL; chassis = new control::Chassis(chassis_data); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); HAL_Delay(300); } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); osDelay(500); // DBUS initialization needs time while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + const float ratio = 1.0f / 660.0f * 6 * PI; - chassis->SetSpeed(dbus->ch0 * ratio, dbus->ch1 * ratio, dbus->ch2 * ratio); + chassis + ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus->swl == remote::UP || dbus->swl == remote::DOWN) { + if (dbus_state.left_switch == Up || + dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/examples/DM_MC01_general/chassis/sbus.cpp b/examples/DM_MC01_general/chassis/sbus.cpp deleted file mode 100644 index caace711..00000000 --- a/examples/DM_MC01_general/chassis/sbus.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "sbus.h" - -#include "bsp_print.h" -#include "chassis.h" -#include "cmsis_os.h" -#include "main.h" - -bsp::CAN* can = nullptr; -driver::DjiMotorBase* fl_motor = nullptr; -driver::DjiMotorBase* fr_motor = nullptr; -driver::DjiMotorBase* bl_motor = nullptr; -driver::DjiMotorBase* br_motor = nullptr; - -control::Chassis* chassis = nullptr; -remote::SBUS* sbus = nullptr; - -void RM_RTOS_Init() { - HAL_Delay(200); - print_use_uart(&huart5); - can = new bsp::CAN(&hcan1, true); - fl_motor = new driver::Motor3508(can, 0x202); - fr_motor = new driver::Motor3508(can, 0x201); - bl_motor = new driver::Motor3508(can, 0x203); - br_motor = new driver::Motor3508(can, 0x204); - - control::ConstrainedPID::PID_Init_t omega_pid_init = { - .kp = 2500, - .ki = 3, - .kd = 0, - .max_out = 30000, - .max_iout = 10000, - .deadband = 0, // 死区 - .A = 3 * PI, // 变速积分所能达到的最大值为A+B - .B = 2 * PI, // 启动变速积分的死区 - .output_filtering_coefficient = 0.1, // 输出滤波系数 - .derivative_filtering_coefficient = 0, // 微分滤波系数 - .mode = control::ConstrainedPID::Integral_Limit | // 积分限幅 - control::ConstrainedPID::OutputFilter | // 输出滤波 - control::ConstrainedPID::Trapezoid_Intergral | // 梯形积分 - control::ConstrainedPID::ChangingIntegralRate, // 变速积分 - }; - - fl_motor->ReInitPID(omega_pid_init, driver::DjiMotorBase::OMEGA); - fl_motor->SetMode(driver::DjiMotorBase::OMEGA); - fl_motor->SetTransmissionRatio(19); - - fr_motor->ReInitPID(omega_pid_init, driver::DjiMotorBase::OMEGA); - fr_motor->SetMode(driver::DjiMotorBase::OMEGA); - fr_motor->SetTransmissionRatio(19); - - bl_motor->ReInitPID(omega_pid_init, driver::DjiMotorBase::OMEGA); - bl_motor->SetMode(driver::DjiMotorBase::OMEGA); - bl_motor->SetTransmissionRatio(19); - - br_motor->ReInitPID(omega_pid_init, driver::DjiMotorBase::OMEGA); - br_motor->SetMode(driver::DjiMotorBase::OMEGA); - br_motor->SetTransmissionRatio(19); - - driver::DjiMotorBase* motors[control::FourWheel::motor_num]; - motors[control::FourWheel::front_left] = fl_motor; - motors[control::FourWheel::front_right] = fr_motor; - motors[control::FourWheel::back_left] = bl_motor; - motors[control::FourWheel::back_right] = br_motor; - - control::chassis_t chassis_data; - chassis_data.motors = motors; - chassis_data.model = control::CHASSIS_MECANUM_WHEEL; - chassis = new control::Chassis(chassis_data); - - sbus = new remote::SBUS(&huart3); - HAL_Delay(300); -} - -void RM_RTOS_Default_Task(const void* args) { - UNUSED(args); - - osDelay(500); // DBUS initialization needs time - - while (true) { - const float ratio = 1.0f / 660.0f * 6 * PI; - chassis->SetSpeed(-sbus->ch1 * ratio, sbus->ch2 * ratio, sbus->ch4 * ratio); - - // Kill switch - if (sbus->ch5 >= 550) { - RM_ASSERT_TRUE(false, "Operation killed"); - } - - chassis->SetPower(false, 30, 20, 60); - chassis->Update(); - osDelay(10); - } -} diff --git a/examples/DM_MC01_general/dbus/CMakeLists.txt b/examples/DM_MC01_general/dbus/CMakeLists.txt deleted file mode 100644 index 45816a8d..00000000 --- a/examples/DM_MC01_general/dbus/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -project(example_dbus_${BOARD_NAME} ASM C CXX) - -uicrm_add_arm_executable(${PROJECT_NAME} - TARGET ${BOARD_NAME} - SOURCES main.cpp) - diff --git a/examples/DM_MC01_general/dbus/main.cpp b/examples/DM_MC01_general/dbus/main.cpp deleted file mode 100644 index 5c98eab9..00000000 --- a/examples/DM_MC01_general/dbus/main.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "main.h" - -#include "bsp_print.h" -#include "cmsis_os.h" -#include "dji_dbus.h" - -static remote::DBUS* dbus; - -void RM_RTOS_Init(void) { - // print_use_uart(&huart5); - print_use_usb(); - dbus = new remote::DBUS(&huart3); -} - -void RM_RTOS_Default_Task(const void* arguments) { - UNUSED(arguments); - - // NOTE(alvin): print is split because of stack usage is almost reaching - // limits - while (true) { - set_cursor(0, 0); - clear_screen(); - print("Online: %s\r\n", (dbus->IsOnline() ? "true" : "false")); - print( - "CH0: %-4d CH1: %-4d CH2: %-4d CH3: %-4d \r\nSWL: %d SWR: %d " - "TWL: %d " - "@ %d " - "ms\r\n", - dbus->ch0, - dbus->ch1, - dbus->ch2, - dbus->ch3, - dbus->swl, - dbus->swr, - dbus->ch4, - dbus->GetLastUptime() - ); - print( - "W: %d A: %d S: %d D: %d\r\n", - dbus->keyboard.bit.W, - dbus->keyboard.bit.A, - dbus->keyboard.bit.S, - dbus->keyboard.bit.D - ); - print( - "Q: %d E: %d R: %d F: %d G: %d\r\n", - dbus->keyboard.bit.Q, - dbus->keyboard.bit.E, - dbus->keyboard.bit.R, - dbus->keyboard.bit.F, - dbus->keyboard.bit.G - ); - print( - "Z: %d X: %d C: %d V: %d B: %d\r\n", - dbus->keyboard.bit.Z, - dbus->keyboard.bit.X, - dbus->keyboard.bit.C, - dbus->keyboard.bit.V, - dbus->keyboard.bit.B - ); - print("SHIFT: %d CTRL: %d\r\n", dbus->keyboard.bit.SHIFT, dbus->keyboard.bit.CTRL); - print( - "Mouse: x: %d y: %d z: %d l: %d r: %d\r\n", - dbus->mouse.x, - dbus->mouse.y, - dbus->mouse.z, - dbus->mouse.l, - dbus->mouse.r - ); - - osDelay(50); - } -} diff --git a/examples/DM_MC01_general/motor/m2305.cpp b/examples/DM_MC01_general/motor/m2305.cpp index 226a724c..1337d7e8 100644 --- a/examples/DM_MC01_general/motor/m2305.cpp +++ b/examples/DM_MC01_general/motor/m2305.cpp @@ -22,7 +22,7 @@ #include "bsp_gpio.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #include "utils.h" @@ -38,10 +38,10 @@ driver::PWMMotorBase* motor1; driver::PWMMotorBase* motor2; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; void RM_RTOS_Init() { - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); print_use_uart(&huart4); motor1 = new driver::PWMMotorBase(&htim8, LEFT_MOTOR_PWM_CHANNEL, TIM_CLOCK_FREQ, MOTOR_OUT_FREQ, SNAIL_IDLE_THROTTLE); @@ -54,20 +54,25 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); bsp::GPIO key(KEY_GPIO_GROUP, KEY_GPIO_PIN); RampSource ramp_1 = RampSource(0, 0, 450, 0.001); RampSource ramp_2 = RampSource(0, 0, 450, 0.001); int current = 0; int state = 0; - int8_t last_state = remote::MID; + auto last_state = Mid; while (true) { - if (dbus->swl == remote::UP) { - if (last_state == remote::MID) - last_state = remote::UP; - } else if (dbus->swl == remote::MID) { - if (last_state == remote::UP) { - last_state = remote::MID; + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.left_switch == Up) { + if (last_state == Mid) + last_state = Up; + } else if (dbus_state.left_switch == Mid) { + if (last_state == Up) { + last_state = Mid; if (state == 0) { state = 1; diff --git a/examples/DM_MC01_general/motor/servo_m2006.cpp b/examples/DM_MC01_general/motor/servo_m2006.cpp index 750c237f..c45be460 100644 --- a/examples/DM_MC01_general/motor/servo_m2006.cpp +++ b/examples/DM_MC01_general/motor/servo_m2006.cpp @@ -23,20 +23,20 @@ #include "bsp_os.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" bsp::CAN* can2 = NULL; driver::DjiMotorBase* motor1 = NULL; driver::ServoMotor* load_servo = NULL; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; float load_step_angle = 2 * PI / 8; void RM_RTOS_Init() { bsp::SetHighresClockTimer(&htim5); HAL_Delay(200); print_use_uart(&huart4); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); can2 = new bsp::CAN(&hcan2, false); motor1 = new driver::Motor2006(can2, 0x207); driver::servo_t servo_data; @@ -56,17 +56,22 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); - int last_state = remote::MID; + auto last_state = Mid; int state = 0; while (true) { - if (dbus->swl == remote::UP) { - if (last_state == remote::MID) - last_state = remote::UP; - } else if (dbus->swl == remote::MID) { - if (last_state == remote::UP) { - last_state = remote::MID; + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.left_switch == Up) { + if (last_state == Mid) + last_state = Up; + } else if (dbus_state.left_switch == Mid) { + if (last_state == Up) { + last_state = Mid; load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); if (state == 0) { state = 1; diff --git a/examples/DM_MC01_general/motor/servo_m3508.cpp b/examples/DM_MC01_general/motor/servo_m3508.cpp index e251ffcf..f093b318 100644 --- a/examples/DM_MC01_general/motor/servo_m3508.cpp +++ b/examples/DM_MC01_general/motor/servo_m3508.cpp @@ -23,20 +23,20 @@ #include "bsp_os.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" bsp::CAN* can1 = NULL; driver::DjiMotorBase* motor1 = NULL; driver::ServoMotor* load_servo = NULL; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; float load_step_angle = 2 * PI / 8; void RM_RTOS_Init() { bsp::SetHighresClockTimer(&htim5); HAL_Delay(200); print_use_uart(&huart4); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); can1 = new bsp::CAN(&hcan1, true); motor1 = new driver::Motor2006(can1, 0x201); @@ -56,17 +56,22 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); - int last_state = remote::MID; + auto last_state = Mid; int state = 0; while (true) { - if (dbus->swl == remote::UP) { - if (last_state == remote::MID) - last_state = remote::UP; - } else if (dbus->swl == remote::MID) { - if (last_state == remote::UP) { - last_state = remote::MID; + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.left_switch == Up) { + if (last_state == Mid) + last_state = Up; + } else if (dbus_state.left_switch == Mid) { + if (last_state == Up) { + last_state = Mid; load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); if (state == 0) { state = 1; From fde715a98f4437ff19d7f614daa4c5c3c5ffc8d7 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:21 +0800 Subject: [PATCH 13/17] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20DJI=5FBo?= =?UTF-8?q?ard=5FTypeC=20=E7=A4=BA=E4=BE=8B=E8=87=B3=20controller=20?= =?UTF-8?q?=E9=81=A5=E6=8E=A7=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DJI_Board_TypeC_general/CMakeLists.txt | 4 +- .../can_bridge/host.cpp | 17 +- .../chassis/CMakeLists.txt | 6 +- .../chassis/mecanum_example.cpp | 17 +- .../chassis/omni_example.cpp | 35 +- .../chassis/power_data_collect.cpp | 11 +- .../chassis/power_limit_test.cpp | 17 +- .../DJI_Board_TypeC_general/chassis/sbus.cpp | 112 ------ .../controller/dt7.cpp | 22 +- .../controller/fs_i6x.cpp | 70 ++-- .../controller/vt13.cpp | 50 +-- .../dbus/CMakeLists.txt | 6 - .../DJI_Board_TypeC_general/dbus/main.cpp | 91 ----- .../gimbal/CMakeLists.txt | 4 - .../DJI_Board_TypeC_general/gimbal/typeC.cpp | 57 +++- .../gimbal/typeC_sbus.cpp | 321 ------------------ .../DJI_Board_TypeC_general/motor/m2305.cpp | 25 +- .../motor/servo_m2006.cpp | 25 +- .../motor/servo_m3508.cpp | 25 +- .../referee/CMakeLists.txt | 4 - .../DJI_Board_TypeC_general/referee/rc.cpp | 104 ------ .../sbus/CMakeLists.txt | 6 - .../DJI_Board_TypeC_general/sbus/main.cpp | 67 ---- 23 files changed, 202 insertions(+), 894 deletions(-) delete mode 100644 examples/DJI_Board_TypeC_general/chassis/sbus.cpp delete mode 100644 examples/DJI_Board_TypeC_general/dbus/CMakeLists.txt delete mode 100644 examples/DJI_Board_TypeC_general/dbus/main.cpp delete mode 100644 examples/DJI_Board_TypeC_general/gimbal/typeC_sbus.cpp delete mode 100644 examples/DJI_Board_TypeC_general/referee/rc.cpp delete mode 100644 examples/DJI_Board_TypeC_general/sbus/CMakeLists.txt delete mode 100644 examples/DJI_Board_TypeC_general/sbus/main.cpp diff --git a/examples/DJI_Board_TypeC_general/CMakeLists.txt b/examples/DJI_Board_TypeC_general/CMakeLists.txt index ff048f90..0425a0fb 100644 --- a/examples/DJI_Board_TypeC_general/CMakeLists.txt +++ b/examples/DJI_Board_TypeC_general/CMakeLists.txt @@ -6,7 +6,6 @@ add_subdirectory(can_bridge) add_subdirectory(chassis) add_subdirectory(cybergear) add_subdirectory(controller) -add_subdirectory(dbus) add_subdirectory(gimbal) add_subdirectory(imu) add_subdirectory(ist8310) @@ -16,8 +15,7 @@ add_subdirectory(motor) add_subdirectory(oled) add_subdirectory(onboard_temp) add_subdirectory(referee) -add_subdirectory(sbus) add_subdirectory(witimu) add_subdirectory(usb) add_subdirectory(supercap) -add_subdirectory(Automata) \ No newline at end of file +add_subdirectory(Automata) diff --git a/examples/DJI_Board_TypeC_general/can_bridge/host.cpp b/examples/DJI_Board_TypeC_general/can_bridge/host.cpp index 93278398..3ade6dc1 100644 --- a/examples/DJI_Board_TypeC_general/can_bridge/host.cpp +++ b/examples/DJI_Board_TypeC_general/can_bridge/host.cpp @@ -24,13 +24,13 @@ #include "bsp_uart.h" #include "can_bridge.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" static bsp::CAN* can1 = nullptr; static communication::CanBridge* can_bridge = nullptr; -static remote::DBUS* dbus = nullptr; +static controller::DBUS* dbus = nullptr; void RM_RTOS_Init(void) { print_use_usb(); @@ -38,18 +38,21 @@ void RM_RTOS_Init(void) { can1 = new bsp::CAN(&hcan1, true, 8); can_bridge = new communication::CanBridge(can1, 0x02); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); } void RM_RTOS_Default_Task(const void* argument) { UNUSED(argument); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + communication::can_bridge_data_t data; - data.data_four_int16.data[0] = dbus->ch0; - data.data_four_int16.data[1] = dbus->ch1; - data.data_four_int16.data[2] = dbus->ch2; - data.data_four_int16.data[3] = dbus->ch3; + data.data_four_int16.data[0] = dbus_state.channels[0]; + data.data_four_int16.data[1] = dbus_state.channels[1]; + data.data_four_int16.data[2] = dbus_state.channels[2]; + data.data_four_int16.data[3] = dbus_state.channels[3]; communication::can_bridge_ext_id_t ext_id; ext_id.data.rx_id = 0x01; ext_id.data.type = communication::CAN_BRIDGE_TYPE_FOUR_INT16; diff --git a/examples/DJI_Board_TypeC_general/chassis/CMakeLists.txt b/examples/DJI_Board_TypeC_general/chassis/CMakeLists.txt index 5fe43b9a..199d7983 100644 --- a/examples/DJI_Board_TypeC_general/chassis/CMakeLists.txt +++ b/examples/DJI_Board_TypeC_general/chassis/CMakeLists.txt @@ -8,10 +8,6 @@ uicrm_add_arm_executable(${PROJECT_NAME}_omni TARGET ${BOARD_NAME} SOURCES omni_example.cpp) -uicrm_add_arm_executable(${PROJECT_NAME}_sbus - TARGET ${BOARD_NAME} - SOURCES sbus.cpp) - uicrm_add_arm_executable(${PROJECT_NAME}_can_bridge TARGET ${BOARD_NAME} SOURCES can_bridge_chassis.cpp) @@ -24,4 +20,4 @@ uicrm_add_arm_executable(${PROJECT_NAME}_power_data_collect uicrm_add_arm_executable(${PROJECT_NAME}_power_limit_test TARGET ${BOARD_NAME} SOURCES power_limit_test.cpp -) \ No newline at end of file +) diff --git a/examples/DJI_Board_TypeC_general/chassis/mecanum_example.cpp b/examples/DJI_Board_TypeC_general/chassis/mecanum_example.cpp index fe64efc1..725b4ce8 100644 --- a/examples/DJI_Board_TypeC_general/chassis/mecanum_example.cpp +++ b/examples/DJI_Board_TypeC_general/chassis/mecanum_example.cpp @@ -23,7 +23,7 @@ #include "bsp_print.h" #include "chassis.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" bsp::CAN* can = nullptr; driver::DjiMotorBase* fl_motor = nullptr; @@ -32,7 +32,7 @@ driver::DjiMotorBase* bl_motor = nullptr; driver::DjiMotorBase* br_motor = nullptr; control::Chassis* chassis = nullptr; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; void RM_RTOS_Init() { HAL_Delay(200); @@ -86,21 +86,28 @@ void RM_RTOS_Init() { chassis_data.model = control::CHASSIS_MECANUM_WHEEL; chassis = new control::Chassis(chassis_data); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); HAL_Delay(300); } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); osDelay(500); // DBUS initialization needs time while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + const float ratio = 1.0f / 660.0f * 6 * PI; - chassis->SetSpeed(dbus->ch0 * ratio, dbus->ch1 * ratio, dbus->ch2 * ratio); + chassis + ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus->swl == remote::UP || dbus->swl == remote::DOWN) { + if (dbus_state.left_switch == Up || + dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/examples/DJI_Board_TypeC_general/chassis/omni_example.cpp b/examples/DJI_Board_TypeC_general/chassis/omni_example.cpp index 33d2b7fd..7661daf3 100644 --- a/examples/DJI_Board_TypeC_general/chassis/omni_example.cpp +++ b/examples/DJI_Board_TypeC_general/chassis/omni_example.cpp @@ -24,7 +24,7 @@ #include "bsp_print.h" #include "chassis.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" bsp::CAN* can = nullptr; driver::DjiMotorBase* fl_motor = nullptr; @@ -33,7 +33,7 @@ driver::DjiMotorBase* bl_motor = nullptr; driver::DjiMotorBase* br_motor = nullptr; control::Chassis* chassis = nullptr; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; void RM_RTOS_Init() { HAL_Delay(200); @@ -88,21 +88,28 @@ void RM_RTOS_Init() { chassis_data.model = control::CHASSIS_OMNI_WHEEL; chassis = new control::Chassis(chassis_data); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); HAL_Delay(300); } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); osDelay(500); // DBUS initialization needs time while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + const float ratio = 1.0f / 660.0f * 6 * PI; - chassis->SetSpeed(dbus->ch0 * ratio, dbus->ch1 * ratio, dbus->ch2 * ratio); + chassis + ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus->swl == remote::UP || dbus->swl == remote::DOWN) { + if (dbus_state.left_switch == Up || + dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); @@ -120,17 +127,17 @@ void RM_RTOS_Default_Task(const void* args) { // DBUS info print( - "DBUS [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [TWL: %d] [SWL: %d] [SWR: %d]" + "DBUS [CH0: %-4d] [CH1: %-4d] [CH2: %-4d] [CH3: %-4d] [TWL: %d] [SWL: %s] [SWR: %s]" "@ %d " "ms\r\n", - dbus->ch0, - dbus->ch1, - dbus->ch2, - dbus->ch3, - dbus->ch4, - dbus->swl, - dbus->swr, - dbus->GetLastUptime() + dbus_state.channels[0], + dbus_state.channels[1], + dbus_state.channels[2], + dbus_state.channels[3], + dbus_state.channels[4], + controller::SwitchName(dbus_state.left_switch), + controller::SwitchName(dbus_state.right_switch), + dbus->GetLastValidTimeMs() ); print("\r\n"); diff --git a/examples/DJI_Board_TypeC_general/chassis/power_data_collect.cpp b/examples/DJI_Board_TypeC_general/chassis/power_data_collect.cpp index 6bb18f3b..693e34d3 100644 --- a/examples/DJI_Board_TypeC_general/chassis/power_data_collect.cpp +++ b/examples/DJI_Board_TypeC_general/chassis/power_data_collect.cpp @@ -21,7 +21,7 @@ #include "bsp_print.h" #include "chassis.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #include "power_meter.h" @@ -32,7 +32,7 @@ driver::DjiMotorBase* bl_motor = nullptr; driver::DjiMotorBase* br_motor = nullptr; control::Chassis* chassis = nullptr; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; power_meter* power_meter_1 = nullptr; @@ -107,7 +107,7 @@ void RM_RTOS_Init() { chassis_data.model = control::CHASSIS_MECANUM_WHEEL; chassis = new control::Chassis(chassis_data); - dbus = new remote::DBUS(&BOARD_DBUS); + dbus = new controller::DBUS(&BOARD_DBUS); power_meter_1 = new power_meter(&BOARD_UART2, 1, callback); @@ -123,8 +123,11 @@ void RM_RTOS_Default_Task(const void* args) { osDelay(500); // DBUS initialization needs time while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + const float ratio = 1.0f / 660.0f * PI * 12; - float target = ratio * dbus->ch0; + float target = ratio * dbus_state.channels[0]; fr_motor->SetTarget(target, true); osDelay(10); } diff --git a/examples/DJI_Board_TypeC_general/chassis/power_limit_test.cpp b/examples/DJI_Board_TypeC_general/chassis/power_limit_test.cpp index e4e18b0f..bc2bb892 100644 --- a/examples/DJI_Board_TypeC_general/chassis/power_limit_test.cpp +++ b/examples/DJI_Board_TypeC_general/chassis/power_limit_test.cpp @@ -22,7 +22,7 @@ #include "bsp_print.h" #include "chassis.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #include "power_meter.h" @@ -33,7 +33,7 @@ driver::DjiMotorBase* bl_motor = nullptr; driver::DjiMotorBase* br_motor = nullptr; control::Chassis* chassis = nullptr; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; power_meter* power_meter_1 = nullptr; bsp::BatteryVol* battery_vol = nullptr; @@ -110,7 +110,7 @@ void RM_RTOS_Init() { chassis_data.power_limit_on = true; chassis = new control::Chassis(chassis_data); - dbus = new remote::DBUS(&BOARD_DBUS); + dbus = new controller::DBUS(&BOARD_DBUS); power_meter_1 = new power_meter(&BOARD_UART2, 1, callback); battery_vol = new bsp::BatteryVol(&hadc3, ADC_CHANNEL_8, 1, ADC_SAMPLETIME_3CYCLES); @@ -122,16 +122,23 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); osDelay(500); // DBUS initialization needs time while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + const float ratio = 1.0f / 660.0f * 6 * PI; - chassis->SetSpeed(dbus->ch0 * ratio, dbus->ch1 * ratio, dbus->ch2 * ratio); + chassis + ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus->swl == remote::UP || dbus->swl == remote::DOWN) { + if (dbus_state.left_switch == Up || + dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->UpdatePower(true, 60, battery_vol->GetBatteryVol(), 50); diff --git a/examples/DJI_Board_TypeC_general/chassis/sbus.cpp b/examples/DJI_Board_TypeC_general/chassis/sbus.cpp deleted file mode 100644 index 08ca40e0..00000000 --- a/examples/DJI_Board_TypeC_general/chassis/sbus.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "sbus.h" - -#include "bsp_print.h" -#include "chassis.h" -#include "cmsis_os.h" -#include "main.h" - -bsp::CAN* can = nullptr; -driver::DjiMotorBase* fl_motor = nullptr; -driver::DjiMotorBase* fr_motor = nullptr; -driver::DjiMotorBase* bl_motor = nullptr; -driver::DjiMotorBase* br_motor = nullptr; - -control::Chassis* chassis = nullptr; -remote::SBUS* sbus = nullptr; - -void RM_RTOS_Init() { - HAL_Delay(200); - print_use_uart(&huart1); - can = new bsp::CAN(&hcan1, true); - fl_motor = new driver::Motor3508(can, 0x202); - fr_motor = new driver::Motor3508(can, 0x201); - bl_motor = new driver::Motor3508(can, 0x203); - br_motor = new driver::Motor3508(can, 0x204); - - control::ConstrainedPID::PID_Init_t omega_pid_init = { - .kp = 2500, - .ki = 3, - .kd = 0, - .max_out = 30000, - .max_iout = 10000, - .deadband = 0, // 死区 - .A = 3 * PI, // 变速积分所能达到的最大值为A+B - .B = 2 * PI, // 启动变速积分的死区 - .output_filtering_coefficient = 0.1, // 输出滤波系数 - .derivative_filtering_coefficient = 0, // 微分滤波系数 - .mode = control::ConstrainedPID::Integral_Limit | // 积分限幅 - control::ConstrainedPID::OutputFilter | // 输出滤波 - control::ConstrainedPID::Trapezoid_Intergral | // 梯形积分 - control::ConstrainedPID::ChangingIntegralRate, // 变速积分 - }; - - fl_motor->ReInitPID(omega_pid_init, driver::DjiMotorBase::OMEGA); - fl_motor->SetMode(driver::DjiMotorBase::OMEGA); - fl_motor->SetTransmissionRatio(19); - - fr_motor->ReInitPID(omega_pid_init, driver::DjiMotorBase::OMEGA); - fr_motor->SetMode(driver::DjiMotorBase::OMEGA); - fr_motor->SetTransmissionRatio(19); - - bl_motor->ReInitPID(omega_pid_init, driver::DjiMotorBase::OMEGA); - bl_motor->SetMode(driver::DjiMotorBase::OMEGA); - bl_motor->SetTransmissionRatio(19); - - br_motor->ReInitPID(omega_pid_init, driver::DjiMotorBase::OMEGA); - br_motor->SetMode(driver::DjiMotorBase::OMEGA); - br_motor->SetTransmissionRatio(19); - - driver::DjiMotorBase* motors[control::FourWheel::motor_num]; - motors[control::FourWheel::front_left] = fl_motor; - motors[control::FourWheel::front_right] = fr_motor; - motors[control::FourWheel::back_left] = bl_motor; - motors[control::FourWheel::back_right] = br_motor; - - control::chassis_t chassis_data; - chassis_data.motors = motors; - chassis_data.model = control::CHASSIS_MECANUM_WHEEL; - chassis = new control::Chassis(chassis_data); - - sbus = new remote::SBUS(&huart3); - HAL_Delay(300); -} - -void RM_RTOS_Default_Task(const void* args) { - UNUSED(args); - - osDelay(500); // DBUS initialization needs time - - while (true) { - const float ratio = 1.0f / 660.0f * 6 * PI; - chassis->SetSpeed(-sbus->ch1 * ratio, sbus->ch2 * ratio, sbus->ch4 * ratio); - - // Kill switch - if (sbus->ch5 >= 550) { - RM_ASSERT_TRUE(false, "Operation killed"); - } - - chassis->SetPower(false, 30, 20, 60); - chassis->Update(); - osDelay(10); - } -} diff --git a/examples/DJI_Board_TypeC_general/controller/dt7.cpp b/examples/DJI_Board_TypeC_general/controller/dt7.cpp index 61ec1332..e619bc99 100644 --- a/examples/DJI_Board_TypeC_general/controller/dt7.cpp +++ b/examples/DJI_Board_TypeC_general/controller/dt7.cpp @@ -25,24 +25,23 @@ #include "dbus.h" namespace { - remote::Dbus* receiver = nullptr; + controller::DBUS* receiver = nullptr; } void RM_RTOS_Init(void) { print_use_uart(&huart1); - receiver = new remote::Dbus(&huart3); + receiver = new controller::DBUS(&huart3); } void RM_RTOS_Default_Task(const void* argument) { UNUSED(argument); while (true) { - remote::DbusFrame state; - bool online = receiver->IsOnline(); - bool has_state = receiver->GetState(state); - uint32_t sequence = receiver->GetSequence(); - uint32_t last_valid_ms = receiver->GetLastValidTimeMs(); - + controller::DbusFrame state; + const bool has_state = receiver->GetState(state); + const bool online = receiver->IsOnline(); + const uint32_t sequence = receiver->GetSequence(); + const uint32_t last_valid_ms = receiver->GetLastValidTimeMs(); set_cursor(0, 0); clear_screen(); @@ -54,8 +53,11 @@ void RM_RTOS_Default_Task(const void* argument) { print("Right X/Y: %d / %d\r\n", state.channels[0], state.channels[1]); print("Left X/Y: %d / %d\r\n", state.channels[2], state.channels[3]); print("Dial: %d\r\n", state.channels[4]); - print("Switch L/R: %u / %u\r\n", static_cast(state.left_switch), - static_cast(state.right_switch)); + print( + "Switch L/R: %s / %s\r\n", + controller::SwitchName(state.left_switch), + controller::SwitchName(state.right_switch) + ); print("Mouse X/Y: %d / %d\r\n", state.mouse.x, state.mouse.y); print("Mouse Z: %d\r\n", state.mouse.z); print("Mouse L/R: %d / %d\r\n", state.mouse.left, state.mouse.right); diff --git a/examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp b/examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp index 7f717fe5..dcf6d12a 100644 --- a/examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp +++ b/examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp @@ -24,50 +24,25 @@ #include "cmsis_os.h" #include "sbus.h" -namespace { - remote::I6x* receiver = nullptr; - - const char* PositionName(remote::TwoPositionSwitch position) { - return position == remote::TwoPositionSwitch::Up ? "UP" : "DOWN"; - } - - const char* PositionName(remote::ThreePositionSwitch position) { - switch (position) { - case remote::ThreePositionSwitch::Up: - return "UP"; - case remote::ThreePositionSwitch::Mid: - return "MID"; - case remote::ThreePositionSwitch::Down: - return "DOWN"; - } - return "UNKNOWN"; - } -} +static controller::I6x* receiver = nullptr; void RM_RTOS_Init(void) { print_use_uart(&huart1); - receiver = new remote::I6x(&huart3); + // I6x 继承 SBUS 的 UART 接收,无需另外创建 SBUS 或注册回调。 + receiver = new controller::I6x(&huart3); } void RM_RTOS_Default_Task(const void* argument) { UNUSED(argument); while (true) { - remote::I6xState state; - bool online; - bool has_state; - uint32_t sequence; - uint32_t last_valid_ms; + controller::I6xState state; + controller::SbusFrame raw; - // USART3 优先级为 4,FreeRTOS 临界区不能屏蔽它。 - // 保存并短暂关闭中断,拷贝后恢复原状态;打印和延时在保护区外。 - const uint32_t interrupt_mask = __get_PRIMASK(); - __disable_irq(); - online = receiver->IsOnline(); - has_state = receiver->GetState(state); - sequence = receiver->GetSequence(); - last_valid_ms = receiver->GetLastValidTimeMs(); - __set_PRIMASK(interrupt_mask); + const bool has_state = receiver->GetState(state) && receiver->GetRawState(raw); + const bool online = receiver->IsOnline(); + const uint32_t sequence = receiver->GetSequence(); + const uint32_t last_valid_ms = receiver->GetLastValidTimeMs(); set_cursor(0, 0); clear_screen(); @@ -75,24 +50,29 @@ void RM_RTOS_Default_Task(const void* argument) { print("Sequence: %lu\r\n", static_cast(sequence)); print("Last valid: %lu ms\r\n", static_cast(last_valid_ms)); if (has_state) { - print("Frame lost: %d Failsafe: %d Flags: 0x%02X\r\n", - state.frame_lost, state.failsafe, static_cast(state.flags)); + print( + "Frame lost: %d Failsafe: %d Flags: 0x%02X\r\n", + state.frame_lost, + state.failsafe, + static_cast(raw.flags) + ); // CH1/2:右 X/Y;CH3/4:左 Y/X;CH5/6:VrA/VrB;CH7~10:SwA~SwD。 // I6x 已统一映射到 ±660 并处理原始 ±10 死区;原始通道保留用于诊断。 print("Right X/Y: %d / %d\r\n", state.channels[0], state.channels[1]); print("Left X/Y: %d / %d\r\n", state.channels[3], state.channels[2]); print("VrA/VrB: %d / %d\r\n", state.channels[4], state.channels[5]); - print("SwA: %s SwB: %s SwC: %s SwD: %s\r\n", - PositionName(state.sw_a), PositionName(state.sw_b), PositionName(state.sw_c), - PositionName(state.sw_d)); - print("Switch codes A/B/C/D: %u / %u / %u / %u\r\n", - static_cast(state.sw_a), static_cast(state.sw_b), - static_cast(state.sw_c), static_cast(state.sw_d)); + print( + "Switch A/B/C/D: %s / %s / %s / %s\r\n", + controller::SwitchName(state.sw_a), + controller::SwitchName(state.sw_b), + controller::SwitchName(state.sw_c), + controller::SwitchName(state.sw_d) + ); print("Usable: %d\r\n", online && !state.failsafe && !state.frame_lost); - for (size_t i = 0; i < state.raw_channels.size(); ++i) { - print("Raw CH%u: %u\r\n", static_cast(i + 1), - static_cast(state.raw_channels[i])); + for (size_t i = 0; i < raw.channels.size(); ++i) { + print("Raw CH%u: %u\r\n", static_cast(i + 1), static_cast(raw.channels[i])); } + print("Digital CH17/18: %d / %d\r\n", raw.channel17, raw.channel18); // 离线仍可读到最后有效帧,在线也可能失控;实际控制须分别检查。 } else { print("Waiting for a valid SBUS frame\r\n"); diff --git a/examples/DJI_Board_TypeC_general/controller/vt13.cpp b/examples/DJI_Board_TypeC_general/controller/vt13.cpp index f830692f..51998f8f 100644 --- a/examples/DJI_Board_TypeC_general/controller/vt13.cpp +++ b/examples/DJI_Board_TypeC_general/controller/vt13.cpp @@ -20,56 +20,31 @@ #include "main.h" -#include "bsp_os.h" #include "bsp_print.h" -#include "bsp_uart.h" #include "cmsis_os.h" -#include "protocol.h" -#include "task.h" +#include "refereerc.h" -namespace { - communication::Referee* link = nullptr; -} +static controller::RefereeRC* receiver = nullptr; void RM_RTOS_Init(void) { print_use_uart(&huart1); - // 图传模块发送端 UART:921600 baud、8 位数据、无校验、1 位停止位。 - huart6.Init.BaudRate = 921600; - huart6.Init.WordLength = UART_WORDLENGTH_8B; - huart6.Init.Parity = UART_PARITY_NONE; - huart6.Init.StopBits = UART_STOPBITS_1; - if (HAL_UART_Init(&huart6) != HAL_OK) { - Error_Handler(); - } - - auto* uart = new bsp::UART(&huart6); - // Referee 内部注册 UART 回调和接收线程,由 Protocol 完成 A5/A9 分帧。 - link = new communication::Referee(uart); - uart->SetupRx(300); + // 只接收纯遥控字节流;UART 接入、分帧及校验均由 RefereeRC 完成。 + receiver = new controller::RefereeRC(&huart6); } void RM_RTOS_Default_Task(const void* argument) { UNUSED(argument); while (true) { - remote::RefereeRcFrame state; - bool online; - bool has_state; - uint32_t sequence; - uint32_t last_valid_ms; - - // 防止接收线程在拷贝状态期间切入;临界区内不打印、不延时。 - taskENTER_CRITICAL(); - const auto& receiver = link->RefereeRc(); - online = receiver.IsOnline(bsp::GetHighresTickMilliSec()); - has_state = receiver.GetState(state); - sequence = receiver.GetSequence(); - last_valid_ms = receiver.GetLastValidTimeMs(); - taskEXIT_CRITICAL(); + controller::RefereeRcFrame state; + const bool has_state = receiver->GetState(state); + const bool online = receiver->IsOnline(); + const uint32_t sequence = receiver->GetSequence(); + const uint32_t last_valid_ms = receiver->GetLastValidTimeMs(); set_cursor(0, 0); clear_screen(); - // 使用遥控有效帧的在线状态,不能用 Referee::IsOnline 代替。 + // 只有有效遥控帧刷新在线状态;离线后仍保留最后有效输入。 print("VT13: %s\r\n", online ? "ONLINE" : "OFFLINE"); print("Sequence: %lu\r\n", static_cast(sequence)); print("Last valid: %lu ms\r\n", static_cast(last_valid_ms)); @@ -78,8 +53,9 @@ void RM_RTOS_Default_Task(const void* argument) { print("Right X/Y: %d / %d\r\n", state.channels[0], state.channels[1]); print("Left Y/X: %d / %d\r\n", state.channels[2], state.channels[3]); print("Dial: %d\r\n", state.channels[4]); - const char* mode = state.mode == remote::RefereeRcMode::C ? "C" : - state.mode == remote::RefereeRcMode::N ? "N" : "S"; + const char* mode = state.mode == controller::RefereeRcMode::C ? "C" : + state.mode == controller::RefereeRcMode::N ? "N" : + "S"; print("Mode: %s Pause: %d\r\n", mode, state.pause); print("Button L/R: %d / %d\r\n", state.left_button, state.right_button); print("Trigger: %d\r\n", state.trigger); diff --git a/examples/DJI_Board_TypeC_general/dbus/CMakeLists.txt b/examples/DJI_Board_TypeC_general/dbus/CMakeLists.txt deleted file mode 100644 index 45816a8d..00000000 --- a/examples/DJI_Board_TypeC_general/dbus/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -project(example_dbus_${BOARD_NAME} ASM C CXX) - -uicrm_add_arm_executable(${PROJECT_NAME} - TARGET ${BOARD_NAME} - SOURCES main.cpp) - diff --git a/examples/DJI_Board_TypeC_general/dbus/main.cpp b/examples/DJI_Board_TypeC_general/dbus/main.cpp deleted file mode 100644 index fa77b0a3..00000000 --- a/examples/DJI_Board_TypeC_general/dbus/main.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "main.h" - -#include "bsp_print.h" -#include "cmsis_os.h" -#include "dji_dbus.h" - -static remote::DBUS* dbus; - -void RM_RTOS_Init(void) { - print_use_uart(&huart1); - dbus = new remote::DBUS(&huart3); -} - -void RM_RTOS_Default_Task(const void* arguments) { - UNUSED(arguments); - - // NOTE(alvin): print is split because of stack usage is almost reaching - // limits - while (true) { - set_cursor(0, 0); - clear_screen(); - print( - "CH0: %-4d CH1: %-4d CH2: %-4d CH3: %-4d \r\nSWL: %d SWR: %d " - "TWL: %d " - "@ %d " - "ms\r\n", - dbus->ch0, - dbus->ch1, - dbus->ch2, - dbus->ch3, - dbus->swl, - dbus->swr, - dbus->ch4, - dbus->GetLastUptime() - ); - print( - "W: %d A: %d S: %d D: %d\r\n", - dbus->keyboard.bit.W, - dbus->keyboard.bit.A, - dbus->keyboard.bit.S, - dbus->keyboard.bit.D - ); - print( - "Q: %d E: %d R: %d F: %d G: %d\r\n", - dbus->keyboard.bit.Q, - dbus->keyboard.bit.E, - dbus->keyboard.bit.R, - dbus->keyboard.bit.F, - dbus->keyboard.bit.G - ); - print( - "Z: %d X: %d C: %d V: %d B: %d\r\n", - dbus->keyboard.bit.Z, - dbus->keyboard.bit.X, - dbus->keyboard.bit.C, - dbus->keyboard.bit.V, - dbus->keyboard.bit.B - ); - print("SHIFT: %d CTRL: %d\r\n", dbus->keyboard.bit.SHIFT, dbus->keyboard.bit.CTRL); - print( - "Mouse: x: %d y: %d z: %d l: %d r: %d\r\n", - dbus->mouse.x, - dbus->mouse.y, - dbus->mouse.z, - dbus->mouse.l, - dbus->mouse.r - ); - - osDelay(50); - } -} diff --git a/examples/DJI_Board_TypeC_general/gimbal/CMakeLists.txt b/examples/DJI_Board_TypeC_general/gimbal/CMakeLists.txt index d4aceac7..5722fb26 100644 --- a/examples/DJI_Board_TypeC_general/gimbal/CMakeLists.txt +++ b/examples/DJI_Board_TypeC_general/gimbal/CMakeLists.txt @@ -4,7 +4,3 @@ project(example_gimbal_${BOARD_NAME} ASM C CXX) uicrm_add_arm_executable(${PROJECT_NAME} TARGET ${BOARD_NAME} SOURCES typeC.cpp) - -uicrm_add_arm_executable(${PROJECT_NAME}_sbus - TARGET ${BOARD_NAME} - SOURCES typeC_sbus.cpp) \ No newline at end of file diff --git a/examples/DJI_Board_TypeC_general/gimbal/typeC.cpp b/examples/DJI_Board_TypeC_general/gimbal/typeC.cpp index 21ea1f74..256d0188 100644 --- a/examples/DJI_Board_TypeC_general/gimbal/typeC.cpp +++ b/examples/DJI_Board_TypeC_general/gimbal/typeC.cpp @@ -21,14 +21,14 @@ #include "bsp_imu.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "gimbal.h" #include "i2c.h" #include "main.h" #include "spi.h" static bsp::CAN* can1 = nullptr; -static remote::DBUS* dbus = nullptr; +static controller::DBUS* dbus = nullptr; #define RX_SIGNAL (1 << 0) @@ -92,11 +92,16 @@ const osThreadAttr_t gimbalTaskAttribute = osThreadId_t gimbalTaskHandle; void gimbalTask(void* arg) { + using enum controller::ThreePositionSwitch; + UNUSED(arg); print("Wait for beginning signal...\r\n"); while (true) { - if (dbus->keyboard.bit.V || dbus->swr == remote::DOWN) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.keyboard.bit.V || dbus_state.right_switch == Down) { break; } osDelay(100); @@ -129,19 +134,24 @@ void gimbalTask(void* arg) { float pitch_target = 0, yaw_target = 0; while (true) { - if (dbus->keyboard.bit.B || dbus->swl == remote::DOWN) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.keyboard.bit.B || dbus_state.left_switch == Down) { while (true) { - if (dbus->keyboard.bit.V) { + dbus->GetState(dbus_state); + + if (dbus_state.keyboard.bit.V) { break; } osDelay(10); } } - pitch_ratio = dbus->mouse.y / 32767.0 * 7.5 / 7.0; - yaw_ratio = -dbus->mouse.x / 32767.0 * 7.5 / 7.0; - pitch_ratio = dbus->ch3 / 18000.0 / 7.0; - yaw_ratio = -dbus->ch2 / 18000.0 / 7.0; + pitch_ratio = dbus_state.mouse.y / 32767.0 * 7.5 / 7.0; + yaw_ratio = -dbus_state.mouse.x / 32767.0 * 7.5 / 7.0; + pitch_ratio = dbus_state.channels[3] / 18000.0 / 7.0; + yaw_ratio = -dbus_state.channels[2] / 18000.0 / 7.0; pitch_target = clip(pitch_ratio, -gimbal_param->pitch_max_, gimbal_param->pitch_max_); yaw_target = clip(yaw_ratio, -gimbal_param->yaw_max_, gimbal_param->yaw_max_); @@ -162,7 +172,7 @@ void RM_RTOS_Init(void) { print_use_uart(&huart6); can1 = new bsp::CAN(&hcan1, true); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); bsp::IST8310_init_t IST8310_init; IST8310_init.hi2c = &hi2c3; @@ -303,7 +313,10 @@ void RM_RTOS_Threads_Init(void) { void KillAll() { RM_EXPECT_TRUE(false, "Operation killed\r\n"); while (true) { - if (dbus->keyboard.bit.V) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.keyboard.bit.V) { break; } pitch_motor->SetOutput(0); @@ -313,10 +326,15 @@ void KillAll() { } void RM_RTOS_Default_Task(const void* arg) { + using enum controller::ThreePositionSwitch; + UNUSED(arg); while (true) { - if (dbus->keyboard.bit.B || dbus->swl == remote::DOWN) + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.keyboard.bit.B || dbus_state.left_switch == Down) KillAll(); set_cursor(0, 0); @@ -337,8 +355,19 @@ void RM_RTOS_Default_Task(const void* arg) { print("\r\n"); - print("CH0: %-4d CH1: %-4d CH2: %-4d CH3: %-4d ", dbus->ch0, dbus->ch1, dbus->ch2, dbus->ch3); - print("SWL: %d SWR: %d @ %d ms\r\n", dbus->swl, dbus->swr, dbus->GetLastUptime()); + print( + "CH0: %-4d CH1: %-4d CH2: %-4d CH3: %-4d ", + dbus_state.channels[0], + dbus_state.channels[1], + dbus_state.channels[2], + dbus_state.channels[3] + ); + print( + "SWL: %s SWR: %s @ %d ms\r\n", + controller::SwitchName(dbus_state.left_switch), + controller::SwitchName(dbus_state.right_switch), + dbus->GetLastValidTimeMs() + ); osDelay(100); } diff --git a/examples/DJI_Board_TypeC_general/gimbal/typeC_sbus.cpp b/examples/DJI_Board_TypeC_general/gimbal/typeC_sbus.cpp deleted file mode 100644 index b17f8b34..00000000 --- a/examples/DJI_Board_TypeC_general/gimbal/typeC_sbus.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "bsp_imu.h" -#include "bsp_print.h" -#include "cmsis_os.h" -#include "gimbal.h" -#include "i2c.h" -#include "main.h" -#include "sbus.h" -#include "spi.h" - -static bsp::CAN* can1 = nullptr; -static remote::SBUS* sbus = nullptr; - -#define RX_SIGNAL (1 << 0) - -const osThreadAttr_t imuTaskAttribute = - {.name = "imuTask", - .attr_bits = osThreadDetached, - .cb_mem = nullptr, - .cb_size = 0, - .stack_mem = nullptr, - .stack_size = 256 * 4, - .priority = (osPriority_t)osPriorityNormal, - .tz_module = 0, - .reserved = 0}; -osThreadId_t imuTaskHandle; - -class IMU : public bsp::IMU_typeC { - public: - using bsp::IMU_typeC::IMU_typeC; - - protected: - void RxCompleteCallback() final { - osThreadFlagsSet(imuTaskHandle, RX_SIGNAL); - } -}; - -static IMU* imu = nullptr; - -void imuTask(void* arg) { - UNUSED(arg); - - while (true) { - uint32_t flags = osThreadFlagsWait(RX_SIGNAL, osFlagsWaitAll, osWaitForever); - if (flags & RX_SIGNAL) { // unnecessary check - imu->Update(); - } - } -} - -static driver::DjiMotorBase* pitch_motor = nullptr; -static driver::DjiMotorBase* yaw_motor = nullptr; -static control::Gimbal* gimbal = nullptr; -static control::gimbal_data_t* gimbal_param = nullptr; - -const control::gimbal_data_t gimbal_init_data = - {.pitch_offset_ = 2.8582f, .yaw_offset_ = 2.5840f, .pitch_max_ = 0.4897f, .yaw_max_ = PI / 2, .yaw_circle_ = true}; - -const osThreadAttr_t gimbalTaskAttribute = - {.name = "gimbalTask", - .attr_bits = osThreadDetached, - .cb_mem = nullptr, - .cb_size = 0, - .stack_mem = nullptr, - .stack_size = 256 * 4, - .priority = (osPriority_t)osPriorityNormal, - .tz_module = 0, - .reserved = 0}; -osThreadId_t gimbalTaskHandle; - -void gimbalTask(void* arg) { - UNUSED(arg); - - print("Wait for beginning signal...\r\n"); - while (true) { - if (sbus->ch7 >= 0) { - break; - } - osDelay(100); - } - - int i = 0; - while (i < 2000 || !imu->DataReady()) { - gimbal->TargetAbs(0, 0); - gimbal->Update(); - osDelay(1); - ++i; - } - - print("Start Calibration.\r\n"); - imu->Calibrate(); - - i = 0; - while (!imu->DataReady() || !imu->CaliDone()) { - gimbal->TargetAbs(0, 0); - gimbal->Update(); - osDelay(1); - ++i; - } - - print("Gimbal Begin!\r\n"); - - float pitch_ratio, yaw_ratio; - float pitch_curr, yaw_curr; - float pitch_diff, yaw_diff; - float pitch_target = 0, yaw_target = 0; - - while (true) { - if (sbus->ch7 < 0) { - while (true) { - if (sbus->ch7 >= 0) { - break; - } - osDelay(10); - } - } - - pitch_ratio = sbus->ch3 / 18000.0 / 7.0; - yaw_ratio = -sbus->ch4 / 18000.0 / 7.0; - pitch_target = clip(pitch_ratio, -gimbal_param->pitch_max_, gimbal_param->pitch_max_); - yaw_target = clip(yaw_ratio, -gimbal_param->yaw_max_, gimbal_param->yaw_max_); - - pitch_diff = wrap(pitch_target, -PI, PI); - yaw_diff = wrap(yaw_target, -PI, PI); - - pitch_curr = imu->INS_angle[2]; - yaw_curr = imu->INS_angle[0]; - - gimbal->TargetRel(pitch_diff, yaw_diff); - - gimbal->UpdateIMU(pitch_curr, yaw_curr); - osDelay(1); - } -} - -void RM_RTOS_Init(void) { - print_use_uart(&huart6); - - can1 = new bsp::CAN(&hcan2, false); - sbus = new remote::SBUS(&huart3); - - bsp::IST8310_init_t IST8310_init; - IST8310_init.hi2c = &hi2c3; - IST8310_init.int_pin = DRDY_IST8310_Pin; - IST8310_init.rst_group = GPIOG; - IST8310_init.rst_pin = GPIO_PIN_6; - bsp::BMI088_init_t BMI088_init; - BMI088_init.hspi = &hspi1; - BMI088_init.CS_ACCEL_Port = CS1_ACCEL_GPIO_Port; - BMI088_init.CS_ACCEL_Pin = CS1_ACCEL_Pin; - BMI088_init.CS_GYRO_Port = CS1_GYRO_GPIO_Port; - BMI088_init.CS_GYRO_Pin = CS1_GYRO_Pin; - bsp::heater_init_t heater_init; - heater_init.htim = &htim10; - heater_init.channel = 1; - heater_init.clock_freq = 1000000; - heater_init.temp = 45; - bsp::IMU_typeC_init_t imu_init; - imu_init.IST8310 = IST8310_init; - imu_init.BMI088 = BMI088_init; - imu_init.heater = heater_init; - imu_init.hspi = &hspi1; - imu_init.hdma_spi_rx = &hdma_spi1_rx; - imu_init.hdma_spi_tx = &hdma_spi1_tx; - imu_init.Accel_INT_pin_ = INT1_ACCEL_Pin; - imu_init.Gyro_INT_pin_ = INT1_GYRO_Pin; - imu = new IMU(imu_init, false); - - pitch_motor = new driver::Motor6020(can1, 0x205); - yaw_motor = new driver::Motor6020(can1, 0x206); - pitch_motor = new driver::Motor6020(can1, 0x206); - yaw_motor = new driver::Motor6020(can1, 0x205); - - pitch_motor->SetTransmissionRatio(1); - control::ConstrainedPID::PID_Init_t pitch_theta_pid_init = { - .kp = 20, - .ki = 0, - .kd = 0, - .max_out = 6 * PI, - .max_iout = 0, - .deadband = 0, // 死区 - .A = 0, // 变速积分所能达到的最大值为A+B - .B = 0, // 启动变速积分的死区 - .output_filtering_coefficient = 0.1, // 输出滤波系数 - .derivative_filtering_coefficient = 0, // 微分滤波系数 - .mode = control::ConstrainedPID::OutputFilter // 输出滤波 - }; - pitch_motor->ReInitPID(pitch_theta_pid_init, driver::DjiMotorBase::THETA); - control::ConstrainedPID::PID_Init_t pitch_omega_pid_init = { - .kp = 200, - .ki = 1, - .kd = 0, - .max_out = 16384, - .max_iout = 2000, - .deadband = 0, // 死区 - .A = 1.5 * PI, // 变速积分所能达到的最大值为A+B - .B = 1 * PI, // 启动变速积分的死区 - .output_filtering_coefficient = 0.1, // 输出滤波系数 - .derivative_filtering_coefficient = 0, // 微分滤波系数 - .mode = control::ConstrainedPID::Integral_Limit | // 积分限幅 - control::ConstrainedPID::OutputFilter | // 输出滤波 - control::ConstrainedPID::Trapezoid_Intergral | // 梯形积分 - control::ConstrainedPID::ChangingIntegralRate, // 变速积分 - }; - pitch_motor->ReInitPID(pitch_omega_pid_init, driver::DjiMotorBase::OMEGA); - pitch_motor->SetMode(driver::DjiMotorBase::THETA | driver::DjiMotorBase::OMEGA | driver::DjiMotorBase::ABSOLUTE); - - yaw_motor->SetTransmissionRatio(1); - control::ConstrainedPID::PID_Init_t yaw_theta_pid_init = { - .kp = 20, - .ki = 0, - .kd = 0, - .max_out = 6 * PI, - .max_iout = 0, - .deadband = 0, // 死区 - .A = 0, // 变速积分所能达到的最大值为A+B - .B = 0, // 启动变速积分的死区 - .output_filtering_coefficient = 0.1, // 输出滤波系数 - .derivative_filtering_coefficient = 0, // 微分滤波系数 - .mode = control::ConstrainedPID::OutputFilter // 输出滤波 - }; - yaw_motor->ReInitPID(yaw_theta_pid_init, driver::DjiMotorBase::THETA); - control::ConstrainedPID::PID_Init_t yaw_omega_pid_init = { - .kp = 200, - .ki = 1, - .kd = 0, - .max_out = 16384, - .max_iout = 2000, - .deadband = 0, // 死区 - .A = 1.5 * PI, // 变速积分所能达到的最大值为A+B - .B = 1 * PI, // 启动变速积分的死区 - .output_filtering_coefficient = 0.1, // 输出滤波系数 - .derivative_filtering_coefficient = 0, // 微分滤波系数 - .mode = control::ConstrainedPID::Integral_Limit | // 积分限幅 - control::ConstrainedPID::OutputFilter | // 输出滤波 - control::ConstrainedPID::Trapezoid_Intergral | // 梯形积分 - control::ConstrainedPID::ChangingIntegralRate, // 变速积分 - }; - yaw_motor->ReInitPID(yaw_omega_pid_init, driver::DjiMotorBase::OMEGA); - yaw_motor->SetMode(driver::DjiMotorBase::THETA | driver::DjiMotorBase::OMEGA | driver::DjiMotorBase::ABSOLUTE); - - control::gimbal_t gimbal_data; - gimbal_data.data = gimbal_init_data; - gimbal_data.pitch_motor = pitch_motor; - gimbal_data.yaw_motor = yaw_motor; - - gimbal = new control::Gimbal(gimbal_data); - gimbal_param = gimbal->GetData(); -} - -void RM_RTOS_Threads_Init(void) { - imuTaskHandle = osThreadNew(imuTask, nullptr, &imuTaskAttribute); - gimbalTaskHandle = osThreadNew(gimbalTask, nullptr, &gimbalTaskAttribute); -} - -void KillAll() { - RM_EXPECT_TRUE(false, "Operation killed\r\n"); - while (true) { - pitch_motor->SetOutput(0); - yaw_motor->SetOutput(0); - osDelay(10); - } -} - -void RM_RTOS_Default_Task(const void* arg) { - UNUSED(arg); - - while (true) { - if (sbus->ch5 > 0) - KillAll(); - - set_cursor(0, 0); - clear_screen(); - - print( - "# %.2f s, IMU %s\r\n", - HAL_GetTick() / 1000.0, - imu->CaliDone() ? "\033[1;42mReady\033[0m" : "\033[1;41mNot Ready\033[0m" - ); - print("Temp: %.2f\r\n", imu->Temp); - print( - "Euler Angles: %.2f, %.2f, %.2f\r\n", - imu->INS_angle[0] / PI * 180, - imu->INS_angle[1] / PI * 180, - imu->INS_angle[2] / PI * 180 - ); - - print("\r\n"); - - print("CH1: %-4d CH2: %-4d CH3: %-4d CH4: %-4d ", sbus->ch1, sbus->ch2, sbus->ch3, sbus->ch4); - print( - "CH5: %d CH6: %d CH7: %d CH8: %d @ %d ms\r\n", - sbus->ch5, - sbus->ch6, - sbus->ch7, - sbus->ch8, - sbus->timestamp - ); - - osDelay(100); - } -} diff --git a/examples/DJI_Board_TypeC_general/motor/m2305.cpp b/examples/DJI_Board_TypeC_general/motor/m2305.cpp index 2b4a4247..95eac943 100644 --- a/examples/DJI_Board_TypeC_general/motor/m2305.cpp +++ b/examples/DJI_Board_TypeC_general/motor/m2305.cpp @@ -22,7 +22,7 @@ #include "bsp_gpio.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #include "utils.h" @@ -38,10 +38,10 @@ driver::PWMMotorBase* motor1; driver::PWMMotorBase* motor2; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; void RM_RTOS_Init() { - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); print_use_uart(&huart6); motor1 = new driver::PWMMotorBase(&htim1, LEFT_MOTOR_PWM_CHANNEL, TIM_CLOCK_FREQ, MOTOR_OUT_FREQ, SNAIL_IDLE_THROTTLE); @@ -54,20 +54,25 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); bsp::GPIO key(KEY_GPIO_GROUP, KEY_GPIO_PIN); RampSource ramp_1 = RampSource(0, 0, 450, 0.001); RampSource ramp_2 = RampSource(0, 0, 450, 0.001); int current = 0; int state = 0; - int8_t last_state = remote::MID; + auto last_state = Mid; while (true) { - if (dbus->swl == remote::UP) { - if (last_state == remote::MID) - last_state = remote::UP; - } else if (dbus->swl == remote::MID) { - if (last_state == remote::UP) { - last_state = remote::MID; + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.left_switch == Up) { + if (last_state == Mid) + last_state = Up; + } else if (dbus_state.left_switch == Mid) { + if (last_state == Up) { + last_state = Mid; if (state == 0) { state = 1; diff --git a/examples/DJI_Board_TypeC_general/motor/servo_m2006.cpp b/examples/DJI_Board_TypeC_general/motor/servo_m2006.cpp index 8fd08ac2..cefdb1cf 100644 --- a/examples/DJI_Board_TypeC_general/motor/servo_m2006.cpp +++ b/examples/DJI_Board_TypeC_general/motor/servo_m2006.cpp @@ -23,20 +23,20 @@ #include "bsp_os.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" bsp::CAN* can2 = NULL; driver::DjiMotorBase* motor1 = NULL; driver::ServoMotor* load_servo = NULL; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; float load_step_angle = 2 * PI / 8; void RM_RTOS_Init() { bsp::SetHighresClockTimer(&htim5); HAL_Delay(200); print_use_uart(&huart1); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); can2 = new bsp::CAN(&hcan1, true); motor1 = new driver::Motor2006(can2, 0x201); driver::servo_t servo_data; @@ -56,27 +56,32 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); - int last_state = remote::MID; + auto last_state = Mid; while (true) { - if (last_state != dbus->swl && dbus->swl == remote::MID) { - if (last_state == remote::UP) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (last_state != dbus_state.left_switch && dbus_state.left_switch == Mid) { + if (last_state == Up) { load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); - } else if (last_state == remote::DOWN) { + } else if (last_state == Down) { load_servo->SetTarget(load_servo->GetTarget() - load_step_angle); } } else { - if (dbus->ch3 > 0) { + if (dbus_state.channels[3] > 0) { load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); - } else if (dbus->ch3 < 0) { + } else if (dbus_state.channels[3] < 0) { load_servo->SetTarget(load_servo->GetTarget() - load_step_angle); } } load_servo->CalcOutput(); - last_state = dbus->swl; + last_state = dbus_state.left_switch; osDelay(1); } } diff --git a/examples/DJI_Board_TypeC_general/motor/servo_m3508.cpp b/examples/DJI_Board_TypeC_general/motor/servo_m3508.cpp index 1b8c86d3..be90b823 100644 --- a/examples/DJI_Board_TypeC_general/motor/servo_m3508.cpp +++ b/examples/DJI_Board_TypeC_general/motor/servo_m3508.cpp @@ -23,20 +23,20 @@ #include "bsp_os.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" bsp::CAN* can1 = NULL; driver::DjiMotorBase* motor1 = NULL; driver::ServoMotor* load_servo = NULL; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; float load_step_angle = 10 * PI; void RM_RTOS_Init() { bsp::SetHighresClockTimer(&htim5); HAL_Delay(200); print_use_uart(&huart6); - dbus = new remote::DBUS(&huart3); + dbus = new controller::DBUS(&huart3); can1 = new bsp::CAN(&hcan1, true); motor1 = new driver::Motor3508(can1, 0x201); @@ -56,26 +56,31 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); - int last_state = remote::MID; + auto last_state = Mid; while (true) { - if (last_state != dbus->swl && dbus->swl == remote::MID) { - if (last_state == remote::UP) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (last_state != dbus_state.left_switch && dbus_state.left_switch == Mid) { + if (last_state == Up) { load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); - } else if (last_state == remote::DOWN) { + } else if (last_state == Down) { load_servo->SetTarget(load_servo->GetTarget() - load_step_angle); } } else { - if (dbus->ch3 > 0) { + if (dbus_state.channels[3] > 0) { load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); - } else if (dbus->ch3 < 0) { + } else if (dbus_state.channels[3] < 0) { load_servo->SetTarget(load_servo->GetTarget() - load_step_angle); } } load_servo->CalcOutput(); - last_state = dbus->swl; + last_state = dbus_state.left_switch; osDelay(1); } } diff --git a/examples/DJI_Board_TypeC_general/referee/CMakeLists.txt b/examples/DJI_Board_TypeC_general/referee/CMakeLists.txt index 88e8e8d0..9fce1431 100644 --- a/examples/DJI_Board_TypeC_general/referee/CMakeLists.txt +++ b/examples/DJI_Board_TypeC_general/referee/CMakeLists.txt @@ -3,7 +3,3 @@ project(example_referee_${BOARD_NAME} ASM C CXX) uicrm_add_arm_executable(${PROJECT_NAME} TARGET ${BOARD_NAME} SOURCES main.cpp) - -uicrm_add_arm_executable(${PROJECT_NAME}_rc - TARGET ${BOARD_NAME} - SOURCES rc.cpp) \ No newline at end of file diff --git a/examples/DJI_Board_TypeC_general/referee/rc.cpp b/examples/DJI_Board_TypeC_general/referee/rc.cpp deleted file mode 100644 index e36f506c..00000000 --- a/examples/DJI_Board_TypeC_general/referee/rc.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "bsp_print.h" -#include "bsp_uart.h" -#include "cmsis_os.h" -#include "dji_dbus.h" -#include "main.h" -#include "protocol.h" - -communication::Referee* referee = nullptr; -bsp::UART* referee_uart = nullptr; - -communication::Referee* refereeRc = nullptr; -bsp::UART* refereeRc_uart = nullptr; - -void RM_RTOS_Init(void) { - print_use_usb(); - - referee_uart = new bsp::UART(&huart1); - referee_uart->SetupRx(300); - referee_uart->SetupTx(300); - - refereeRc_uart = new bsp::UART(&huart6); - refereeRc_uart->SetupRx(300); - refereeRc_uart->SetupTx(300); - - referee = new communication::Referee(referee_uart); - - refereeRc = new communication::Referee(refereeRc_uart); -} - -void RM_RTOS_Threads_Init(void) { -} - -void RM_RTOS_Default_Task(const void* argument) { - UNUSED(argument); - - while (true) { - set_cursor(0, 0); - clear_screen(); - // print("Chassis Volt: %.3f\r\n", referee->power_heat_data.chassis_volt / 1000.0); - // print("Chassis Curr: %.3f\r\n", referee->power_heat_data.chassis_current / - // 1000.0); print("Chassis Power: %.3f\r\n", referee->power_heat_data.chassis_power); - // print("Chassis Power Limit: %d\r\n", - // referee->game_robot_status.chassis_power_limit); print("\r\n"); print("Shooter - // Cooling Heat: %hu\r\n", - // referee->power_heat_data.shooter_id1_17mm_cooling_heat); - // print("Bullet Frequency: %hhu\r\n", referee->shoot_data.bullet_freq); - // print("Bullet Speed: %.3f\r\n", referee->shoot_data.bullet_speed); - // print("\r\n"); - // print("Current HP %d/%d\n", referee->game_robot_status.remain_HP, - // referee->game_robot_status.max_HP); - // print("Remain bullet %d\n", referee->bullet_remaining.bullet_remaining_num_17mm); - remote::keyboard_t keyboard = referee->remote_control.keyboard; - remote::mouse_t mouse = referee->remote_control.mouse; - print( - "W: %d A: %d S: %d D: %d\r\n" - "Q: %d E: %d R: %d F: %d G: %d\r\n" - "Z: %d X: %d C: %d V: %d B: %d\r\n" - "SHIFT: %d CTRL: %d\r\n" - "Mouse: x: %d y: %d z: %d l: %d r: %d\r\n", - keyboard.bit.W, - keyboard.bit.A, - keyboard.bit.S, - keyboard.bit.D, - keyboard.bit.Q, - keyboard.bit.E, - keyboard.bit.R, - keyboard.bit.F, - keyboard.bit.G, - keyboard.bit.Z, - keyboard.bit.X, - keyboard.bit.C, - keyboard.bit.V, - keyboard.bit.B, - keyboard.bit.SHIFT, - keyboard.bit.CTRL, - mouse.x, - mouse.y, - mouse.z, - mouse.l, - mouse.r - ); - osDelay(1); - } -} \ No newline at end of file diff --git a/examples/DJI_Board_TypeC_general/sbus/CMakeLists.txt b/examples/DJI_Board_TypeC_general/sbus/CMakeLists.txt deleted file mode 100644 index f1ea8bb9..00000000 --- a/examples/DJI_Board_TypeC_general/sbus/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -project(example_sbus_${BOARD_NAME} ASM C CXX) - -uicrm_add_arm_executable(${PROJECT_NAME} - TARGET ${BOARD_NAME} - SOURCES main.cpp) - diff --git a/examples/DJI_Board_TypeC_general/sbus/main.cpp b/examples/DJI_Board_TypeC_general/sbus/main.cpp deleted file mode 100644 index 137d1b10..00000000 --- a/examples/DJI_Board_TypeC_general/sbus/main.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "main.h" - -#include "bsp_print.h" -#include "cmsis_os.h" -#include "sbus.h" - -static remote::SBUS* dbus; - -void RM_RTOS_Init(void) { - print_use_uart(&huart1); - dbus = new remote::SBUS(&huart3); -} - -void RM_RTOS_Default_Task(const void* arguments) { - UNUSED(arguments); - - // NOTE(alvin): print is split because of stack usage is almost reaching - // limits - while (true) { - set_cursor(0, 0); - clear_screen(); - print( - "CH1: %-4d CH2: %-4d CH3: %-4d CH4: %-4d \r\n" - "CH5: %-4d CH6: %-4d CH7: %-4d CH8: %-4d \r\n" - "CH9: %-4d CH10: %-4d CH11: %-4d CH12: %-4d \r\n" - "CH13: %-4d CH14: %-4d CH15: %-4d CH16: %-4d \r\n", - dbus->ch1, - dbus->ch2, - dbus->ch3, - dbus->ch4, - dbus->ch5, - dbus->ch6, - dbus->ch7, - dbus->ch8, - dbus->ch9, - dbus->ch10, - dbus->ch11, - dbus->ch12, - dbus->ch13, - dbus->ch14, - dbus->ch15, - dbus->ch16 - ); - - osDelay(50); - } -} From ce17f66569a9097003bfd81370ffdaee02f6f81a Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:21 +0800 Subject: [PATCH 14/17] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20DJI=5FBo?= =?UTF-8?q?ard=5FTypeA=20=E7=A4=BA=E4=BE=8B=E8=87=B3=20controller=20?= =?UTF-8?q?=E9=81=A5=E6=8E=A7=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DJI_Board_TypeA_general/CMakeLists.txt | 3 +- .../can_bridge/host.cpp | 17 +-- .../chassis/CMakeLists.txt | 4 - .../chassis/can_bridge_chassis_sender.cpp | 19 +-- .../chassis/mecanum_example.cpp | 17 ++- .../chassis/omni_example.cpp | 17 ++- .../DJI_Board_TypeA_general/chassis/sbus.cpp | 112 ------------------ .../dbus/CMakeLists.txt | 6 - .../DJI_Board_TypeA_general/dbus/main.cpp | 91 -------------- .../DJI_Board_TypeA_general/gimbal/typeA.cpp | 57 ++++++--- .../DJI_Board_TypeA_general/motor/m2305.cpp | 25 ++-- .../motor/servo_m2006.cpp | 25 ++-- .../motor/servo_m3508.cpp | 25 ++-- .../referee/CMakeLists.txt | 4 - .../DJI_Board_TypeA_general/referee/rc.cpp | 104 ---------------- 15 files changed, 135 insertions(+), 391 deletions(-) delete mode 100644 examples/DJI_Board_TypeA_general/chassis/sbus.cpp delete mode 100644 examples/DJI_Board_TypeA_general/dbus/CMakeLists.txt delete mode 100644 examples/DJI_Board_TypeA_general/dbus/main.cpp delete mode 100644 examples/DJI_Board_TypeA_general/referee/rc.cpp diff --git a/examples/DJI_Board_TypeA_general/CMakeLists.txt b/examples/DJI_Board_TypeA_general/CMakeLists.txt index f9967ae9..8e64eaf6 100644 --- a/examples/DJI_Board_TypeA_general/CMakeLists.txt +++ b/examples/DJI_Board_TypeA_general/CMakeLists.txt @@ -3,11 +3,10 @@ set(BOARD_NAME ${CURRENT_DIR_NAME}) add_subdirectory(buzzer) add_subdirectory(can_bridge) add_subdirectory(chassis) -add_subdirectory(dbus) add_subdirectory(MPU6500) add_subdirectory(fatfs) add_subdirectory(led_flow) add_subdirectory(gimbal) add_subdirectory(motor) add_subdirectory(witimu) -add_subdirectory(referee) \ No newline at end of file +add_subdirectory(referee) diff --git a/examples/DJI_Board_TypeA_general/can_bridge/host.cpp b/examples/DJI_Board_TypeA_general/can_bridge/host.cpp index 7cc0b12a..a35515c2 100644 --- a/examples/DJI_Board_TypeA_general/can_bridge/host.cpp +++ b/examples/DJI_Board_TypeA_general/can_bridge/host.cpp @@ -24,13 +24,13 @@ #include "bsp_uart.h" #include "can_bridge.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" static bsp::CAN* can1 = nullptr; static communication::CanBridge* can_bridge = nullptr; -static remote::DBUS* dbus = nullptr; +static controller::DBUS* dbus = nullptr; void RM_RTOS_Init(void) { print_use_usb(); @@ -38,18 +38,21 @@ void RM_RTOS_Init(void) { can1 = new bsp::CAN(&hcan1, true, 8); can_bridge = new communication::CanBridge(can1, 0x02); - dbus = new remote::DBUS(&huart1); + dbus = new controller::DBUS(&huart1); } void RM_RTOS_Default_Task(const void* argument) { UNUSED(argument); while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + communication::can_bridge_data_t data; - data.data_four_int16.data[0] = dbus->ch0; - data.data_four_int16.data[1] = dbus->ch1; - data.data_four_int16.data[2] = dbus->ch2; - data.data_four_int16.data[3] = dbus->ch3; + data.data_four_int16.data[0] = dbus_state.channels[0]; + data.data_four_int16.data[1] = dbus_state.channels[1]; + data.data_four_int16.data[2] = dbus_state.channels[2]; + data.data_four_int16.data[3] = dbus_state.channels[3]; communication::can_bridge_ext_id_t ext_id; ext_id.data.rx_id = 0x01; ext_id.data.type = communication::CAN_BRIDGE_TYPE_FOUR_INT16; diff --git a/examples/DJI_Board_TypeA_general/chassis/CMakeLists.txt b/examples/DJI_Board_TypeA_general/chassis/CMakeLists.txt index e69f68d4..72baf94f 100644 --- a/examples/DJI_Board_TypeA_general/chassis/CMakeLists.txt +++ b/examples/DJI_Board_TypeA_general/chassis/CMakeLists.txt @@ -8,10 +8,6 @@ uicrm_add_arm_executable(${PROJECT_NAME}_omni TARGET ${BOARD_NAME} SOURCES omni_example.cpp) -uicrm_add_arm_executable(${PROJECT_NAME}_sbus - TARGET ${BOARD_NAME} - SOURCES sbus.cpp) - uicrm_add_arm_executable(${PROJECT_NAME}_can_bridge TARGET ${BOARD_NAME} SOURCES can_bridge_chassis.cpp) diff --git a/examples/DJI_Board_TypeA_general/chassis/can_bridge_chassis_sender.cpp b/examples/DJI_Board_TypeA_general/chassis/can_bridge_chassis_sender.cpp index c01f40f9..77933064 100644 --- a/examples/DJI_Board_TypeA_general/chassis/can_bridge_chassis_sender.cpp +++ b/examples/DJI_Board_TypeA_general/chassis/can_bridge_chassis_sender.cpp @@ -21,7 +21,7 @@ #include "bsp_print.h" #include "can_bridge.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #ifndef PI @@ -29,7 +29,7 @@ #endif static bsp::CAN* can1 = nullptr; -static remote::DBUS* dbus = nullptr; +static controller::DBUS* dbus = nullptr; static communication::CanBridge* can_bridge = nullptr; void RM_RTOS_Init() { @@ -38,11 +38,13 @@ void RM_RTOS_Init() { can1 = new bsp::CAN(&hcan1, true); can_bridge = new communication::CanBridge(can1, 0x51); - dbus = new remote::DBUS(&huart1); + dbus = new controller::DBUS(&huart1); HAL_Delay(300); } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); osDelay(500); // DBUS initialization needs time @@ -50,10 +52,13 @@ void RM_RTOS_Default_Task(const void* args) { communication::can_bridge_ext_id_t ext_id; communication::can_bridge_data_t can_bridge_data; while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + const float ratio = 1.0f / 660.0f * 6 * PI; ext_id.data.type = communication::CAN_BRIDGE_TYPE_TWO_FLOAT; ext_id.data.rx_id = 0x52; - if (dbus->swr == remote::DOWN) { + if (dbus_state.right_switch == Down) { { ext_id.data.reg = 0x71; @@ -68,8 +73,8 @@ void RM_RTOS_Default_Task(const void* args) { { ext_id.data.reg = 0x70; - can_bridge_data.data_two_float.data[0] = (float)dbus->ch0 * ratio; - can_bridge_data.data_two_float.data[1] = (float)dbus->ch1 * ratio; + can_bridge_data.data_two_float.data[0] = (float)dbus_state.channels[0] * ratio; + can_bridge_data.data_two_float.data[1] = (float)dbus_state.channels[1] * ratio; can_bridge->Send(ext_id, can_bridge_data); osDelay(1); @@ -78,7 +83,7 @@ void RM_RTOS_Default_Task(const void* args) { ext_id.data.reg = 0x71; can_bridge_data.data_two_float.data[0] = (float)1; - can_bridge_data.data_two_float.data[1] = (float)dbus->ch2 * ratio; + can_bridge_data.data_two_float.data[1] = (float)dbus_state.channels[2] * ratio; can_bridge->Send(ext_id, can_bridge_data); osDelay(1); diff --git a/examples/DJI_Board_TypeA_general/chassis/mecanum_example.cpp b/examples/DJI_Board_TypeA_general/chassis/mecanum_example.cpp index 05e03be5..61029cc1 100644 --- a/examples/DJI_Board_TypeA_general/chassis/mecanum_example.cpp +++ b/examples/DJI_Board_TypeA_general/chassis/mecanum_example.cpp @@ -23,7 +23,7 @@ #include "bsp_print.h" #include "chassis.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" bsp::CAN* can = nullptr; driver::DjiMotorBase* fl_motor = nullptr; @@ -32,7 +32,7 @@ driver::DjiMotorBase* bl_motor = nullptr; driver::DjiMotorBase* br_motor = nullptr; control::Chassis* chassis = nullptr; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; void RM_RTOS_Init() { HAL_Delay(200); @@ -87,21 +87,28 @@ void RM_RTOS_Init() { chassis_data.model = control::CHASSIS_MECANUM_WHEEL; chassis = new control::Chassis(chassis_data); - dbus = new remote::DBUS(&huart1); + dbus = new controller::DBUS(&huart1); HAL_Delay(300); } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); osDelay(500); // DBUS initialization needs time while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + const float ratio = 1.0f / 660.0f * 6 * PI; - chassis->SetSpeed(dbus->ch0 * ratio, dbus->ch1 * ratio, dbus->ch2 * ratio); + chassis + ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus->swl == remote::UP || dbus->swl == remote::DOWN) { + if (dbus_state.left_switch == Up || + dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/examples/DJI_Board_TypeA_general/chassis/omni_example.cpp b/examples/DJI_Board_TypeA_general/chassis/omni_example.cpp index 8c0f034c..e27bf763 100644 --- a/examples/DJI_Board_TypeA_general/chassis/omni_example.cpp +++ b/examples/DJI_Board_TypeA_general/chassis/omni_example.cpp @@ -24,7 +24,7 @@ #include "bsp_print.h" #include "chassis.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" bsp::CAN* can = nullptr; driver::DjiMotorBase* fl_motor = nullptr; @@ -33,7 +33,7 @@ driver::DjiMotorBase* bl_motor = nullptr; driver::DjiMotorBase* br_motor = nullptr; control::Chassis* chassis = nullptr; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; void RM_RTOS_Init() { HAL_Delay(200); @@ -88,21 +88,28 @@ void RM_RTOS_Init() { chassis_data.model = control::CHASSIS_OMNI_WHEEL; chassis = new control::Chassis(chassis_data); - dbus = new remote::DBUS(&huart1); + dbus = new controller::DBUS(&huart1); HAL_Delay(300); } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); osDelay(500); // DBUS initialization needs time while (true) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + const float ratio = 1.0f / 660.0f * 6 * PI; - chassis->SetSpeed(dbus->ch0 * ratio, dbus->ch1 * ratio, dbus->ch2 * ratio); + chassis + ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus->swl == remote::UP || dbus->swl == remote::DOWN) { + if (dbus_state.left_switch == Up || + dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/examples/DJI_Board_TypeA_general/chassis/sbus.cpp b/examples/DJI_Board_TypeA_general/chassis/sbus.cpp deleted file mode 100644 index fe86e640..00000000 --- a/examples/DJI_Board_TypeA_general/chassis/sbus.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "sbus.h" - -#include "bsp_print.h" -#include "chassis.h" -#include "cmsis_os.h" -#include "main.h" - -bsp::CAN* can = nullptr; -driver::DjiMotorBase* fl_motor = nullptr; -driver::DjiMotorBase* fr_motor = nullptr; -driver::DjiMotorBase* bl_motor = nullptr; -driver::DjiMotorBase* br_motor = nullptr; - -control::Chassis* chassis = nullptr; -remote::SBUS* sbus = nullptr; - -void RM_RTOS_Init() { - HAL_Delay(200); - print_use_uart(&huart8); - can = new bsp::CAN(&hcan1, true); - fl_motor = new driver::Motor3508(can, 0x202); - fr_motor = new driver::Motor3508(can, 0x201); - bl_motor = new driver::Motor3508(can, 0x203); - br_motor = new driver::Motor3508(can, 0x204); - - control::ConstrainedPID::PID_Init_t omega_pid_init = { - .kp = 2500, - .ki = 3, - .kd = 0, - .max_out = 30000, - .max_iout = 10000, - .deadband = 0, // 死区 - .A = 6000, // 变速积分所能达到的最大值为A+B - .B = 4000, // 启动变速积分的死区 - .output_filtering_coefficient = 0.1, // 输出滤波系数 - .derivative_filtering_coefficient = 0, // 微分滤波系数 - .mode = control::ConstrainedPID::Integral_Limit | // 积分限幅 - control::ConstrainedPID::OutputFilter | // 输出滤波 - control::ConstrainedPID::Trapezoid_Intergral | // 梯形积分 - control::ConstrainedPID::ChangingIntegralRate, // 变速积分 - }; - - fl_motor->ReInitPID(omega_pid_init, driver::DjiMotorBase::OMEGA); - fl_motor->SetMode(driver::DjiMotorBase::OMEGA); - fl_motor->SetTransmissionRatio(19); - - fr_motor->ReInitPID(omega_pid_init, driver::DjiMotorBase::OMEGA); - fr_motor->SetMode(driver::DjiMotorBase::OMEGA); - fr_motor->SetTransmissionRatio(19); - - bl_motor->ReInitPID(omega_pid_init, driver::DjiMotorBase::OMEGA); - bl_motor->SetMode(driver::DjiMotorBase::OMEGA); - bl_motor->SetTransmissionRatio(19); - - br_motor->ReInitPID(omega_pid_init, driver::DjiMotorBase::OMEGA); - br_motor->SetMode(driver::DjiMotorBase::OMEGA); - br_motor->SetTransmissionRatio(19); - - driver::DjiMotorBase* motors[control::FourWheel::motor_num]; - motors[control::FourWheel::front_left] = fl_motor; - motors[control::FourWheel::front_right] = fr_motor; - motors[control::FourWheel::back_left] = bl_motor; - motors[control::FourWheel::back_right] = br_motor; - - control::chassis_t chassis_data; - chassis_data.motors = motors; - chassis_data.model = control::CHASSIS_MECANUM_WHEEL; - chassis = new control::Chassis(chassis_data); - - sbus = new remote::SBUS(&huart1); - HAL_Delay(300); -} - -void RM_RTOS_Default_Task(const void* args) { - UNUSED(args); - - osDelay(500); // DBUS initialization needs time - - while (true) { - const float ratio = 1.0f / 660.0f * 6 * PI; - chassis->SetSpeed(-sbus->ch1 * ratio, sbus->ch2 * ratio, sbus->ch4 * ratio); - - // Kill switch - if (sbus->ch5 >= 550) { - RM_ASSERT_TRUE(false, "Operation killed"); - } - - chassis->SetPower(false, 30, 20, 60); - chassis->Update(); - osDelay(10); - } -} diff --git a/examples/DJI_Board_TypeA_general/dbus/CMakeLists.txt b/examples/DJI_Board_TypeA_general/dbus/CMakeLists.txt deleted file mode 100644 index 45816a8d..00000000 --- a/examples/DJI_Board_TypeA_general/dbus/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -project(example_dbus_${BOARD_NAME} ASM C CXX) - -uicrm_add_arm_executable(${PROJECT_NAME} - TARGET ${BOARD_NAME} - SOURCES main.cpp) - diff --git a/examples/DJI_Board_TypeA_general/dbus/main.cpp b/examples/DJI_Board_TypeA_general/dbus/main.cpp deleted file mode 100644 index 7d289410..00000000 --- a/examples/DJI_Board_TypeA_general/dbus/main.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "main.h" - -#include "bsp_print.h" -#include "cmsis_os.h" -#include "dji_dbus.h" - -static remote::DBUS* dbus; - -void RM_RTOS_Init(void) { - print_use_uart(&huart8); - dbus = new remote::DBUS(&huart1); -} - -void RM_RTOS_Default_Task(const void* arguments) { - UNUSED(arguments); - - // NOTE(alvin): print is split because of stack usage is almost reaching - // limits - while (true) { - set_cursor(0, 0); - clear_screen(); - print( - "CH0: %-4d CH1: %-4d CH2: %-4d CH3: %-4d \r\nSWL: %d SWR: %d " - "TWL: %d " - "@ %d " - "ms\r\n", - dbus->ch0, - dbus->ch1, - dbus->ch2, - dbus->ch3, - dbus->swl, - dbus->swr, - dbus->ch4, - dbus->GetLastUptime() - ); - print( - "W: %d A: %d S: %d D: %d\r\n", - dbus->keyboard.bit.W, - dbus->keyboard.bit.A, - dbus->keyboard.bit.S, - dbus->keyboard.bit.D - ); - print( - "Q: %d E: %d R: %d F: %d G: %d\r\n", - dbus->keyboard.bit.Q, - dbus->keyboard.bit.E, - dbus->keyboard.bit.R, - dbus->keyboard.bit.F, - dbus->keyboard.bit.G - ); - print( - "Z: %d X: %d C: %d V: %d B: %d\r\n", - dbus->keyboard.bit.Z, - dbus->keyboard.bit.X, - dbus->keyboard.bit.C, - dbus->keyboard.bit.V, - dbus->keyboard.bit.B - ); - print("SHIFT: %d CTRL: %d\r\n", dbus->keyboard.bit.SHIFT, dbus->keyboard.bit.CTRL); - print( - "Mouse: x: %d y: %d z: %d l: %d r: %d\r\n", - dbus->mouse.x, - dbus->mouse.y, - dbus->mouse.z, - dbus->mouse.l, - dbus->mouse.r - ); - - osDelay(50); - } -} diff --git a/examples/DJI_Board_TypeA_general/gimbal/typeA.cpp b/examples/DJI_Board_TypeA_general/gimbal/typeA.cpp index dc43be2a..95c67b6e 100644 --- a/examples/DJI_Board_TypeA_general/gimbal/typeA.cpp +++ b/examples/DJI_Board_TypeA_general/gimbal/typeA.cpp @@ -26,7 +26,7 @@ #include "bsp_os.h" #include "bsp_spi.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "gimbal.h" #include "heater.h" #include "main.h" @@ -88,7 +88,7 @@ void imuUpdateTask(void* arguments) { static bsp::CAN* can1 = nullptr; static bsp::CAN* can2 = nullptr; -static remote::DBUS* dbus = nullptr; +static controller::DBUS* dbus = nullptr; static driver::DjiMotorBase* pitch_motor = nullptr; static driver::DjiMotorBase* yaw_motor = nullptr; @@ -120,11 +120,16 @@ const osThreadAttr_t gimbalTaskAttribute = osThreadId_t gimbalTaskHandle; void gimbalTask(void* arg) { + using enum controller::ThreePositionSwitch; + UNUSED(arg); print("Wait for beginning signal...\r\n"); while (true) { - if (dbus->keyboard.bit.V || dbus->swr == remote::DOWN) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.keyboard.bit.V || dbus_state.right_switch == Down) { break; } osDelay(100); @@ -159,19 +164,24 @@ void gimbalTask(void* arg) { float pitch_target = 0, yaw_target = 0; while (true) { - if (dbus->keyboard.bit.B || dbus->swl == remote::DOWN) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.keyboard.bit.B || dbus_state.left_switch == Down) { while (true) { - if (dbus->keyboard.bit.V) { + dbus->GetState(dbus_state); + + if (dbus_state.keyboard.bit.V) { break; } osDelay(10); } } - pitch_ratio = dbus->mouse.y / 32767.0 * 7.5 / 7.0; - yaw_ratio = -dbus->mouse.x / 32767.0 * 7.5 / 7.0; - pitch_ratio = -dbus->ch3 / 18000.0 / 7.0; - yaw_ratio = dbus->ch2 / 18000.0 / 7.0; + pitch_ratio = dbus_state.mouse.y / 32767.0 * 7.5 / 7.0; + yaw_ratio = -dbus_state.mouse.x / 32767.0 * 7.5 / 7.0; + pitch_ratio = -dbus_state.channels[3] / 18000.0 / 7.0; + yaw_ratio = dbus_state.channels[2] / 18000.0 / 7.0; pitch_target = clip(pitch_ratio, -gimbal_param->pitch_max_, gimbal_param->pitch_max_); yaw_target = clip(yaw_ratio, -gimbal_param->yaw_max_, gimbal_param->yaw_max_); @@ -194,7 +204,7 @@ void RM_RTOS_Init(void) { can1 = new bsp::CAN(&hcan1, true); can2 = new bsp::CAN(&hcan2, false); - dbus = new remote::DBUS(&huart1); + dbus = new controller::DBUS(&huart1); imu_cs = new bsp::GPIO(ONBOARD_IMU_CS_GROUP, ONBOARD_IMU_CS_PIN); mpu6500_it = new bsp::GPIT(MPU6500_IT_Pin); @@ -309,7 +319,10 @@ void RM_RTOS_Threads_Init(void) { void KillAll() { RM_EXPECT_TRUE(false, "Operation killed\r\n"); while (true) { - if (dbus->keyboard.bit.V) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.keyboard.bit.V) { break; } pitch_motor->Disable(); @@ -320,11 +333,16 @@ void KillAll() { } void RM_RTOS_Default_Task(const void* arg) { + using enum controller::ThreePositionSwitch; + UNUSED(arg); mpu6500->RegisterCallback(MPU6500ReceiveDone); while (true) { - if (dbus->keyboard.bit.B || dbus->swl == remote::DOWN) + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.keyboard.bit.B || dbus_state.left_switch == Down) KillAll(); set_cursor(0, 0); @@ -345,8 +363,19 @@ void RM_RTOS_Default_Task(const void* arg) { print("\r\n"); - print("CH0: %-4d CH1: %-4d CH2: %-4d CH3: %-4d ", dbus->ch0, dbus->ch1, dbus->ch2, dbus->ch3); - print("SWL: %d SWR: %d @ %d ms\r\n", dbus->swl, dbus->swr, dbus->GetLastUptime()); + print( + "CH0: %-4d CH1: %-4d CH2: %-4d CH3: %-4d ", + dbus_state.channels[0], + dbus_state.channels[1], + dbus_state.channels[2], + dbus_state.channels[3] + ); + print( + "SWL: %s SWR: %s @ %d ms\r\n", + controller::SwitchName(dbus_state.left_switch), + controller::SwitchName(dbus_state.right_switch), + dbus->GetLastValidTimeMs() + ); osDelay(100); } diff --git a/examples/DJI_Board_TypeA_general/motor/m2305.cpp b/examples/DJI_Board_TypeA_general/motor/m2305.cpp index 18003a4a..7086fd9e 100644 --- a/examples/DJI_Board_TypeA_general/motor/m2305.cpp +++ b/examples/DJI_Board_TypeA_general/motor/m2305.cpp @@ -22,7 +22,7 @@ #include "bsp_gpio.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" #include "utils.h" @@ -38,10 +38,10 @@ driver::PWMMotorBase* motor1; driver::PWMMotorBase* motor2; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; void RM_RTOS_Init() { - dbus = new remote::DBUS(&huart1); + dbus = new controller::DBUS(&huart1); print_use_uart(&huart8); motor1 = new driver::PWMMotorBase(&htim1, LEFT_MOTOR_PWM_CHANNEL, TIM_CLOCK_FREQ, MOTOR_OUT_FREQ, IDLE_THROTTLE); motor2 = new driver::PWMMotorBase(&htim1, RIGHT_MOTOR_PWM_CHANNEL, TIM_CLOCK_FREQ, MOTOR_OUT_FREQ, IDLE_THROTTLE); @@ -52,20 +52,25 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); bsp::GPIO key(KEY_GPIO_GROUP, KEY_GPIO_PIN); RampSource ramp_1 = RampSource(0, 0, 800, 0.001); RampSource ramp_2 = RampSource(0, 0, 800, 0.001); int current = 0; int state = 0; - int8_t last_state = remote::MID; + auto last_state = Mid; while (true) { - if (dbus->swl == remote::UP) { - if (last_state == remote::MID) - last_state = remote::UP; - } else if (dbus->swl == remote::MID) { - if (last_state == remote::UP) { - last_state = remote::MID; + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.left_switch == Up) { + if (last_state == Mid) + last_state = Up; + } else if (dbus_state.left_switch == Mid) { + if (last_state == Up) { + last_state = Mid; if (state == 0) { state = 1; diff --git a/examples/DJI_Board_TypeA_general/motor/servo_m2006.cpp b/examples/DJI_Board_TypeA_general/motor/servo_m2006.cpp index 3bd3eefd..a494c1db 100644 --- a/examples/DJI_Board_TypeA_general/motor/servo_m2006.cpp +++ b/examples/DJI_Board_TypeA_general/motor/servo_m2006.cpp @@ -23,20 +23,20 @@ #include "bsp_os.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" bsp::CAN* can2 = NULL; driver::DjiMotorBase* motor1 = NULL; driver::ServoMotor* load_servo = NULL; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; float load_step_angle = 2 * PI / 8; void RM_RTOS_Init() { bsp::SetHighresClockTimer(&htim7); HAL_Delay(200); print_use_uart(&huart8); - dbus = new remote::DBUS(&huart1); + dbus = new controller::DBUS(&huart1); can2 = new bsp::CAN(&hcan1, true); motor1 = new driver::Motor2006(can2, 0x201); driver::servo_t servo_data; @@ -56,27 +56,32 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); - int last_state = remote::MID; + auto last_state = Mid; while (true) { - if (last_state != dbus->swl && dbus->swl == remote::MID) { - if (last_state == remote::UP) { + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (last_state != dbus_state.left_switch && dbus_state.left_switch == Mid) { + if (last_state == Up) { load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); - } else if (last_state == remote::DOWN) { + } else if (last_state == Down) { load_servo->SetTarget(load_servo->GetTarget() - load_step_angle); } } else { - if (dbus->ch3 > 0) { + if (dbus_state.channels[3] > 0) { load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); - } else if (dbus->ch3 < 0) { + } else if (dbus_state.channels[3] < 0) { load_servo->SetTarget(load_servo->GetTarget() - load_step_angle); } } load_servo->CalcOutput(); - last_state = dbus->swl; + last_state = dbus_state.left_switch; osDelay(1); } } diff --git a/examples/DJI_Board_TypeA_general/motor/servo_m3508.cpp b/examples/DJI_Board_TypeA_general/motor/servo_m3508.cpp index 2d91ef4e..757d3810 100644 --- a/examples/DJI_Board_TypeA_general/motor/servo_m3508.cpp +++ b/examples/DJI_Board_TypeA_general/motor/servo_m3508.cpp @@ -23,20 +23,20 @@ #include "bsp_os.h" #include "bsp_print.h" #include "cmsis_os.h" -#include "dji_dbus.h" +#include "dbus.h" #include "main.h" bsp::CAN* can1 = NULL; driver::DjiMotorBase* motor1 = NULL; driver::ServoMotor* load_servo = NULL; -remote::DBUS* dbus = nullptr; +controller::DBUS* dbus = nullptr; float load_step_angle = 2 * PI / 8; void RM_RTOS_Init() { bsp::SetHighresClockTimer(&htim7); HAL_Delay(200); print_use_uart(&huart8); - dbus = new remote::DBUS(&huart1); + dbus = new controller::DBUS(&huart1); can1 = new bsp::CAN(&hcan1, true); motor1 = new driver::Motor2006(can1, 0x201); @@ -56,17 +56,22 @@ void RM_RTOS_Init() { } void RM_RTOS_Default_Task(const void* args) { + using enum controller::ThreePositionSwitch; + UNUSED(args); - int last_state = remote::MID; + auto last_state = Mid; int state = 0; while (true) { - if (dbus->swl == remote::UP) { - if (last_state == remote::MID) - last_state = remote::UP; - } else if (dbus->swl == remote::MID) { - if (last_state == remote::UP) { - last_state = remote::MID; + controller::DbusFrame dbus_state{}; + dbus->GetState(dbus_state); + + if (dbus_state.left_switch == Up) { + if (last_state == Mid) + last_state = Up; + } else if (dbus_state.left_switch == Mid) { + if (last_state == Up) { + last_state = Mid; load_servo->SetTarget(load_servo->GetTarget() + load_step_angle); if (state == 0) { state = 1; diff --git a/examples/DJI_Board_TypeA_general/referee/CMakeLists.txt b/examples/DJI_Board_TypeA_general/referee/CMakeLists.txt index 88e8e8d0..9fce1431 100644 --- a/examples/DJI_Board_TypeA_general/referee/CMakeLists.txt +++ b/examples/DJI_Board_TypeA_general/referee/CMakeLists.txt @@ -3,7 +3,3 @@ project(example_referee_${BOARD_NAME} ASM C CXX) uicrm_add_arm_executable(${PROJECT_NAME} TARGET ${BOARD_NAME} SOURCES main.cpp) - -uicrm_add_arm_executable(${PROJECT_NAME}_rc - TARGET ${BOARD_NAME} - SOURCES rc.cpp) \ No newline at end of file diff --git a/examples/DJI_Board_TypeA_general/referee/rc.cpp b/examples/DJI_Board_TypeA_general/referee/rc.cpp deleted file mode 100644 index 8ed031cc..00000000 --- a/examples/DJI_Board_TypeA_general/referee/rc.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "bsp_print.h" -#include "bsp_uart.h" -#include "cmsis_os.h" -#include "dji_dbus.h" -#include "main.h" -#include "protocol.h" - -communication::Referee* referee = nullptr; -bsp::UART* referee_uart = nullptr; - -communication::Referee* refereeRc = nullptr; -bsp::UART* refereeRc_uart = nullptr; - -void RM_RTOS_Init(void) { - print_use_uart(&huart8); - - referee_uart = new bsp::UART(&huart3); - referee_uart->SetupRx(300); - referee_uart->SetupTx(300); - - refereeRc_uart = new bsp::UART(&huart6); - refereeRc_uart->SetupRx(300); - refereeRc_uart->SetupTx(300); - - referee = new communication::Referee(referee_uart); - - refereeRc = new communication::Referee(refereeRc_uart); -} - -void RM_RTOS_Threads_Init(void) { -} - -void RM_RTOS_Default_Task(const void* argument) { - UNUSED(argument); - - while (true) { - set_cursor(0, 0); - clear_screen(); - // print("Chassis Volt: %.3f\r\n", referee->power_heat_data.chassis_volt / 1000.0); - // print("Chassis Curr: %.3f\r\n", referee->power_heat_data.chassis_current / - // 1000.0); print("Chassis Power: %.3f\r\n", referee->power_heat_data.chassis_power); - // print("Chassis Power Limit: %d\r\n", - // referee->game_robot_status.chassis_power_limit); print("\r\n"); print("Shooter - // Cooling Heat: %hu\r\n", - // referee->power_heat_data.shooter_id1_17mm_cooling_heat); - // print("Bullet Frequency: %hhu\r\n", referee->shoot_data.bullet_freq); - // print("Bullet Speed: %.3f\r\n", referee->shoot_data.bullet_speed); - // print("\r\n"); - // print("Current HP %d/%d\n", referee->game_robot_status.remain_HP, - // referee->game_robot_status.max_HP); - // print("Remain bullet %d\n", referee->bullet_remaining.bullet_remaining_num_17mm); - remote::keyboard_t keyboard = referee->remote_control.keyboard; - remote::mouse_t mouse = referee->remote_control.mouse; - print( - "W: %d A: %d S: %d D: %d\r\n" - "Q: %d E: %d R: %d F: %d G: %d\r\n" - "Z: %d X: %d C: %d V: %d B: %d\r\n" - "SHIFT: %d CTRL: %d\r\n" - "Mouse: x: %d y: %d z: %d l: %d r: %d\r\n", - keyboard.bit.W, - keyboard.bit.A, - keyboard.bit.S, - keyboard.bit.D, - keyboard.bit.Q, - keyboard.bit.E, - keyboard.bit.R, - keyboard.bit.F, - keyboard.bit.G, - keyboard.bit.Z, - keyboard.bit.X, - keyboard.bit.C, - keyboard.bit.V, - keyboard.bit.B, - keyboard.bit.SHIFT, - keyboard.bit.CTRL, - mouse.x, - mouse.y, - mouse.z, - mouse.l, - mouse.r - ); - osDelay(1); - } -} \ No newline at end of file From 01f51d7dbecbf30db1e69d4b6bb9aaf8b153400f Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:21 +0800 Subject: [PATCH 15/17] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=20protocol?= =?UTF-8?q?=20=E4=B8=8E=E6=9E=84=E5=BB=BA=E7=B3=BB=E7=BB=9F=E5=88=B0=20con?= =?UTF-8?q?troller=20=E5=B9=B6=E6=B8=85=E7=90=86=E6=97=A7=E9=81=A5?= =?UTF-8?q?=E6=8E=A7=E6=A0=B8=E5=BF=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ample_dbus_DJI_Board_TypeA_general_elf.xml | 10 -- ...ample_dbus_DJI_Board_TypeC_general_elf.xml | 10 -- .../example_dbus_DM_MC01_general_elf.xml | 10 -- .../example_dbus_DM_MC02_general_elf.xml | 10 -- ...referee_DJI_Board_TypeC_general_rc_elf.xml | 10 -- ...ample_sbus_DJI_Board_TypeC_general_elf.xml | 10 -- boards/CMakeLists.txt | 1 - boards/drivers/CMakeLists.txt | 3 +- boards/drivers/include/dji_dbus.h | 124 --------------- boards/drivers/include/dji_remote.h | 108 ------------- boards/drivers/include/protocol.h | 24 +-- boards/drivers/include/sbus.h | 97 ------------ boards/drivers/src/dji_dbus.cpp | 83 ---------- boards/drivers/src/protocol.cpp | 35 ++--- boards/drivers/src/sbus.cpp | 109 ------------- boards/remote/CMakeLists.txt | 9 -- .../include/protocols/refereerc_receiver.h | 145 ------------------ .../remote/include/protocols/sbus_receiver.h | 126 --------------- boards/remote/src/protocols/sbus_receiver.cpp | 99 ------------ 19 files changed, 19 insertions(+), 1004 deletions(-) delete mode 100644 .idea/runConfigurations/example_dbus_DJI_Board_TypeA_general_elf.xml delete mode 100644 .idea/runConfigurations/example_dbus_DJI_Board_TypeC_general_elf.xml delete mode 100644 .idea/runConfigurations/example_dbus_DM_MC01_general_elf.xml delete mode 100644 .idea/runConfigurations/example_dbus_DM_MC02_general_elf.xml delete mode 100644 .idea/runConfigurations/example_referee_DJI_Board_TypeC_general_rc_elf.xml delete mode 100644 .idea/runConfigurations/example_sbus_DJI_Board_TypeC_general_elf.xml delete mode 100644 boards/drivers/include/dji_dbus.h delete mode 100644 boards/drivers/include/dji_remote.h delete mode 100644 boards/drivers/include/sbus.h delete mode 100644 boards/drivers/src/dji_dbus.cpp delete mode 100644 boards/drivers/src/sbus.cpp delete mode 100644 boards/remote/CMakeLists.txt delete mode 100644 boards/remote/include/protocols/refereerc_receiver.h delete mode 100644 boards/remote/include/protocols/sbus_receiver.h delete mode 100644 boards/remote/src/protocols/sbus_receiver.cpp diff --git a/.idea/runConfigurations/example_dbus_DJI_Board_TypeA_general_elf.xml b/.idea/runConfigurations/example_dbus_DJI_Board_TypeA_general_elf.xml deleted file mode 100644 index e8b47ba8..00000000 --- a/.idea/runConfigurations/example_dbus_DJI_Board_TypeA_general_elf.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/example_dbus_DJI_Board_TypeC_general_elf.xml b/.idea/runConfigurations/example_dbus_DJI_Board_TypeC_general_elf.xml deleted file mode 100644 index 1d5fc340..00000000 --- a/.idea/runConfigurations/example_dbus_DJI_Board_TypeC_general_elf.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/example_dbus_DM_MC01_general_elf.xml b/.idea/runConfigurations/example_dbus_DM_MC01_general_elf.xml deleted file mode 100644 index 4e0c0e77..00000000 --- a/.idea/runConfigurations/example_dbus_DM_MC01_general_elf.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/example_dbus_DM_MC02_general_elf.xml b/.idea/runConfigurations/example_dbus_DM_MC02_general_elf.xml deleted file mode 100644 index ff206d64..00000000 --- a/.idea/runConfigurations/example_dbus_DM_MC02_general_elf.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/example_referee_DJI_Board_TypeC_general_rc_elf.xml b/.idea/runConfigurations/example_referee_DJI_Board_TypeC_general_rc_elf.xml deleted file mode 100644 index adf94785..00000000 --- a/.idea/runConfigurations/example_referee_DJI_Board_TypeC_general_rc_elf.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/example_sbus_DJI_Board_TypeC_general_elf.xml b/.idea/runConfigurations/example_sbus_DJI_Board_TypeC_general_elf.xml deleted file mode 100644 index 1a671c2b..00000000 --- a/.idea/runConfigurations/example_sbus_DJI_Board_TypeC_general_elf.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/boards/CMakeLists.txt b/boards/CMakeLists.txt index b9be9a4b..2fa82b5b 100644 --- a/boards/CMakeLists.txt +++ b/boards/CMakeLists.txt @@ -1,7 +1,6 @@ add_subdirectory(base) add_subdirectory(platform) add_subdirectory(algorithm) -add_subdirectory(remote) add_subdirectory(drivers) add_subdirectory(components) add_subdirectory(third_party) diff --git a/boards/drivers/CMakeLists.txt b/boards/drivers/CMakeLists.txt index 2543a1d4..863160ba 100644 --- a/boards/drivers/CMakeLists.txt +++ b/boards/drivers/CMakeLists.txt @@ -4,11 +4,10 @@ file(GLOB_RECURSE CRC_CHECK_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/c file(GLOB_RECURSE DRIVER_SOURCES_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.*) set(DRIVER_SOURCES ${DRIVER_SOURCES_FILES} - ${UICRM_REMOTE_SOURCES} ${CRC_CHECK_SOURCES}) set(DRIVER_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include - ${UICRM_REMOTE_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include/controller ${CMAKE_CURRENT_SOURCE_DIR}/include/Motor ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/crc_check/include) diff --git a/boards/drivers/include/dji_dbus.h b/boards/drivers/include/dji_dbus.h deleted file mode 100644 index b97f55a4..00000000 --- a/boards/drivers/include/dji_dbus.h +++ /dev/null @@ -1,124 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#pragma once - -#include "bsp_uart.h" -#include "connection_driver.h" -#include "dji_remote.h" - -namespace remote { - - typedef enum { - UP = 1, - DOWN = 2, - MID = 3, - } switch_t; - - // inline uint8_t operator- (const switch_t a, const switch_t b) - // {return static_cast(a) - static_cast(b);} - - /** - * @brief DBUS 遥控器接收类 - * @note 用于DJI DR16接收机 - */ - /** - * @brief DBUS remote receiver class - * @note used for DJI DR16 receiver - */ - class DBUS : public bsp::UART, public driver::ConnectionDriver { - public: - /** - * @brief 构造函数 - * @note 和uart类似,dbus需要时间进行初始化 - * - * @param huart uart实例 - */ - /** - * @brief intialize DBUS the same way as a generic UART peripheral - * @note like uart, dbus needs time to initialize - * - * @param huart uart instance - */ - DBUS(UART_HandleTypeDef* huart); - - // Add custom rx data handler - void RxCompleteCallback() override final; - - // rocker channel information - /** - * @note 遥控器的样式 - * - * @note the style of the remote - * - * C4( - * SWL* *SWR - * C3-^ ^-C1 - * C2-< >+ -< >+C0 - * +v v+ - * - */ - /** - * @brief 获取右摇杆的x轴值 - */ - volatile int16_t ch0; - /** - * @brief 获取右摇杆的y轴值 - */ - volatile int16_t ch1; - /** - * @brief 获取左摇杆的x轴值 - */ - volatile int16_t ch2; - /** - * @brief 获取左摇杆的y轴值 - */ - volatile int16_t ch3; - - // left and right switch information - /** - * @brief 获取左拨杆的状态 - */ - volatile switch_t swl; - /** - * @brief 获取右拨杆的状态 - */ - volatile switch_t swr; - // left track wheel - /** - * @brief 获取左波轮的x轴值 - */ - volatile int16_t ch4; - // mouse movement and button information - /** - * @brief 获取鼠标的数据,仅限于DT7连接上电脑之后 - */ - mouse_t mouse; - // keyboard key information - /** - * @brief 获取键盘的数据,仅限于DT7连接上电脑之后 - */ - keyboard_t keyboard; - - static const int16_t ROCKER_MIN = -660; - static const int16_t ROCKER_MAX = 660; - }; - -} /* namespace remote */ diff --git a/boards/drivers/include/dji_remote.h b/boards/drivers/include/dji_remote.h deleted file mode 100644 index 31850f57..00000000 --- a/boards/drivers/include/dji_remote.h +++ /dev/null @@ -1,108 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#pragma once - -#include "main.h" - -namespace remote { - typedef struct { - int16_t x; - int16_t y; - int16_t z; - uint8_t l; - uint8_t r; - } __packed mouse_t; - -#define mouse_xy_max 32767.0 - - typedef union { - uint16_t code; - struct { - uint16_t W : 1; // 前 - uint16_t S : 1; // 后 - uint16_t A : 1; // 左 - uint16_t D : 1; // 右 - uint16_t SHIFT : 1; // boost - uint16_t CTRL : 1; // 切换 小陀螺/自瞄/坦克/标准 模式 - uint16_t Q : 1; // 小陀螺加速/减速 - uint16_t E : 1; // 小陀螺加速/减速 - uint16_t R : 1; // - uint16_t F : 1; // - uint16_t G : 1; // - uint16_t Z : 1; // 摩擦轮 - uint16_t X : 1; // - uint16_t C : 1; // 清除自定义UI - uint16_t V : 1; // 强制刷新自定义UI - uint16_t B : 1; // - } __packed bit; - } __packed keyboard_t; - - typedef struct vt13_remote_t { - uint64_t ch0 : 11; - uint64_t ch1 : 11; - uint64_t ch2 : 11; - uint64_t ch3 : 11; - enum vt13_mode_t : uint64_t { - MODE_C = 0, - MODE_N = 1, - MODE_S = 2, - } mode_sw : 2; - uint64_t pause : 1; - uint64_t swl : 1; - uint64_t swr : 1; - uint64_t ch4 : 11; - uint64_t trigger : 1; - constexpr static uint16_t ROCKER_MID = 1024; - constexpr static uint16_t ROCKER_RANGE = 660; - } __packed vt13_remote_t; - - typedef struct vt13_mouse_t { - int16_t x; - int16_t y; - int16_t roll; - struct { - uint8_t l : 1; - uint8_t reserved : 1; // 不知道为什么,VT13目前的包中间空了一位 - uint8_t r : 1; - uint8_t mid : 1; - }; - explicit operator mouse_t() const { - mouse_t result; - result.x = x; - result.y = y; - result.z = roll; - result.l = l; // shoot - result.r = r; // unload - return result; - } - } __packed vt13_mouse_t; - - typedef struct vt13_packet_t { - constexpr static uint8_t SOF = 0xA9; - constexpr static uint8_t CMD = 0x53; - uint8_t sof; // 0xA9 - uint8_t cmd; // 0x53 - vt13_remote_t remote; - vt13_mouse_t mouse; - keyboard_t keyboard; - uint16_t crc16; - } __packed vt13_packet_t; -} // namespace remote \ No newline at end of file diff --git a/boards/drivers/include/protocol.h b/boards/drivers/include/protocol.h index 93c963cf..1c6a7b30 100644 --- a/boards/drivers/include/protocol.h +++ b/boards/drivers/include/protocol.h @@ -25,8 +25,7 @@ #include "bsp_uart.h" #include "bsp_usb.h" #include "connection_driver.h" -#include "dji_remote.h" -#include "protocols/refereerc_receiver.h" +#include "refereerc.h" namespace communication { @@ -47,7 +46,9 @@ namespace communication { * @return true for success; false for failure */ bool Receive(package_t package); - const remote::RefereeRcReceiver& Vt13() const { return refereerc_receiver_; } + const controller::RefereeRC& RefereeRc() const { + return refereerc_; + } /** * @brief Generate the package to be sent according to the command and save to the internal @@ -65,8 +66,6 @@ namespace communication { uint8_t bufferRx[MAX_FRAME_LEN] = {0}; uint8_t bufferTx[MAX_FRAME_LEN] = {0}; - // Called only for a complete VT13 frame accepted by the new receiver. - virtual void ProcessVt13Rx(const uint8_t* data, size_t size); /** * @brief verify the header of frame with crc8 @@ -124,7 +123,7 @@ namespace communication { private: size_t rx_used_ = 0; - remote::RefereeRcReceiver refereerc_receiver_; + controller::RefereeRC refereerc_; void DiscardRx(size_t size); void ResyncRx(); }; @@ -533,13 +532,6 @@ namespace communication { uint8_t cmd_source; } __packed map_command_t; - // Obsolete 0x0304 layout, retained only for old robot source compatibility. - typedef struct { - remote::mouse_t mouse; - remote::keyboard_t keyboard; - uint16_t reserved; - } __packed remote_control_t; - /* ===== MAP_ROBOT_DATA 0x0305 ===== */ typedef struct { uint16_t target_robot_id; @@ -608,14 +600,11 @@ namespace communication { custom_robot_data_t custom_robot_data{}; // 0x0302 map_command_t map_command{}; // 0x0303 - remote_control_t remote_control{}; // Obsolete: never updated by Receive; migrate old callers. map_robot_data_t map_robot_data{}; // 0x0305 custom_client_data_t custom_client_data{}; // 0x0306 custom_client_map_command_t custom_client_map_command{}; // 0x0307 custom_info_t custom_info{}; // 0x0308 - remote::vt13_packet_t vt13_packet{}; - void PrepareUIContent(content graph_content); private: @@ -639,7 +628,6 @@ namespace communication { */ int ProcessDataTx(int cmd_id, uint8_t* data) final; - void ProcessVt13Rx(const uint8_t* data, size_t size) override; content graph_content_ = NO_GRAPH; }; @@ -858,4 +846,4 @@ namespace communication { #endif -} /* namespace communication */ \ No newline at end of file +} /* namespace communication */ diff --git a/boards/drivers/include/sbus.h b/boards/drivers/include/sbus.h deleted file mode 100644 index 656a6943..00000000 --- a/boards/drivers/include/sbus.h +++ /dev/null @@ -1,97 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#pragma once - -#include "bsp_uart.h" -#include "connection_driver.h" - -namespace remote { - - /** - * @brief SBUS 遥控器接收类 - * @note 用于支持SBUS的接收机 - */ - /** - * @brief DBUS remote receiver class - * @note used for DJI DR16 receiver - */ - class SBUS : public bsp::UART, public driver::ConnectionDriver { - public: - /** - * @brief 构造函数 - * @note 和uart类似,sbus需要时间进行初始化 - * - * @param huart uart实例 - */ - /** - * @brief intialize SBUS the same way as a generic UART peripheral - * @note like uart, sbus needs time to initialize - * - * @param huart uart instance - */ - SBUS(UART_HandleTypeDef* huart); - - // Add custom rx data handler - void RxCompleteCallback() override final; - - // rocker channel information - /** - * @note 遥控器的样式 - * - * @note the style of the remote - * - * C4( - * SWL* *SWR - * C3-^ ^-C1 - * C2-< >+ -< >+C0 - * +v v+ - * - */ - - volatile int16_t ch1; - volatile int16_t ch2; - volatile int16_t ch3; - volatile int16_t ch4; - volatile int16_t ch5; - volatile int16_t ch6; - volatile int16_t ch7; - volatile int16_t ch8; - volatile int16_t ch9; - volatile int16_t ch10; - volatile int16_t ch11; - volatile int16_t ch12; - volatile int16_t ch13; - volatile int16_t ch14; - volatile int16_t ch15; - volatile int16_t ch16; - volatile uint8_t flag; - - // timestamp of the update interrupt - /** - * @brief 获取更新中断的时间戳 - */ - uint32_t timestamp; - - static const int16_t ROCKER_MIN = -1023; - static const int16_t ROCKER_MAX = 1023; - }; - -} /* namespace remote */ diff --git a/boards/drivers/src/dji_dbus.cpp b/boards/drivers/src/dji_dbus.cpp deleted file mode 100644 index 5dfce5bb..00000000 --- a/boards/drivers/src/dji_dbus.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "dji_dbus.h" - -#include -#include - -#include "bsp_error_handler.h" - -/* rocker range and deadzones */ -#define RC_ROCKER_MID 1024 -#define RC_ROCKER_ZERO_DRIFT 10 // Range of possible drift around initial position -// Range of possible drift around min or max position - -namespace remote { - - // helper struct for decoding raw bytes - typedef struct { - /* rocker channel information */ - uint16_t ch0 : 11; // S1* *S2 - uint16_t ch1 : 11; // C3-^ ^-C1 - uint16_t ch2 : 11; // C2-< >+ -< >+C0 - uint16_t ch3 : 11; // +v v+ - /* left and right switch information */ - uint8_t swr : 2; - uint8_t swl : 2; - /* mouse movement and button information */ - remote::mouse_t mouse; - /* keyboard key information */ - remote::keyboard_t keyboard; - uint16_t ch4 : 11; - } __packed dbus_t; - - DBUS::DBUS(UART_HandleTypeDef* huart) : bsp::UART(huart) { - SetupRx(sizeof(dbus_t) + 1); - } - - void DBUS::RxCompleteCallback() { - Heartbeat(); - - uint8_t* data; - // data frame misalignment - if (this->Read(&data) != sizeof(dbus_t)) - return; - - // re-interpret the data buffer and decode into class properties - dbus_t* repr = reinterpret_cast(data); - this->ch0 = repr->ch0 - RC_ROCKER_MID; - this->ch1 = repr->ch1 - RC_ROCKER_MID; - this->ch2 = repr->ch2 - RC_ROCKER_MID; - this->ch3 = repr->ch3 - RC_ROCKER_MID; - this->ch4 = repr->ch4 - RC_ROCKER_MID; - this->ch0 = abs(this->ch0) <= RC_ROCKER_ZERO_DRIFT ? 0 : this->ch0; - this->ch1 = abs(this->ch1) <= RC_ROCKER_ZERO_DRIFT ? 0 : this->ch1; - this->ch2 = abs(this->ch2) <= RC_ROCKER_ZERO_DRIFT ? 0 : this->ch2; - this->ch3 = abs(this->ch3) <= RC_ROCKER_ZERO_DRIFT ? 0 : this->ch3; - this->ch4 = abs(this->ch4) <= RC_ROCKER_ZERO_DRIFT ? 0 : this->ch4; - this->swl = static_cast(repr->swl); - this->swr = static_cast(repr->swr); - - memcpy(&this->mouse, &repr->mouse, sizeof(mouse_t)); - memcpy(&this->keyboard, &repr->keyboard, sizeof(keyboard_t)); - } - -} /* namespace remote */ diff --git a/boards/drivers/src/protocol.cpp b/boards/drivers/src/protocol.cpp index 3881fbc3..bf6baf09 100644 --- a/boards/drivers/src/protocol.cpp +++ b/boards/drivers/src/protocol.cpp @@ -24,7 +24,6 @@ #include "bsp_usb.h" #include "crc_check.h" -#include "dji_remote.h" #include "bsp_os.h" static const uint8_t SOF = 0xA5; @@ -42,16 +41,12 @@ namespace communication { void Protocol::ResyncRx() { size_t next = 1; while (next < rx_used_ && bufferRx[next] != SOF && - bufferRx[next] != remote::RefereeRcReceiver::SOF) { + bufferRx[next] != controller::RefereeRC::SOF) { ++next; } DiscardRx(next); } - void Protocol::ProcessVt13Rx(const uint8_t* data, size_t size) { - ProcessDataRx(remote::RefereeRcReceiver::CMD, data, static_cast(size)); - } - bool Protocol::Receive(package_t package) { if (!package.data || package.length <= 0) return false; // Preserve the legacy link heartbeat. Input-source health is independent. @@ -59,34 +54,33 @@ namespace communication { const uint32_t now_ms = bsp::GetHighresTickMilliSec(); for (int i = 0; i < package.length; ++i) { const auto byte = package.data[i]; - if (!rx_used_ && byte != SOF && byte != remote::RefereeRcReceiver::SOF) continue; + if (!rx_used_ && byte != SOF && byte != controller::RefereeRC::SOF) continue; // A5 lengths are capped below; every full candidate is consumed or // resynchronized before the next append, keeping this buffer bounded. bufferRx[rx_used_++] = byte; while (rx_used_) { - if (bufferRx[0] != SOF && bufferRx[0] != remote::RefereeRcReceiver::SOF) { + if (bufferRx[0] != SOF && bufferRx[0] != controller::RefereeRC::SOF) { ResyncRx(); continue; } - if (bufferRx[0] == remote::RefereeRcReceiver::SOF) { + if (bufferRx[0] == controller::RefereeRC::SOF) { if (rx_used_ < 2) break; - if (bufferRx[1] != remote::RefereeRcReceiver::CMD) { + if (bufferRx[1] != controller::RefereeRC::CMD) { ResyncRx(); continue; } - if (rx_used_ < remote::RefereeRcReceiver::FRAME_SIZE) break; + if (rx_used_ < controller::RefereeRC::FRAME_SIZE) break; // Protocol owns stream framing; the receiver owns VT13 // validation, decoding and the independent input timestamp. - refereerc_receiver_.ResetStream(); - const auto sequence = refereerc_receiver_.GetSequence(); - refereerc_receiver_.UpdateData(bufferRx, remote::RefereeRcReceiver::FRAME_SIZE, now_ms); - refereerc_receiver_.ResetStream(); - if (refereerc_receiver_.GetSequence() == sequence) { + refereerc_.ResetStream(); + const auto sequence = refereerc_.GetSequence(); + refereerc_.UpdateData(bufferRx, controller::RefereeRC::FRAME_SIZE, now_ms); + refereerc_.ResetStream(); + if (refereerc_.GetSequence() == sequence) { ResyncRx(); continue; } - ProcessVt13Rx(bufferRx, remote::RefereeRcReceiver::FRAME_SIZE); - DiscardRx(remote::RefereeRcReceiver::FRAME_SIZE); + DiscardRx(controller::RefereeRC::FRAME_SIZE); } else { if (rx_used_ < FRAME_HEADER_LEN) break; const int payload = int(bufferRx[1]) | (int(bufferRx[2]) << BYTE); @@ -294,11 +288,6 @@ namespace communication { return true; } - void Referee::ProcessVt13Rx(const uint8_t* data, size_t size) { - // Wire-compatible snapshot only; validation/decoding lives in RefereeRcReceiver. - if (size == sizeof(vt13_packet)) memcpy(&vt13_packet, data, size); - } - int Referee::ProcessDataTx(int cmd_id, uint8_t* data) { int data_len; switch (cmd_id) { diff --git a/boards/drivers/src/sbus.cpp b/boards/drivers/src/sbus.cpp deleted file mode 100644 index 756584d7..00000000 --- a/boards/drivers/src/sbus.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/*########################################################### - # Copyright (c) 2023-2024. BNU-HKBU UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ - -#include "sbus.h" - -#include -#include - -#include "bsp_error_handler.h" -#include "utils.h" - -/* rocker range and deadzones */ -#define SBUS_RC_ROCKER_MID 1024 -#define SBUS_RC_ROCKER_ZERO_DRIFT 10 // Range of possible drift around initial position -// Range of possible drift around min or max position - -namespace remote { - - // helper struct for decoding raw bytes - typedef struct { - uint8_t start : 8; - uint16_t ch1 : 11; - uint16_t ch2 : 11; - uint16_t ch3 : 11; - uint16_t ch4 : 11; - uint16_t ch5 : 11; - uint16_t ch6 : 11; - uint16_t ch7 : 11; - uint16_t ch8 : 11; - uint16_t ch9 : 11; - uint16_t ch10 : 11; - uint16_t ch11 : 11; - uint16_t ch12 : 11; - uint16_t ch13 : 11; - uint16_t ch14 : 11; - uint16_t ch15 : 11; - uint16_t ch16 : 11; - uint8_t flag : 8; - uint8_t end : 8; - } __packed sbus_t; - - SBUS::SBUS(UART_HandleTypeDef* huart) : bsp::UART(huart) { - SetupRx(sizeof(sbus_t) + 1); - } - - void SBUS::RxCompleteCallback() { - Heartbeat(); - - uint8_t* data; - // data frame misalignment - if (this->Read(&data) != sizeof(sbus_t)) - return; - - // re-interpret the data buffer and decode into class properties - sbus_t* repr = reinterpret_cast(data); - this->ch1 = clip(repr->ch1 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch2 = clip(repr->ch2 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch3 = clip(repr->ch3 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch4 = clip(repr->ch4 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch5 = clip(repr->ch5 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch6 = clip(repr->ch6 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch7 = clip(repr->ch7 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch8 = clip(repr->ch8 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch9 = clip(repr->ch9 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch10 = clip(repr->ch10 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch11 = clip(repr->ch11 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch12 = clip(repr->ch12 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch13 = clip(repr->ch13 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch14 = clip(repr->ch14 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch15 = clip(repr->ch15 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch16 = clip(repr->ch16 - SBUS_RC_ROCKER_MID, -660, 660); - this->ch1 = abs(this->ch1) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch1; - this->ch2 = abs(this->ch2) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch2; - this->ch3 = abs(this->ch3) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch3; - this->ch4 = abs(this->ch4) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch4; - this->ch5 = abs(this->ch5) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch5; - this->ch6 = abs(this->ch6) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch6; - this->ch7 = abs(this->ch7) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch7; - this->ch8 = abs(this->ch8) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch8; - this->ch9 = abs(this->ch9) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch9; - this->ch10 = abs(this->ch10) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch10; - this->ch11 = abs(this->ch11) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch11; - this->ch12 = abs(this->ch12) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch12; - this->ch13 = abs(this->ch13) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch13; - this->ch14 = abs(this->ch14) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch14; - this->ch15 = abs(this->ch15) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch15; - this->ch16 = abs(this->ch16) <= SBUS_RC_ROCKER_ZERO_DRIFT ? 0 : this->ch16; - this->flag = repr->flag; - this->timestamp = GetLastUptime(); - } - -} /* namespace remote */ diff --git a/boards/remote/CMakeLists.txt b/boards/remote/CMakeLists.txt deleted file mode 100644 index eb1a9dfd..00000000 --- a/boards/remote/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -set(UICRM_REMOTE_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/src/protocols/dbus_receiver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/protocols/sbus_receiver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/protocols/refereerc_receiver.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/controller/fs_i6x_receiver.cpp) - -# The board-specific driver libraries compile these sources with their own target settings. -set(UICRM_REMOTE_SOURCES ${UICRM_REMOTE_SOURCES} PARENT_SCOPE) -set(UICRM_REMOTE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE) diff --git a/boards/remote/include/protocols/refereerc_receiver.h b/boards/remote/include/protocols/refereerc_receiver.h deleted file mode 100644 index 1c72f5e3..00000000 --- a/boards/remote/include/protocols/refereerc_receiver.h +++ /dev/null @@ -1,145 +0,0 @@ -/*########################################################### -# Copyright (c) 2026-2027. BNBU/UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ -#pragma once - -#include - -#include "remote.h" - -namespace remote { - /** @brief VT13 模式编码;是否允许控制由本车逻辑决定。 */ - enum class Vt13Mode : uint8_t { - C = 0, ///< C 模式。 - N = 1, ///< N 模式。 - S = 2 ///< S 模式。 - }; - - /** @brief VT13 鼠标输入,保留协议中的原始有符号数值。 */ - struct Vt13MouseState { - int16_t x = 0; ///< 鼠标 X 轴输入。 - int16_t y = 0; ///< 鼠标 Y 轴输入。 - int16_t z = 0; ///< 鼠标滚轮输入。 - bool left = false; ///< 鼠标左键是否按下。 - bool right = false; ///< 鼠标右键是否按下。 - bool middle = false; ///< 鼠标中键是否按下。 - }; - - /** - * @brief VT13 键盘状态,提供完整位图 code 和命名按键位域 bit。 - * @details 位序与 VT13 协议及旧 keyboard_t 一致;多个按键可同时按下。 - * code 与 bit 共享两字节存储,code 默认为 0,各按键位 0 表示松开、1 表示按下。 - * @note 位域视图采用本项目 GCC/ARM 布局;线上数据仍按小端字节显式解码, - * 不将接收缓存强制转换为此类型。更换编译器平台须验证位域布局。 - */ - union Vt13KeyboardState { - uint16_t code = 0; ///< 完整 16 位按键位图,范围 0~65535。 - struct { - uint16_t W : 1; ///< bit0:W 键。 - uint16_t S : 1; ///< bit1:S 键。 - uint16_t A : 1; ///< bit2:A 键。 - uint16_t D : 1; ///< bit3:D 键。 - uint16_t SHIFT : 1; ///< bit4:SHIFT 键。 - uint16_t CTRL : 1; ///< bit5:CTRL 键。 - uint16_t Q : 1; ///< bit6:Q 键。 - uint16_t E : 1; ///< bit7:E 键。 - uint16_t R : 1; ///< bit8:R 键。 - uint16_t F : 1; ///< bit9:F 键。 - uint16_t G : 1; ///< bit10:G 键。 - uint16_t Z : 1; ///< bit11:Z 键。 - uint16_t X : 1; ///< bit12:X 键。 - uint16_t C : 1; ///< bit13:C 键。 - uint16_t V : 1; ///< bit14:V 键。 - uint16_t B : 1; ///< bit15:B 键。 - } __attribute__((packed)) bit; - } __attribute__((packed)); - static_assert(sizeof(Vt13KeyboardState) == 2, "VT13 keyboard must occupy two bytes"); - - /** @brief VT13 有效帧快照,通道减中心并处理死区,不包含本车控制映射。 */ - struct Vt13Frame { - /** - * @brief 五通道减去 1024,包含 ±10 死区;不缩放或额外限幅。 - * @details 输出范围 -660~660,中心为 0;顺序为右 X/Y、左 Y/X、拨轮。 - */ - std::array channels{}; - Vt13Mode mode = Vt13Mode::C; ///< 模式选择,不自动转换为协议失控标志。 - bool pause = false; ///< 暂停按钮状态。 - bool left_button = false; ///< 遥控器左侧按钮状态,与鼠标左键不同。 - bool right_button = false; ///< 遥控器右侧按钮状态,与鼠标右键不同。 - bool trigger = false; ///< 扳机状态。 - Vt13MouseState mouse{}; ///< 鼠标状态。 - Vt13KeyboardState keyboard{}; ///< 键盘状态,支持 code 和 bit 按键访问。 - uint16_t crc16 = 0; ///< 已通过校验的帧内 CRC16 值。 - }; - - /** - * @brief VT13 21 字节遥控协议接收器,无 UART、HAL 或系统时钟依赖。 - * @details 验证 0xA9 帧头、0x53 命令字、既有 CRC16、合法模式 0/1/2、 - * 五通道范围 364~1684,以及各占两位的鼠标左/右/中键编码 0/1。 - * 仅有效帧更新数据和独立在线时间,N/S 模式及暂停按钮不自动视为协议失控。 - * @note VT13 由图传链路承载;A5/A9 混合分帧位于 protocol.cpp,不属于本接收器职责。 - * 所有输入与读取须由接入层同步保护。 - */ - class RefereeRcReceiver final : public RemoteReceiver { - public: - static constexpr size_t FRAME_SIZE = 21; ///< 单帧长度,单位字节。 - static constexpr uint8_t SOF = 0xA9; ///< VT13 帧头。 - static constexpr uint8_t CMD = 0x53; ///< VT13 命令字。 - static constexpr uint16_t CHANNEL_MIN = 364; ///< 五通道原始值有效下限,包含边界。 - static constexpr uint16_t CHANNEL_MAX = 1684; ///< 五通道原始值有效上限,包含边界。 - static constexpr uint16_t CHANNEL_CENTER = 1024; - static constexpr int16_t CHANNEL_DEADZONE = 10; - /** @brief 继承基类构造,可传入在线超时毫秒数,默认 250。 */ - using RemoteReceiver::RemoteReceiver; - - /** - * @brief 输入纯 VT13 字节流,支持半包、连续帧及错误后的后缀恢复。 - * @param[in] data 接收字节地址,空指针不提交状态,调用结束后不保留该指针。 - * @param[in] size 数据字节数。 - * @param[in] now_ms 本次输入的时间,单位毫秒;完成的有效帧使用此时间提交。 - * @warning 不直接输入混合 A5/A9 图传流,应由 Protocol::Receive 完成分帧后接入。 - */ - void UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) override; - - /** @brief 清除暂存半包,保留最后有效状态、序号和接收时间。 */ - void ResetStream(); - - /** - * @brief 拷贝最后一帧有效状态。 - * @param[out] output 成功时接收完整快照;失败时保持原值。 - * @return 曾接收有效帧时为 true,否则为 false。 - * @note 离线后仍可读取最后状态;控制前须检查 IsOnline 及本车模式允许条件。 - */ - bool GetState(Vt13Frame& output) const; - - private: - /** - * @brief 校验并解码内部缓存的完整候选帧,对有效数据更新快照并提交状态。 - * @param[in] now_ms 本帧接收时间,单位毫秒。 - * @return 校验通过并提交时为 true,否则为 false。 - * @details 校验帧头、命令字、CRC16、模式编码、通道范围及鼠标按钮;解码五通道、控制按钮和键鼠。 - * 所有校验通过后才整体替换最后状态并调用 CommitFrame;失败时状态、序号及有效时间不变。 - * @note 仅由内部完整候选帧入口调用,不负责收集半包或恢复字节边界。 - */ - bool Decode(uint32_t now_ms); - std::array buffer_{}; ///< 候选帧缓存。 - size_t used_ = 0; ///< 已缓存字节数。 - Vt13Frame state_{}; ///< 最后一帧有效状态。 - }; -} // namespace remote diff --git a/boards/remote/include/protocols/sbus_receiver.h b/boards/remote/include/protocols/sbus_receiver.h deleted file mode 100644 index e0f39523..00000000 --- a/boards/remote/include/protocols/sbus_receiver.h +++ /dev/null @@ -1,126 +0,0 @@ -/*########################################################### -# Copyright (c) 2026-2027. BNBU/UIC RoboMaster # - # # - # This program is free software: you can redistribute it # - # and/or modify it under the terms of the GNU General # - # Public License as published by the Free Software # - # Foundation, either version 3 of the License, or (at # - # your option) any later version. # - # # - # This program is distributed in the hope that it will be # - # useful, but WITHOUT ANY WARRANTY; without even # - # the implied warranty of MERCHANTABILITY or FITNESS # - # FOR A PARTICULAR PURPOSE. See the GNU General # - # Public License for more details. # - # # - # You should have received a copy of the GNU General # - # Public License along with this program. If not, see # - # . # - ###########################################################*/ -#pragma once - -#include - -#include "bsp_uart.h" -#include "remote.h" - -namespace remote { - /** @brief SBUS 有效帧快照,保留原始通道和协议标志,不做本车控制映射。 */ - struct SbusFrame { - std::array channels{}; ///< 原始 11 位值 0~2047,下标 0 对应通道 1;部件映射由设备配置决定。 - uint8_t flags = 0; ///< 原始标志字节。 - bool channel17 = false; ///< 数字通道 17。 - bool channel18 = false; ///< 数字通道 18。 - bool frame_lost = false; ///< 接收机报告丢帧,不自动等同于失控。 - bool failsafe = false; ///< 接收机报告失控;有效失控帧仍会刷新通信在线。 - }; - - /** - * @brief SBUS 25 字节流接收器,支持通过 UART 句柄构造后自动接收。 - * @details 按 0x0F 帧头及配置的尾字节识别候选帧,支持半包、连续帧与错误后的后缀恢复。 - * SBUS 无 CRC,帧头和尾字节检查不能保证数据完整性。通道不减中心、不做死区或限幅。 - * @note 不绑定设备的摇杆、拨杆或通道端点;所有调用与状态读取须由接入层同步。 - */ - class SbusReceiver final : public RemoteReceiver { - public: - static constexpr size_t FRAME_SIZE = 25; ///< 单帧长度,单位字节。 - /** - * @brief 创建手动输入模式接收器,设置在线超时及允许的帧尾字节,不创建 UART。 - * @param[in] online_threshold_ms 在线超时,单位毫秒,默认 250。 - * @param[in] footer 唯一允许的帧尾字节,默认 0x00,须按实际接收机配置。 - */ - explicit SbusReceiver(uint32_t online_threshold_ms = 250, uint8_t footer = 0x00); - /** - * @brief 创建并拥有 UART 接收对象,自动配置缓存和注册接收回调。 - * @param[in] huart 已完成板级配置的 UART 句柄,不得重复绑定同一 UART。 - * @param[in] online_threshold_ms 在线超时,单位毫秒,默认 250。 - * @param[in] footer 唯一允许的帧尾字节,默认 0x00。 - * @note 波特率、数据位、校验位、停止位及反相由板级配置;对象须覆盖中断使用周期。 - */ - explicit SbusReceiver(UART_HandleTypeDef* huart, uint32_t online_threshold_ms = 250, - uint8_t footer = 0x00); - /** - * @brief 借用旧兼容包装的 UART,不创建第二个 UART、不替换原回调。 - * @param[in] uart 生命周期须长于本接收器的 UART 对象。 - * @param[in] online_threshold_ms 在线超时,单位毫秒,默认 250。 - * @param[in] footer 唯一允许的帧尾字节,默认 0x00。 - * @note 包装在自身回调中调用 RxCompleteCallback,接收器内部完成数据读取。 - */ - explicit SbusReceiver(bsp::UART& uart, uint32_t online_threshold_ms = 250, - uint8_t footer = 0x00); - /** @brief 释放本接收器拥有的 UART;借用的 UART 不释放。 */ - ~SbusReceiver() override; - SbusReceiver(const SbusReceiver&) = delete; - SbusReceiver& operator=(const SbusReceiver&) = delete; - /** @brief 使用系统毫秒时钟判断最近有效帧是否在线;失控标志须另行查询。 */ - bool IsOnline() const; - /** @brief 保留显式时钟查询,供手动输入和测试使用。 */ - using RemoteReceiver::IsOnline; - /** - * @brief UART 回调入口,读取接收块并交给流解析;UART 模式自动调用。 - * @note IDLE 块可以是半包或连续数据,不要求等于一帧;读取失败时清除半包。 - */ - void RxCompleteCallback(); - /** - * @brief 输入 SBUS 字节流,内部暂存半包并提交完整有效帧。 - * @param[in] data 接收字节地址,空指针不提交状态,调用结束后不保留该指针。 - * @param[in] size 数据字节数。 - * @param[in] now_ms 本次输入的时间,单位毫秒;完成的有效帧使用此时间提交。 - * @note 有效失控帧仍更新状态与在线时间,控制前须同时检查 IsFailsafe。 - */ - void UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) override; - /** @brief 清除暂存半包,保留最后有效状态、序号和接收时间。 */ - void ResetStream(); - /** - * @brief 拷贝最后一帧有效状态。 - * @param[out] output 成功时接收完整快照;失败时保持原值。 - * @return 曾接收有效帧时为 true,否则为 false。 - * @note 离线后仍可读取最后状态;控制前须检查 IsOnline 和 IsFailsafe。 - */ - bool GetState(SbusFrame& output) const; - /** - * @brief 修改唯一允许的帧尾字节,并清除暂存半包。 - * @param[in] footer 实际接收机使用的帧尾字节。 - * @note 不清除最后有效状态、序号或接收时间;不会自动接受其他尾字节变体。 - */ - void SetFooter(uint8_t footer); - - private: - /** - * @brief 校验并解码内部缓存的完整候选帧,对有效数据更新快照并提交状态。 - * @param[in] now_ms 本帧接收时间,单位毫秒。 - * @return 校验通过并提交时为 true,否则为 false。 - * @details 校验帧头与配置的尾字节;解码 16 个原始通道及数字通道、丢帧和失控标志。 - * 所有校验通过后才整体替换最后状态并调用 CommitFrame;失败时状态、序号及有效时间不变。 - * @note 仅由内部完整候选帧入口调用,不负责收集半包或恢复字节边界。 - */ - bool Decode(uint32_t now_ms); - static void UartCallback(void* context); ///< UART 回调转发入口。 - bsp::UART* uart_ = nullptr; ///< 内部拥有或旧包装借用的 UART。 - bool owns_uart_ = false; ///< 是否负责销毁 UART。 - std::array buffer_{}; ///< 候选帧缓存。 - size_t used_ = 0; ///< 已缓存字节数。 - uint8_t footer_; ///< 唯一允许的帧尾字节。 - SbusFrame state_{}; ///< 最后一帧有效状态。 - }; -} // namespace remote diff --git a/boards/remote/src/protocols/sbus_receiver.cpp b/boards/remote/src/protocols/sbus_receiver.cpp deleted file mode 100644 index c61b5dc8..00000000 --- a/boards/remote/src/protocols/sbus_receiver.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2026. BNU-HKBU UIC RoboMaster -// SPDX-License-Identifier: GPL-3.0-or-later -#include "protocols/sbus_receiver.h" - -#include "bsp_os.h" - -namespace remote { - SbusReceiver::SbusReceiver(uint32_t online_threshold_ms, uint8_t footer) - : RemoteReceiver(online_threshold_ms), footer_(footer) { - } - - SbusReceiver::SbusReceiver(UART_HandleTypeDef* huart, uint32_t online_threshold_ms, uint8_t footer) - : RemoteReceiver(online_threshold_ms), uart_(new bsp::UART(huart)), owns_uart_(true), footer_(footer) { - uart_->RegisterCallback(UartCallback, this); - uart_->SetupRx(FRAME_SIZE + 1); - } - - SbusReceiver::SbusReceiver(bsp::UART& uart, uint32_t online_threshold_ms, uint8_t footer) - : RemoteReceiver(online_threshold_ms), uart_(&uart), footer_(footer) { - uart_->SetupRx(FRAME_SIZE + 1); - } - - SbusReceiver::~SbusReceiver() { - if (owns_uart_) delete uart_; - } - - bool SbusReceiver::IsOnline() const { - return RemoteReceiver::IsOnline(bsp::GetHighresTickMilliSec()); - } - - void SbusReceiver::UartCallback(void* context) { - static_cast(context)->RxCompleteCallback(); - } - - void SbusReceiver::RxCompleteCallback() { - if (!uart_) return; - uint8_t* data = nullptr; - const int32_t length = uart_->Read(&data); - if (length <= 0 || data == nullptr) { - if (length != 0) ResetStream(); - return; - } - UpdateData(data, static_cast(length), bsp::GetHighresTickMilliSec()); - } - - void SbusReceiver::UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) { - if (data == nullptr) { - return; - } - for (size_t i = 0; i < size; ++i) { - if (used_ == 0 && data[i] != 0x0F) { - continue; - } - buffer_[used_++] = data[i]; - if (used_ == FRAME_SIZE) { - if (Decode(now_ms)) { - used_ = 0; - } else { - detail::FindNextFrame(buffer_, used_, 0x0F); - } - } - } - } - - void SbusReceiver::ResetStream() { - used_ = 0; - } - - void SbusReceiver::SetFooter(uint8_t footer) { - footer_ = footer; - ResetStream(); - } - - bool SbusReceiver::GetState(SbusFrame& output) const { - if (!HasState()) { - return false; - } - output = state_; - return true; - } - - bool SbusReceiver::Decode(uint32_t now_ms) { - if (buffer_[0] != 0x0F || buffer_[24] != footer_) { - return false; - } - SbusFrame next; - for (size_t i = 0; i < next.channels.size(); ++i) { - next.channels[i] = detail::DecodeBits(buffer_.data(), 8 + 11 * i, 11); - } - next.flags = buffer_[23]; - next.channel17 = (next.flags & 0x01) != 0; - next.channel18 = (next.flags & 0x02) != 0; - next.frame_lost = (next.flags & 0x04) != 0; - next.failsafe = (next.flags & 0x08) != 0; - state_ = next; - CommitFrame(now_ms, next.failsafe); - return true; - } -} // namespace remote From 6d7cfc242c5cf62fa8b6aba5418a821481df1cdf Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:34:21 +0800 Subject: [PATCH 16/17] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20controller?= =?UTF-8?q?=20=E9=81=A5=E6=8E=A7=E6=8E=A5=E6=94=B6=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E5=8F=8A=20DBUS/SBUS/RefereeRC=20=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- boards/drivers/include/connection_driver.h | 2 +- .../include/controller/controller.h} | 122 +++++++++- .../include/controller/dbus.h} | 118 +++------- boards/drivers/include/controller/refereerc.h | 138 ++++++++++++ boards/drivers/include/controller/sbus.h | 210 ++++++++++++++++++ .../src/controller/dbus.cpp} | 72 +++--- .../src/controller/refereerc.cpp} | 58 ++++- boards/drivers/src/controller/sbus.cpp | 177 +++++++++++++++ .../third_party/crc_check/include/crc_check.h | 2 +- boards/third_party/crc_check/src/crc_check.c | 2 + 10 files changed, 769 insertions(+), 132 deletions(-) rename boards/{remote/include/remote.h => drivers/include/controller/controller.h} (63%) rename boards/{remote/include/protocols/dbus_receiver.h => drivers/include/controller/dbus.h} (54%) create mode 100644 boards/drivers/include/controller/refereerc.h create mode 100644 boards/drivers/include/controller/sbus.h rename boards/{remote/src/protocols/dbus_receiver.cpp => drivers/src/controller/dbus.cpp} (65%) rename boards/{remote/src/protocols/refereerc_receiver.cpp => drivers/src/controller/refereerc.cpp} (69%) create mode 100644 boards/drivers/src/controller/sbus.cpp diff --git a/boards/drivers/include/connection_driver.h b/boards/drivers/include/connection_driver.h index ec0881bc..1dc72a50 100644 --- a/boards/drivers/include/connection_driver.h +++ b/boards/drivers/include/connection_driver.h @@ -34,7 +34,7 @@ namespace driver { * @brief 判断节点是否在线 * @return true 表示当前连接节点在线,false 表示当前节点连接离线 */ - bool IsOnline() const; + virtual bool IsOnline() const; /** * @return 获取节点上一个心跳包的时间(以毫秒为单位) diff --git a/boards/remote/include/remote.h b/boards/drivers/include/controller/controller.h similarity index 63% rename from boards/remote/include/remote.h rename to boards/drivers/include/controller/controller.h index 5db9532d..2e70c1fe 100644 --- a/boards/remote/include/remote.h +++ b/boards/drivers/include/controller/controller.h @@ -25,24 +25,124 @@ #include /** @brief 遥控协议解析与状态管理。 */ -namespace remote { +namespace controller { + /** + * @brief 两档拨杆的公共逻辑位置。 + * @note 具体设备负责将协议值转换为位置;枚举数值不用于解码或判断拨动方向。 + */ + enum class TwoPositionSwitch : uint8_t { + Down = 0, ///< 下档。 + Up = 1 ///< 上档。 + }; + + /** + * @brief 三档拨杆的公共逻辑位置。 + * @note 枚举数值保持稳定。 + * 各设备须显式映射协议值,不得依赖枚举数值解码或判断物理拨动方向。 + */ + enum class ThreePositionSwitch : uint8_t { + Up = 1, ///< 上档。 + Down = 2, ///< 下档。 + Mid = 3 ///< 中档。 + }; + + /** + * @brief 获取两档拨杆的名称,便于日志输出。 + * @param[in] position 拨杆位置。 + * @return "Up" 或 "Down";非法枚举值返回 "Unknown"。 + */ + constexpr const char* SwitchName(TwoPositionSwitch position) { + using enum TwoPositionSwitch; + switch (position) { + case Up: + return "Up"; + case Down: + return "Down"; + } + return "Unknown"; + } + + /** + * @brief 获取三档拨杆的名称,便于日志输出。 + * @param[in] position 拨杆位置。 + * @return "Up"、"Mid" 或 "Down";非法枚举值返回 "Unknown"。 + */ + constexpr const char* SwitchName(ThreePositionSwitch position) { + using enum ThreePositionSwitch; + switch (position) { + case Up: + return "Up"; + case Mid: + return "Mid"; + case Down: + return "Down"; + } + return "Unknown"; + } + + /** + * @brief DBUS 与 RefereeRC 共用的鼠标状态。 + * @details 三轴保留协议中的原始有符号数值,范围 -32768~32767,静止值为 0, + * 不套用摇杆的 ±660 范围或死区。按键 false 表示松开,true 表示按下。 + * @note 协议未提供的按键保持 false;DBUS 不提供中键,RefereeRC 支持左、右、中键。 + */ + struct MouseState { + int16_t x = 0; ///< 鼠标 X 轴输入。 + int16_t y = 0; ///< 鼠标 Y 轴输入。 + int16_t z = 0; ///< 鼠标滚轮输入。 + bool left = false; ///< 鼠标左键是否按下。 + bool right = false; ///< 鼠标右键是否按下。 + bool middle = false; ///< 鼠标中键是否按下;DBUS 始终为 false。 + }; + + /** + * @brief DBUS 与 RefereeRC 共用的 16 键键盘状态。 + * @details code 与 bit 共享两字节存储;各按键位 0 表示松开、1 表示按下, + * 多个按键可同时按下。默认 code 为 0,支持 keyboard.code 和 keyboard.bit.W 等访问。 + * @note 位域视图采用本项目 GCC/ARM 布局;线上数据仍由各协议按小端字节显式解码, + * 不把接收缓存强制转换为此类型。更换编译器平台须验证位域布局。 + */ + union KeyboardState { + uint16_t code = 0; ///< 完整 16 位按键位图,范围 0~65535。 + struct { + uint16_t W : 1; ///< bit0:W 键是否按下。 + uint16_t S : 1; ///< bit1:S 键是否按下。 + uint16_t A : 1; ///< bit2:A 键是否按下。 + uint16_t D : 1; ///< bit3:D 键是否按下。 + uint16_t SHIFT : 1; ///< bit4:SHIFT 键是否按下。 + uint16_t CTRL : 1; ///< bit5:CTRL 键是否按下。 + uint16_t Q : 1; ///< bit6:Q 键是否按下。 + uint16_t E : 1; ///< bit7:E 键是否按下。 + uint16_t R : 1; ///< bit8:R 键是否按下。 + uint16_t F : 1; ///< bit9:F 键是否按下。 + uint16_t G : 1; ///< bit10:G 键是否按下。 + uint16_t Z : 1; ///< bit11:Z 键是否按下。 + uint16_t X : 1; ///< bit12:X 键是否按下。 + uint16_t C : 1; ///< bit13:C 键是否按下。 + uint16_t V : 1; ///< bit14:V 键是否按下。 + uint16_t B : 1; ///< bit15:B 键是否按下。 + } __attribute__((packed)) bit; + } __attribute__((packed)); + static_assert(sizeof(KeyboardState) == 2, "KeyboardState must occupy two bytes"); + /** * @brief 遥控接收器的公共状态接口。 * @details 仅管理有效帧序号、接收时间及协议失控标志,不统一各协议的通道布局。 * UART、时钟和控制映射由接入层提供。校验失败或数据未收齐时不提交状态。 - * @note 所有方法须在同一线程调用或由接入层同步保护,不保证跨 ISR/任务的原子快照。 + * @note 不提供内部同步;与接收中断并发读取时,不保证各字段来自同一帧。 + * UpdateData 只允许单一接收上下文调用;解析、重置及协议配置不得并发执行。 */ - class RemoteReceiver { + class ControllerReceiver { public: /** * @brief 设置接收器的初始在线超时。 * @param[in] online_threshold_ms 超时阈值,单位毫秒,默认 250。 */ - explicit RemoteReceiver(uint32_t online_threshold_ms = 250) : online_threshold_ms_(online_threshold_ms) { + explicit ControllerReceiver(uint32_t online_threshold_ms = 250) : online_threshold_ms_(online_threshold_ms) { } /** @brief 支持通过基类指针销毁派生接收器。 */ - virtual ~RemoteReceiver() = default; + virtual ~ControllerReceiver() = default; /** * @brief 输入接收字节,具体边界和校验规则由派生协议定义。 @@ -114,11 +214,11 @@ namespace remote { } private: - uint32_t online_threshold_ms_; ///< 在线超时阈值,单位毫秒。 - uint32_t last_valid_ms_ = 0; ///< 最近有效帧时间,单位毫秒。 - uint32_t sequence_ = 0; ///< 有效帧提交序号。 - bool received_ = false; ///< 是否曾提交有效帧。 - bool failsafe_ = false; ///< 最近有效帧的协议失控标志。 + uint32_t online_threshold_ms_; ///< 在线超时阈值,单位毫秒。 + uint32_t last_valid_ms_ = 0; ///< 最近有效帧时间,单位毫秒。 + uint32_t sequence_ = 0; ///< 有效帧提交序号。 + bool received_ = false; ///< 是否曾提交有效帧。 + bool failsafe_ = false; ///< 最近有效帧的协议失控标志。 }; /** @brief 接收器内部字节解码工具,不涉及 UART、控制映射或有效帧提交。 */ namespace detail { @@ -185,4 +285,4 @@ namespace remote { std::memmove(buffer.data(), buffer.data() + offset, used); } } // namespace detail -} // namespace remote +} // namespace controller diff --git a/boards/remote/include/protocols/dbus_receiver.h b/boards/drivers/include/controller/dbus.h similarity index 54% rename from boards/remote/include/protocols/dbus_receiver.h rename to boards/drivers/include/controller/dbus.h index 8f15eea5..05a59a66 100644 --- a/boards/remote/include/protocols/dbus_receiver.h +++ b/boards/drivers/include/controller/dbus.h @@ -22,61 +22,10 @@ #include -#include "remote.h" +#include "controller.h" #include "bsp_uart.h" -namespace remote { - /** @brief DBUS 拨杆位置,数值与协议编码一致。 */ - enum class DbusSwitchPosition : uint8_t { - Up = 1, ///< 上 - Down = 2, ///< 下 - Middle = 3 ///< 中 - }; - - /** - * @brief DBUS 鼠标输入,保持协议中的原始有符号数值。 - * @details 三轴范围均为 -32768~32767,静止值为 0,不套用摇杆的 ±660 范围或死区。 - * 原始左右键字段必须为 0 或 1,否则拒绝整帧;输出 false 表示松开,true 表示按下。 - */ - struct DbusMouseState { - int16_t x = 0; ///< 鼠标 X 轴输入,范围 -32768~32767。 - int16_t y = 0; ///< 鼠标 Y 轴输入,范围 -32768~32767。 - int16_t z = 0; ///< 鼠标滚轮输入,范围 -32768~32767。 - bool left = false; ///< 鼠标左键是否按下。 - bool right = false; ///< 鼠标右键是否按下。 - }; - - /** - * @brief DBUS 键盘状态,按旧 API 提供完整位图 code 和按键位域 bit。 - * @details 位序沿用旧代码;多个按键可同时为 1,不采用旧版手册中不同的键位定义。 - * code 与 bit 共享存储,支持 keyboard.code 或 keyboard.bit.W 等访问。 - * code 范围为 0~65535,每个按键位只能为 0 或 1,多个按键可同时按下。 - * @note 位域视图采用本项目 GCC/ARM 布局;线上数据仍按小端字节显式解码, - * 不把接收缓存强制转换为该类型。新编译器平台须验证位域布局。 - */ - union DbusKeyboardState { - uint16_t code = 0; ///< 完整 16 位按键位图,默认没有按键按下。 - struct { - uint16_t W : 1; ///< bit0:W 键是否按下。 - uint16_t S : 1; ///< bit1:S 键是否按下。 - uint16_t A : 1; ///< bit2:A 键是否按下。 - uint16_t D : 1; ///< bit3:D 键是否按下。 - uint16_t SHIFT : 1; ///< bit4:SHIFT 键是否按下。 - uint16_t CTRL : 1; ///< bit5:CTRL 键是否按下。 - uint16_t Q : 1; ///< bit6:Q 键是否按下。 - uint16_t E : 1; ///< bit7:E 键是否按下。 - uint16_t R : 1; ///< bit8:R 键是否按下。 - uint16_t F : 1; ///< bit9:F 键是否按下。 - uint16_t G : 1; ///< bit10:G 键是否按下。 - uint16_t Z : 1; ///< bit11:Z 键是否按下。 - uint16_t X : 1; ///< bit12:X 键是否按下。 - uint16_t C : 1; ///< bit13:C 键是否按下。 - uint16_t V : 1; ///< bit14:V 键是否按下。 - uint16_t B : 1; ///< bit15:B 键是否按下。 - } __attribute__((packed)) bit; - } __attribute__((packed)); - static_assert(sizeof(DbusKeyboardState) == 2, "DBUS keyboard must occupy two bytes"); - +namespace controller { /** * @brief DBUS 有效帧快照,通道数值沿用旧 DBUS 的减中心与死区处理。 * @details 原始值减去 1024,绝对值不大于 10 时置零,正常行程为 -660~660。 @@ -97,21 +46,22 @@ namespace remote { * +v v+ */ std::array channels{}; - DbusSwitchPosition right_switch = DbusSwitchPosition::Middle; ///< 右拨杆位置。 - DbusSwitchPosition left_switch = DbusSwitchPosition::Middle; ///< 左拨杆位置。 - DbusMouseState mouse{}; ///< 鼠标状态。 - DbusKeyboardState keyboard{}; ///< 键盘状态,支持 code 和 bit 按键访问。 + ThreePositionSwitch right_switch = ThreePositionSwitch::Mid; ///< 右拨杆位置。 + ThreePositionSwitch left_switch = ThreePositionSwitch::Mid; ///< 左拨杆位置。 + MouseState mouse{}; ///< 鼠标状态;DBUS 不提供中键,middle 始终为 false。 + KeyboardState keyboard{}; ///< 键盘状态,支持 code 和 bit 按键访问。 }; /** * @brief DBUS 18 字节接收器,支持通过 UART 句柄构造后自动接收。 * @details DBUS 无帧头及 CRC,校验长度、拨杆、鼠标按钮和配置的通道范围。 * 字段合理性检查不能保证完整性,也不能用于猜测字节流的帧边界。 - * @note UART 模式内部通过 IDLE 回调接收;跨 ISR/任务读取仍须同步保护。 + * @note UART 模式内部通过 IDLE 回调接收;并发读取不保证整帧一致性。 + * UpdateData 与 SetChannelRange 不得并发调用,UART 模式下修改范围须先停止接收。 */ - class DbusReceiver final : public RemoteReceiver { + class DBUS final : public ControllerReceiver { public: - static constexpr size_t FRAME_SIZE = 18; ///< 单帧长度,单位字节。 + static constexpr size_t FRAME_SIZE = 18; ///< 单帧长度,单位字节。 static constexpr uint16_t CHANNEL_MIN = 364; ///< 原始通道有效下限。 static constexpr uint16_t CHANNEL_MAX = 1684; ///< 原始通道有效上限。 @@ -119,30 +69,22 @@ namespace remote { * @brief 绑定并拥有 UART 接收对象,自动配置缓存和接收回调。 * @param[in] huart 已完成板级配置的 UART 句柄,不得为同一 UART 重复创建接收对象。 * @param[in] online_threshold_ms 在线超时,单位毫秒,默认 250。 - * @note 波特率、偶校验、停止位及反相仍由板级配置负责;对象须覆盖中断使用周期。 + * @note 内部配置 100000 baud、8E1(HAL 使用 9 位字长以包含偶校验位)。 + * 引脚、DMA、中断及信号反相由板级配置;绑定前不得启动该 UART 的收发。 + * 对象须覆盖中断使用周期。 */ - explicit DbusReceiver(UART_HandleTypeDef* huart, uint32_t online_threshold_ms = 250); + explicit DBUS(UART_HandleTypeDef* huart, uint32_t online_threshold_ms = 250); - /** - * @brief 复用旧包装已拥有的 UART,不创建第二个 UART 对象。 - * @param[in] uart 已存在的 UART,生命周期须长于本接收器。 - * @note 兼容包装在自身回调中调用 RxCompleteCallback;本构造不替换原回调。 - */ - explicit DbusReceiver(bsp::UART& uart, uint32_t online_threshold_ms = 250); - - /** @brief 释放本接收器拥有的 UART;借用的 UART 不释放。 */ - ~DbusReceiver() override; + /** @brief 释放本接收器拥有的 UART;调用前须停止相关接收中断。 */ + ~DBUS() override; - DbusReceiver(const DbusReceiver&) = delete; + DBUS(const DBUS&) = delete; - DbusReceiver& operator=(const DbusReceiver&) = delete; + DBUS& operator=(const DBUS&) = delete; /** @brief 使用系统毫秒时钟判断有效 DBUS 帧是否在线,无需调用方传时间。 */ bool IsOnline() const; - /** @brief UART 接收回调入口,读取接收块并按 IDLE 边界校验;UART 模式自动调用。 */ - void RxCompleteCallback(); - /** * @brief 输入具有明确边界的完整 DBUS 接收块,一次调用只处理一帧。 * @param[in] data 接收块地址,须从帧起点开始,调用结束后不保留该指针。 @@ -172,21 +114,31 @@ namespace remote { bool SetChannelRange(uint16_t minimum, uint16_t maximum); private: + /** @brief UART 接收回调入口,读取接收块并按 IDLE 边界校验。 */ + void RxCompleteCallback(); + + /** + * @brief 将 DBUS 两位拨杆编码显式转换为公共三档位置。 + * @param[in] raw 协议编码:1 为上档,2 为下档,3 为中档,0 非法。 + * @param[out] output 成功时接收逻辑位置;失败时保持原值。 + * @return 编码合法时为 true,否则为 false。 + */ + static bool DecodeSwitch(uint16_t raw, ThreePositionSwitch& output); + /** * @brief 校验并解码一帧,对有效数据更新快照并提交状态。 * @param[in] data 已收齐的 FRAME_SIZE 字节候选帧。 * @param[in] now_ms 本帧接收时间,单位毫秒。 * @return 校验通过并提交时为 true,否则为 false。 * @details 校验五通道原始范围、左右拨杆及鼠标按钮;转换通道中心与死区,解码键鼠。 - * 所有校验通过后才整体替换最后状态并调用 CommitValidFrame;失败时状态、序号及有效时间不变。 + * 所有校验通过后才整体替换最后状态并调用 CommitFrame;失败时状态、序号及有效时间不变。 * @note 仅由内部完整候选帧入口调用,不负责收集半包或恢复字节边界。 */ bool Decode(const uint8_t* data, uint32_t now_ms); static void UartCallback(void* context); ///< UART 回调转发入口。 - bsp::UART* uart_ = nullptr; ///< 内部拥有或旧包装借用的 UART。 - bool owns_uart_ = false; ///< 是否负责销毁 UART。 - uint16_t channel_min_ = CHANNEL_MIN; ///< 原始通道值校验下限。 - uint16_t channel_max_ = CHANNEL_MAX; ///< 原始通道值校验上限。 - DbusFrame state_{}; ///< 最后一帧有效状态。 + bsp::UART* uart_ = nullptr; ///< 内部独占的 UART。 + uint16_t channel_min_ = CHANNEL_MIN; ///< 原始通道值校验下限。 + uint16_t channel_max_ = CHANNEL_MAX; ///< 原始通道值校验上限。 + DbusFrame state_{}; ///< 最后一帧有效状态。 }; -} // namespace remote +} // namespace controller diff --git a/boards/drivers/include/controller/refereerc.h b/boards/drivers/include/controller/refereerc.h new file mode 100644 index 00000000..ac9873e8 --- /dev/null +++ b/boards/drivers/include/controller/refereerc.h @@ -0,0 +1,138 @@ +/*########################################################### +# Copyright (c) 2026-2027. BNBU/UIC RoboMaster # + # # + # This program is free software: you can redistribute it # + # and/or modify it under the terms of the GNU General # + # Public License as published by the Free Software # + # Foundation, either version 3 of the License, or (at # + # your option) any later version. # + # # + # This program is distributed in the hope that it will be # + # useful, but WITHOUT ANY WARRANTY; without even # + # the implied warranty of MERCHANTABILITY or FITNESS # + # FOR A PARTICULAR PURPOSE. See the GNU General # + # Public License for more details. # + # # + # You should have received a copy of the GNU General # + # Public License along with this program. If not, see # + # . # + ###########################################################*/ +#pragma once + +#include + +#include "bsp_uart.h" +#include "controller.h" + +namespace controller { + /** @brief RefereeRC 遥控模式编码;是否允许控制由本车逻辑决定。 */ + enum class RefereeRcMode : uint8_t { + C = 0, ///< C 模式。 + N = 1, ///< N 模式。 + S = 2 ///< S 模式。 + }; + + /** @brief RefereeRC 有效帧快照,通道减中心并处理死区,不包含本车控制映射。 */ + struct RefereeRcFrame { + /** + * @brief 五通道减去 1024,包含 ±10 死区;不缩放或额外限幅。 + * @details 输出范围 -660~660,中心为 0;顺序为右 X/Y、左 Y/X、拨轮。 + */ + std::array channels{}; + RefereeRcMode mode = RefereeRcMode::C; ///< 模式选择,不自动转换为协议失控标志。 + bool pause = false; ///< 暂停按钮状态。 + bool left_button = false; ///< 遥控器左侧按钮状态,与鼠标左键不同。 + bool right_button = false; ///< 遥控器右侧按钮状态,与鼠标右键不同。 + bool trigger = false; ///< 扳机状态。 + MouseState mouse{}; ///< 鼠标状态,包含左、右、中键。 + KeyboardState keyboard{}; ///< 键盘状态,支持 code 和 bit 按键访问。 + uint16_t crc16 = 0; ///< 已通过校验的帧内 CRC16 值。 + }; + + /** + * @brief RefereeRC 21 字节遥控接收器,支持 UART 自动接收和手动输入。 + * @details 验证 0xA9 帧头、0x53 命令字、既有 CRC16、合法模式 0/1/2、 + * 五通道范围 364~1684,以及各占两位的鼠标左/右/中键编码 0/1。 + * 仅有效帧更新数据和独立在线时间,N/S 模式及暂停按钮不自动视为协议失控。 + * @note UART 直连仅用于纯遥控字节流;混合 A5/A9 数据须先由外部链路分帧。 + * 并发读取不保证整帧一致性;UpdateData 与 ResetStream 须在同一接收上下文串行调用或停止接收后调用。 + */ + class RefereeRC final : public ControllerReceiver { + public: + static constexpr size_t FRAME_SIZE = 21; ///< 单帧长度,单位字节。 + static constexpr uint8_t SOF = 0xA9; ///< RefereeRC 帧头。 + static constexpr uint8_t CMD = 0x53; ///< RefereeRC 命令字。 + static constexpr uint16_t CHANNEL_MIN = 364; ///< 五通道原始值有效下限,包含边界。 + static constexpr uint16_t CHANNEL_MAX = 1684; ///< 五通道原始值有效上限,包含边界。 + static constexpr uint16_t CHANNEL_CENTER = 1024; + static constexpr int16_t CHANNEL_DEADZONE = 10; + /** + * @brief 创建手动输入模式接收器,不分配 UART。 + * @param[in] online_threshold_ms 有效遥控帧超时阈值,单位 ms。 + */ + explicit RefereeRC(uint32_t online_threshold_ms = 250); + + /** + * @brief 创建并拥有 UART,自动注册回调及配置接收缓存。 + * @param[in] huart 已配置的 UART 句柄,不得为空或重复绑定。 + * @param[in] online_threshold_ms 有效遥控帧超时阈值,单位 ms。 + * @note 内部配置 921600 baud、8N1;引脚、DMA、中断由板级配置。 + * 绑定前不得启动该 UART 的收发;对象须覆盖接收中断使用期。 + */ + explicit RefereeRC(UART_HandleTypeDef* huart, uint32_t online_threshold_ms = 250); + + /** @brief 释放内部 UART;调用前须停止接收及相关中断。 */ + ~RefereeRC() override; + + /** @brief 禁止复制,避免重复拥有 UART 和回调上下文。 */ + RefereeRC(const RefereeRC&) = delete; + /** @brief 禁止复制赋值。 */ + RefereeRC& operator=(const RefereeRC&) = delete; + + /** @brief 使用系统毫秒时钟判断有效遥控帧是否在线。 */ + bool IsOnline() const; + /** @brief 保留手动输入使用的显式时间查询接口。 */ + using ControllerReceiver::IsOnline; + + /** + * @brief 输入纯 RefereeRC 遥控字节流,支持半包、连续帧及错误后的后缀恢复。 + * @param[in] data 接收字节地址,空指针不提交状态,调用结束后不保留该指针。 + * @param[in] size 数据字节数。 + * @param[in] now_ms 本次输入的时间,单位毫秒;完成的有效帧使用此时间提交。 + * @warning 不直接输入混合 A5/A9 图传流,应由 Protocol::Receive 完成分帧后接入。 + */ + void UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) override; + + /** @brief 清除暂存半包,保留最后有效状态、序号和接收时间。 */ + void ResetStream(); + + /** + * @brief 拷贝最后一帧有效状态。 + * @param[out] output 成功时接收完整快照;失败时保持原值。 + * @return 曾接收有效帧时为 true,否则为 false。 + * @note 离线后仍可读取最后状态;控制前须检查 IsOnline 及本车模式允许条件。 + */ + bool GetState(RefereeRcFrame& output) const; + + private: + /** + * @brief 读取 UART 接收块并直接输入解析器,读取错误时丢弃半包。 + * @param[in] context 注册回调时传入的有效 RefereeRC 实例指针。 + */ + static void UartCallback(void* context); + + /** + * @brief 校验并解码内部缓存的完整候选帧,对有效数据更新快照并提交状态。 + * @param[in] now_ms 本帧接收时间,单位毫秒。 + * @return 校验通过并提交时为 true,否则为 false。 + * @details 校验帧头、命令字、CRC16、模式编码、通道范围及鼠标按钮;解码五通道、控制按钮和键鼠。 + * 所有校验通过后才整体替换最后状态并调用 CommitFrame;失败时状态、序号及有效时间不变。 + * @note 仅由内部完整候选帧入口调用,不负责收集半包或恢复字节边界。 + */ + bool Decode(uint32_t now_ms); + bsp::UART* uart_ = nullptr; ///< 独占 UART;手动输入模式为 nullptr。 + std::array buffer_{}; ///< 候选帧缓存。 + size_t used_ = 0; ///< 已缓存字节数。 + RefereeRcFrame state_{}; ///< 最后一帧有效状态。 + }; +} // namespace controller diff --git a/boards/drivers/include/controller/sbus.h b/boards/drivers/include/controller/sbus.h new file mode 100644 index 00000000..aa2741dc --- /dev/null +++ b/boards/drivers/include/controller/sbus.h @@ -0,0 +1,210 @@ +/*########################################################### +# Copyright (c) 2026-2027. BNBU/UIC RoboMaster # + # # + # This program is free software: you can redistribute it # + # and/or modify it under the terms of the GNU General # + # Public License as published by the Free Software # + # Foundation, either version 3 of the License, or (at # + # your option) any later version. # + # # + # This program is distributed in the hope that it will be # + # useful, but WITHOUT ANY WARRANTY; without even # + # the implied warranty of MERCHANTABILITY or FITNESS # + # FOR A PARTICULAR PURPOSE. See the GNU General # + # Public License for more details. # + # # + # You should have received a copy of the GNU General # + # Public License along with this program. If not, see # + # . # + ###########################################################*/ +/** + * @file sbus.h + * @brief SBUS 协议接收器及 FS-i6X/iA10B 设备适配接口。 + */ +#pragma once + +#include + +#include "bsp_uart.h" +#include "controller.h" + +namespace controller { + /** @brief SBUS 原始帧快照,不做减中心、死区处理或设备映射。 */ + struct SbusFrame { + std::array channels{}; ///< CH1~16 原始 11 位值,范围 0~2047。 + uint8_t flags = 0; ///< 原始标志字节,保留所有位。 + bool channel17 = false; ///< flags bit0:数字通道 17。 + bool channel18 = false; ///< flags bit1:数字通道 18。 + bool frame_lost = false; ///< flags bit2:接收机报告丢帧,不等同于失控。 + bool failsafe = false; ///< flags bit3:接收机报告失控,不等同于通信离线。 + }; + + /** + * @brief 通用 SBUS 接收器,管理 UART、分帧、原始状态及有效帧时间。 + * @details 可绑定 UART 自动接收,也可通过 UpdateData 手动输入字节流。 + * 每个有效帧更新状态和序号;帧中的失控标志不阻止在线时间更新。 + * @note 不提供内部同步;与接收中断并发读取时,不保证整帧一致性。 + * UpdateData、ResetStream、SetFooter 须在同一接收上下文串行调用或停止接收后调用。 + * @see I6x + */ + class SBUS : public ControllerReceiver { + public: + static constexpr size_t FRAME_SIZE = 25; ///< SBUS 单帧字节数。 + + /** + * @brief 创建手动输入模式接收器,不分配 UART。 + * @param[in] online_threshold_ms 有效帧超时阈值,单位 ms;0 表示始终离线。 + * @param[in] footer 唯一允许的帧尾字节,应与实际接收机一致。 + */ + explicit SBUS(uint32_t online_threshold_ms = 250, uint8_t footer = 0x00); + + /** + * @brief 创建并拥有一个 UART,配置接收缓存并注册接收回调。 + * @param[in] huart 已完成板级配置的 UART 句柄,不得为空或重复绑定。 + * @param[in] online_threshold_ms 有效帧超时阈值,单位 ms。 + * @param[in] footer 唯一允许的帧尾字节。 + * @note 内部配置 100000 baud、8E2(HAL 使用 9 位字长以包含偶校验位)。 + * 引脚、DMA、中断及信号反相由板级配置;绑定前不得启动该 UART 的收发。 + * 对象生命周期须覆盖 UART 中断使用期。 + */ + explicit SBUS(UART_HandleTypeDef* huart, uint32_t online_threshold_ms = 250, uint8_t footer = 0x00); + + /** + * @brief 释放内部 UART;手动输入模式无需释放外设。 + * @pre 调用方已停止接收及相关中断,不再触发本对象的回调。 + */ + ~SBUS() override; + + /** @brief 禁止复制,避免重复拥有 UART 和回调上下文。 */ + SBUS(const SBUS&) = delete; + /** @brief 禁止复制赋值,保持 UART 所有权唯一。 */ + SBUS& operator=(const SBUS&) = delete; + + /** + * @brief 使用系统毫秒时钟判断最近有效帧是否在线。 + * @return 已收到有效帧且未达到超时阈值时为 true,否则为 false。 + * @note 手动输入的时间须与系统时钟同源,否则使用带 now_ms 的重载。 + * 在线不代表无失控;控制前还须检查帧状态及应用策略。 + */ + bool IsOnline() const; + /** @brief 保留基类的显式毫秒时钟查询接口。 */ + using ControllerReceiver::IsOnline; + + /** + * @brief 拷贝最后一帧有效原始状态。 + * @param[out] output 成功时接收原始快照;失败时保持原值。 + * @return 曾收到有效帧时为 true,首次有效帧前为 false。 + * @note 离线后保留最后状态,返回值不表示输入当前可用于控制。 + */ + bool GetRawState(SbusFrame& output) const; + + /** + * @brief 输入字节流,累积半包并逐帧校验、解码。 + * @param[in] data 输入数据,不保留指针;为空时忽略本次输入。 + * @param[in] size 输入字节数;0 表示不处理数据。 + * @param[in] now_ms 接收时间,单位 ms;本次完成的所有有效帧使用此时间。 + * @details 查找 0x0F 帧头,收齐 25 字节后检查配置的帧尾。 + * 无效候选帧保留下一帧头起始的后缀,继续处理后续字节。 + * 无效数据不刷新最后有效状态;有效失控帧仍更新状态及在线时间。 + * @note SBUS 无 CRC,帧头和帧尾校验不能保证数据完整性。 + */ + void UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) override; + + /** @brief 丢弃暂存半包,保留最后有效帧、序号、时间及失控状态。 */ + void ResetStream(); + + /** + * @brief 修改唯一允许的帧尾字节,并丢弃暂存半包。 + * @param[in] footer 实际接收机使用的帧尾字节。 + * @note 不清除最后有效帧和接收状态。 + */ + void SetFooter(uint8_t footer); + + private: + /** + * @brief 将 UART 回调转发到接收器实例。 + * @param[in] context 注册回调时传入的有效 SBUS 实例指针。 + */ + static void UartCallback(void* context); + + /** + * @brief 读取 UART 接收块,以系统毫秒时间调用 UpdateData。 + * @details 空接收块不处理;读取错误或非空块缺少数据指针时清除半包。 + */ + void RxCompleteCallback(); + + /** + * @brief 校验并解码完整候选帧,成功后发布原始状态。 + * @param[in] now_ms 本帧有效接收时间,单位 ms。 + * @return 帧头、帧尾正确且已提交状态时为 true,否则为 false。 + * @pre buffer_ 中已收齐 FRAME_SIZE 字节。 + * @note 失败不改变最后有效状态;本函数不负责重新查找帧头。 + */ + bool Decode(uint32_t now_ms); + + bsp::UART* uart_ = nullptr; ///< 独占的 UART;手动输入模式为 nullptr。 + std::array buffer_{}; ///< 正在收集的候选帧。 + size_t used_ = 0; ///< 候选帧内已缓存的字节数。 + uint8_t footer_; ///< 当前允许的帧尾字节。 + SbusFrame state_{}; ///< 最后有效帧,离线时仍保留。 + }; + + /** + * @brief i6X 控件快照,原始帧通过继承的 GetRawState 获取。 + * @details 丢帧及失控标志来自参与映射的同一帧,不包含在线超时判定。 + */ + struct I6xState { + std::array channels{}; ///< CH1~6:右 X/Y、左 Y/X、VrA/VrB,范围 ±660。 + TwoPositionSwitch sw_a = TwoPositionSwitch::Down; ///< CH7:SwA,两档。 + TwoPositionSwitch sw_b = TwoPositionSwitch::Down; ///< CH8:SwB,两档。 + ThreePositionSwitch sw_c = ThreePositionSwitch::Mid; ///< CH9:SwC,三档。 + TwoPositionSwitch sw_d = TwoPositionSwitch::Down; ///< CH10:SwD,两档。 + bool frame_lost = false; ///< 接收机报告丢帧,原样传递。 + bool failsafe = false; ///< 接收机报告失控,原样传递。 + }; + + /** + * @brief FS-i6X/iA10B 设备适配,继承 SBUS 的接收和在线状态。 + * @details 使用 240/1024/1807 标定端点及中心,原始 ±10 死区包含边界。 + * 中心两侧按各自行程缩放并四舍五入,输出饱和至 ±660。 + * 高拨杆通道值对应上档,模拟通道保持固定方向。 + * @note 发射机应保持 I6xState 所述通道分配;本类不包含机器人动作。 + * 不另建 UART、接收缓存或在线时间。 + */ + class I6x final : public SBUS { + public: + /** @brief 继承 SBUS 的手动输入及 UART 构造,使用固定设备映射。 */ + using SBUS::SBUS; + + /** + * @brief 从基类最后有效帧转换得到 i6X 控件状态。 + * @param[out] output 成功时接收映射结果;失败时保持原值。 + * @return 曾收到有效帧时为 true,首次有效帧前为 false。 + * @note 不另外缓存映射结果,不修改接收时间和序号。 + * 离线或失控后仍可读取;控制前须另行判断输入是否可用。 + */ + bool GetState(I6xState& output) const; + + private: + /** + * @brief 对模拟通道执行减中心、死区、标定缩放和限幅。 + * @param[in] raw SBUS 原始通道值,范围 0~2047。 + * @return 范围为 -660~660 的映射值,死区内为 0。 + */ + static int16_t MapChannel(uint16_t raw); + + /** + * @brief 以原始中心值 1024 为界解码两档拨杆。 + * @param[in] raw SBUS 原始通道值。 + * @return raw >= 1024 为 Up,否则为 Down。 + */ + static TwoPositionSwitch TwoPosition(uint16_t raw); + + /** + * @brief 按最近标定位置解码三档拨杆。 + * @param[in] raw SBUS 原始通道值。 + * @return 小于 632 为 Down,632~1415 为 Mid,至少 1416 为 Up。 + */ + static ThreePositionSwitch ThreePosition(uint16_t raw); + }; +} // namespace controller diff --git a/boards/remote/src/protocols/dbus_receiver.cpp b/boards/drivers/src/controller/dbus.cpp similarity index 65% rename from boards/remote/src/protocols/dbus_receiver.cpp rename to boards/drivers/src/controller/dbus.cpp index e0aa976d..ecaa508f 100644 --- a/boards/remote/src/protocols/dbus_receiver.cpp +++ b/boards/drivers/src/controller/dbus.cpp @@ -17,50 +17,53 @@ # Public License along with this program. If not, see # # . # ###########################################################*/ -#include "protocols/dbus_receiver.h" +#include "dbus.h" #include "bsp_os.h" -namespace remote { - DbusReceiver::DbusReceiver(UART_HandleTypeDef* huart, uint32_t online_threshold_ms) - : RemoteReceiver(online_threshold_ms), uart_(new bsp::UART(huart)), owns_uart_(true) { +namespace controller { + DBUS::DBUS(UART_HandleTypeDef* huart, uint32_t online_threshold_ms) : ControllerReceiver(online_threshold_ms) { + huart->Init.BaudRate = 100000; + huart->Init.WordLength = UART_WORDLENGTH_9B; + huart->Init.Parity = UART_PARITY_EVEN; + huart->Init.StopBits = UART_STOPBITS_1; + if (HAL_UART_Init(huart) != HAL_OK) { + Error_Handler(); + return; + } + uart_ = new bsp::UART(huart); uart_->RegisterCallback(UartCallback, this); uart_->SetupRx(FRAME_SIZE + 1); } - DbusReceiver::DbusReceiver(bsp::UART& uart, uint32_t online_threshold_ms) - : RemoteReceiver(online_threshold_ms), uart_(&uart) { - uart_->SetupRx(FRAME_SIZE + 1); - } - - DbusReceiver::~DbusReceiver() { - if (owns_uart_) delete uart_; + DBUS::~DBUS() { + delete uart_; } - bool DbusReceiver::IsOnline() const { - return RemoteReceiver::IsOnline(bsp::GetHighresTickMilliSec()); + bool DBUS::IsOnline() const { + return ControllerReceiver::IsOnline(bsp::GetHighresTickMilliSec()); } - void DbusReceiver::UartCallback(void* context) { - static_cast(context)->RxCompleteCallback(); + void DBUS::UartCallback(void* context) { + static_cast(context)->RxCompleteCallback(); } - void DbusReceiver::RxCompleteCallback() { - if (!uart_) return; + void DBUS::RxCompleteCallback() { + if (!uart_) + return; uint8_t* data = nullptr; const int32_t length = uart_->Read(&data); - UpdateData(data, length > 0 ? static_cast(length) : 0, - bsp::GetHighresTickMilliSec()); + UpdateData(data, length > 0 ? static_cast(length) : 0, bsp::GetHighresTickMilliSec()); } - void DbusReceiver::UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) { + void DBUS::UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) { // UART IDLE supplies a candidate frame boundary; only a full block is accepted. if (data != nullptr && size == FRAME_SIZE) { Decode(data, now_ms); } } - bool DbusReceiver::SetChannelRange(uint16_t minimum, uint16_t maximum) { + bool DBUS::SetChannelRange(uint16_t minimum, uint16_t maximum) { if (minimum < CHANNEL_MIN || minimum > maximum || maximum > CHANNEL_MAX) { return false; } @@ -69,7 +72,7 @@ namespace remote { return true; } - bool DbusReceiver::GetState(DbusFrame& output) const { + bool DBUS::GetState(DbusFrame& output) const { if (!HasState()) { return false; } @@ -77,7 +80,23 @@ namespace remote { return true; } - bool DbusReceiver::Decode(const uint8_t* data, uint32_t now_ms) { + bool DBUS::DecodeSwitch(uint16_t raw, ThreePositionSwitch& output) { + switch (raw) { + case 1: + output = ThreePositionSwitch::Up; + return true; + case 2: + output = ThreePositionSwitch::Down; + return true; + case 3: + output = ThreePositionSwitch::Mid; + return true; + default: + return false; + } + } + + bool DBUS::Decode(const uint8_t* data, uint32_t now_ms) { DbusFrame next; for (size_t i = 0; i < next.channels.size(); ++i) { // 处理 ch0-4 @@ -97,11 +116,10 @@ namespace remote { const auto right = detail::DecodeBits(data, 44, 2); const auto left = detail::DecodeBits(data, 46, 2); // 检测左右拨杆范围 + 鼠标左右键(data[12]/data[13]) - if (right == 0 || left == 0 || data[12] > 1 || data[13] > 1) { + if (!DecodeSwitch(right, next.right_switch) || !DecodeSwitch(left, next.left_switch) || data[12] > 1 || + data[13] > 1) { return false; } - next.right_switch = static_cast(right); - next.left_switch = static_cast(left); next.mouse.x = detail::DecodeInt16LE(data + 6); next.mouse.y = detail::DecodeInt16LE(data + 8); next.mouse.z = detail::DecodeInt16LE(data + 10); @@ -112,4 +130,4 @@ namespace remote { CommitFrame(now_ms, false); return true; } -} // namespace remote +} // namespace controller diff --git a/boards/remote/src/protocols/refereerc_receiver.cpp b/boards/drivers/src/controller/refereerc.cpp similarity index 69% rename from boards/remote/src/protocols/refereerc_receiver.cpp rename to boards/drivers/src/controller/refereerc.cpp index 84767acf..56967909 100644 --- a/boards/remote/src/protocols/refereerc_receiver.cpp +++ b/boards/drivers/src/controller/refereerc.cpp @@ -17,12 +17,39 @@ # Public License along with this program. If not, see # # . # ###########################################################*/ -#include "protocols/refereerc_receiver.h" +#include "refereerc.h" +#include "bsp_os.h" #include "crc_check.h" -namespace remote { - void RefereeRcReceiver::UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) { +namespace controller { + RefereeRC::RefereeRC(uint32_t online_threshold_ms) : ControllerReceiver(online_threshold_ms) { + } + + RefereeRC::RefereeRC(UART_HandleTypeDef* huart, uint32_t online_threshold_ms) + : ControllerReceiver(online_threshold_ms) { + huart->Init.BaudRate = 921600; + huart->Init.WordLength = UART_WORDLENGTH_8B; + huart->Init.Parity = UART_PARITY_NONE; + huart->Init.StopBits = UART_STOPBITS_1; + if (HAL_UART_Init(huart) != HAL_OK) { + Error_Handler(); + return; + } + uart_ = new bsp::UART(huart); + uart_->RegisterCallback(UartCallback, this); + uart_->SetupRx(300); + } + + RefereeRC::~RefereeRC() { + delete uart_; + } + + bool RefereeRC::IsOnline() const { + return ControllerReceiver::IsOnline(bsp::GetHighresTickMilliSec()); + } + + void RefereeRC::UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) { if (data == nullptr) { return; } @@ -41,11 +68,11 @@ namespace remote { } } - void RefereeRcReceiver::ResetStream() { + void RefereeRC::ResetStream() { used_ = 0; } - bool RefereeRcReceiver::GetState(Vt13Frame& output) const { + bool RefereeRC::GetState(RefereeRcFrame& output) const { if (!HasState()) { return false; } @@ -53,11 +80,24 @@ namespace remote { return true; } - bool RefereeRcReceiver::Decode(uint32_t now_ms) { + void RefereeRC::UartCallback(void* context) { + auto* self = static_cast(context); + uint8_t* data = nullptr; + const int32_t length = self->uart_->Read(&data); + if (length <= 0 || data == nullptr) { + if (length != 0) { + self->ResetStream(); + } + return; + } + self->UpdateData(data, static_cast(length), bsp::GetHighresTickMilliSec()); + } + + bool RefereeRC::Decode(uint32_t now_ms) { if (buffer_[0] != SOF || buffer_[1] != CMD || !verify_crc16_check_sum(buffer_.data(), FRAME_SIZE)) { return false; } - Vt13Frame next; + RefereeRcFrame next; for (size_t i = 0; i < next.channels.size(); ++i) { const size_t offset = i < 4 ? 16 + 11 * i : 65; const uint16_t raw = detail::DecodeBits(buffer_.data(), offset, 11); @@ -71,7 +111,7 @@ namespace remote { if (mode > 2) { return false; } - next.mode = static_cast(mode); + next.mode = static_cast(mode); next.pause = detail::DecodeBits(buffer_.data(), 62, 1) != 0; next.left_button = detail::DecodeBits(buffer_.data(), 63, 1) != 0; next.right_button = detail::DecodeBits(buffer_.data(), 64, 1) != 0; @@ -95,4 +135,4 @@ namespace remote { CommitFrame(now_ms, false); return true; } -} // namespace remote +} // namespace controller diff --git a/boards/drivers/src/controller/sbus.cpp b/boards/drivers/src/controller/sbus.cpp new file mode 100644 index 00000000..b8ec9047 --- /dev/null +++ b/boards/drivers/src/controller/sbus.cpp @@ -0,0 +1,177 @@ +/*########################################################### +# Copyright (c) 2026-2027. BNBU/UIC RoboMaster # + # # + # This program is free software: you can redistribute it # + # and/or modify it under the terms of the GNU General # + # Public License as published by the Free Software # + # Foundation, either version 3 of the License, or (at # + # your option) any later version. # + # # + # This program is distributed in the hope that it will be # + # useful, but WITHOUT ANY WARRANTY; without even # + # the implied warranty of MERCHANTABILITY or FITNESS # + # FOR A PARTICULAR PURPOSE. See the GNU General # + # Public License for more details. # + # # + # You should have received a copy of the GNU General # + # Public License along with this program. If not, see # + # . # + ###########################################################*/ + +/** + * @file sbus.cpp + * @brief SBUS 字节流接收与 i6X 设备映射实现。 + * @details 函数顺序与 sbus.h + * 一致;接口契约集中记录在头文件中。 + */ +#include "sbus.h" + +#include "bsp_os.h" + +namespace controller { + SBUS::SBUS(uint32_t online_threshold_ms, uint8_t footer) + : ControllerReceiver(online_threshold_ms), footer_(footer) { + } + + SBUS::SBUS(UART_HandleTypeDef* huart, uint32_t online_threshold_ms, uint8_t footer) + : ControllerReceiver(online_threshold_ms), footer_(footer) { + huart->Init.BaudRate = 100000; + huart->Init.WordLength = UART_WORDLENGTH_9B; + huart->Init.Parity = UART_PARITY_EVEN; + huart->Init.StopBits = UART_STOPBITS_2; + if (HAL_UART_Init(huart) != HAL_OK) { + Error_Handler(); + return; + } + uart_ = new bsp::UART(huart); + uart_->RegisterCallback(UartCallback, this); + uart_->SetupRx(FRAME_SIZE + 1); + } + + SBUS::~SBUS() { + delete uart_; + } + + bool SBUS::IsOnline() const { + return ControllerReceiver::IsOnline(bsp::GetHighresTickMilliSec()); + } + + bool SBUS::GetRawState(SbusFrame& output) const { + if (!HasState()) { + return false; + } + output = state_; + return true; + } + + void SBUS::UpdateData(const uint8_t* data, size_t size, uint32_t now_ms) { + if (data == nullptr) { + return; + } + for (size_t i = 0; i < size; ++i) { + if (used_ == 0 && data[i] != 0x0F) { + continue; + } + buffer_[used_++] = data[i]; + if (used_ == FRAME_SIZE) { + if (Decode(now_ms)) { + used_ = 0; + } else { + detail::FindNextFrame(buffer_, used_, 0x0F); + } + } + } + } + + void SBUS::ResetStream() { + used_ = 0; + } + + void SBUS::SetFooter(uint8_t footer) { + footer_ = footer; + ResetStream(); + } + + void SBUS::UartCallback(void* context) { + static_cast(context)->RxCompleteCallback(); + } + + void SBUS::RxCompleteCallback() { + if (!uart_) + return; + uint8_t* data = nullptr; + const int32_t length = uart_->Read(&data); + if (length <= 0 || data == nullptr) { + if (length != 0) + ResetStream(); + return; + } + UpdateData(data, static_cast(length), bsp::GetHighresTickMilliSec()); + } + + bool SBUS::Decode(uint32_t now_ms) { + if (buffer_[0] != 0x0F || buffer_[24] != footer_) { + return false; + } + SbusFrame next; + for (size_t i = 0; i < next.channels.size(); ++i) { + next.channels[i] = detail::DecodeBits(buffer_.data(), 8 + 11 * i, 11); + } + next.flags = buffer_[23]; + next.channel17 = (next.flags & 0x01) != 0; + next.channel18 = (next.flags & 0x02) != 0; + next.frame_lost = (next.flags & 0x04) != 0; + next.failsafe = (next.flags & 0x08) != 0; + state_ = next; + CommitFrame(now_ms, next.failsafe); + return true; + } + + bool I6x::GetState(I6xState& output) const { + SbusFrame raw; + if (!GetRawState(raw)) { + return false; + } + for (size_t i = 0; i < output.channels.size(); ++i) { + output.channels[i] = MapChannel(raw.channels[i]); + } + output.sw_a = TwoPosition(raw.channels[6]); + output.sw_b = TwoPosition(raw.channels[7]); + output.sw_c = ThreePosition(raw.channels[8]); + output.sw_d = TwoPosition(raw.channels[9]); + output.frame_lost = raw.frame_lost; + output.failsafe = raw.failsafe; + return true; + } + + int16_t I6x::MapChannel(uint16_t raw) { + constexpr int32_t center = 1024; + constexpr int32_t minimum = 240; + constexpr int32_t maximum = 1807; + constexpr int32_t range = 660; + const int32_t offset = static_cast(raw) - center; + if (offset >= -10 && offset <= 10) { + return 0; + } + const bool negative = offset < 0; + const int32_t span = negative ? center - minimum : maximum - center; + const int32_t magnitude = negative ? -offset : offset; + const int32_t scaled = magnitude >= span ? range : (magnitude * range + span / 2) / span; + return static_cast(negative ? -scaled : scaled); + } + + TwoPositionSwitch I6x::TwoPosition(uint16_t raw) { + return raw >= 1024 ? TwoPositionSwitch::Up : TwoPositionSwitch::Down; + } + + ThreePositionSwitch I6x::ThreePosition(uint16_t raw) { + // Classify by the nearest calibrated position: 240, 1024, 1807. + if (raw < (240 + 1024) / 2) { + return ThreePositionSwitch::Down; + } + if (raw > (1024 + 1807) / 2) { + return ThreePositionSwitch::Up; + } + return ThreePositionSwitch::Mid; + } +} // namespace controller diff --git a/boards/third_party/crc_check/include/crc_check.h b/boards/third_party/crc_check/include/crc_check.h index e64b0c19..4da80f4f 100644 --- a/boards/third_party/crc_check/include/crc_check.h +++ b/boards/third_party/crc_check/include/crc_check.h @@ -25,7 +25,7 @@ extern "C" { #endif -#include "main.h" +#include /** * Verify CRC8 diff --git a/boards/third_party/crc_check/src/crc_check.c b/boards/third_party/crc_check/src/crc_check.c index a485c6fa..6f11d2c2 100644 --- a/boards/third_party/crc_check/src/crc_check.c +++ b/boards/third_party/crc_check/src/crc_check.c @@ -20,6 +20,8 @@ #include "crc_check.h" +#include + // crc8 generator polynomial:G(x)=x8+x5+x4+1 const uint8_t CRC8_INIT = 0xff; const uint8_t CRC8_TAB[256] = { From 3920fec7b5a0ba1ce187b98dedcd7f3e71ddacca Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 28 Oct 2026 12:36:56 +0800 Subject: [PATCH 17/17] =?UTF-8?q?style:=20=E6=A0=BC=E5=BC=8F=E5=8C=96=20co?= =?UTF-8?q?ntroller=20=E5=8D=8F=E8=AE=AE=E4=B8=8E=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- boards/drivers/src/protocol.cpp | 138 ++++++++++++------ .../chassis/mecanum_example.cpp | 3 +- .../chassis/omni_example.cpp | 3 +- .../chassis/mecanum_example.cpp | 3 +- .../chassis/omni_example.cpp | 3 +- .../chassis/power_limit_test.cpp | 3 +- .../chassis/mecanum_example.cpp | 3 +- .../DM_MC01_general/chassis/omni_example.cpp | 3 +- programs/Ares/chassis/src/chassis_example.cpp | 3 +- programs/Ares/gimbal/src/chassis_task.cpp | 4 +- programs/Ares/gimbal/src/gimbal_task.cpp | 4 +- programs/Ares/gimbal/src/main.cpp | 3 +- programs/Ares/gimbal/src/remote_task.cpp | 4 +- .../Ares/gimbal/src/remote_task_automata.cpp | 11 +- .../DGStandard/gimbal/src/remote_task.cpp | 4 +- programs/Hero/gimbal/src/main.cpp | 3 +- programs/Hero/gimbal/src/remote_task.cpp | 4 +- 17 files changed, 116 insertions(+), 83 deletions(-) diff --git a/boards/drivers/src/protocol.cpp b/boards/drivers/src/protocol.cpp index bf6baf09..01907f0c 100644 --- a/boards/drivers/src/protocol.cpp +++ b/boards/drivers/src/protocol.cpp @@ -40,21 +40,22 @@ namespace communication { void Protocol::ResyncRx() { size_t next = 1; - while (next < rx_used_ && bufferRx[next] != SOF && - bufferRx[next] != controller::RefereeRC::SOF) { + while (next < rx_used_ && bufferRx[next] != SOF && bufferRx[next] != controller::RefereeRC::SOF) { ++next; } DiscardRx(next); } bool Protocol::Receive(package_t package) { - if (!package.data || package.length <= 0) return false; + if (!package.data || package.length <= 0) + return false; // Preserve the legacy link heartbeat. Input-source health is independent. Heartbeat(); const uint32_t now_ms = bsp::GetHighresTickMilliSec(); for (int i = 0; i < package.length; ++i) { const auto byte = package.data[i]; - if (!rx_used_ && byte != SOF && byte != controller::RefereeRC::SOF) continue; + if (!rx_used_ && byte != SOF && byte != controller::RefereeRC::SOF) + continue; // A5 lengths are capped below; every full candidate is consumed or // resynchronized before the next append, keeping this buffer bounded. bufferRx[rx_used_++] = byte; @@ -64,12 +65,14 @@ namespace communication { continue; } if (bufferRx[0] == controller::RefereeRC::SOF) { - if (rx_used_ < 2) break; + if (rx_used_ < 2) + break; if (bufferRx[1] != controller::RefereeRC::CMD) { ResyncRx(); continue; } - if (rx_used_ < controller::RefereeRC::FRAME_SIZE) break; + if (rx_used_ < controller::RefereeRC::FRAME_SIZE) + break; // Protocol owns stream framing; the receiver owns VT13 // validation, decoding and the independent input timestamp. refereerc_.ResetStream(); @@ -82,14 +85,16 @@ namespace communication { } DiscardRx(controller::RefereeRC::FRAME_SIZE); } else { - if (rx_used_ < FRAME_HEADER_LEN) break; + if (rx_used_ < FRAME_HEADER_LEN) + break; const int payload = int(bufferRx[1]) | (int(bufferRx[2]) << BYTE); if (!VerifyHeader(bufferRx, FRAME_HEADER_LEN) || payload > MAX_FRAME_LEN - 9) { ResyncRx(); continue; } const int total = payload + FRAME_HEADER_LEN + CMD_ID_LEN + FRAME_TAIL_LEN; - if (rx_used_ < static_cast(total)) break; + if (rx_used_ < static_cast(total)) + break; if (!VerifyFrame(bufferRx, total)) { ResyncRx(); continue; @@ -162,7 +167,8 @@ namespace communication { package_t UARTProtocol::Transmit(int cmd_id) { package_t package = Protocol::Transmit(cmd_id); - if (package.data && package.length > 0) uart_->Write(package.data, package.length); + if (package.data && package.length > 0) + uart_->Write(package.data, package.length); return package; } @@ -201,7 +207,8 @@ namespace communication { package_t USBProtocol::Transmit(int cmd_id) { package_t package = Protocol::Transmit(cmd_id); - if (package.data && package.length > 0) usb_->Write(package.data, package.length); + if (package.data && package.length > 0) + usb_->Write(package.data, package.length); return package; } @@ -215,71 +222,88 @@ namespace communication { bool Referee::ProcessDataRx(int cmd_id, const uint8_t* data, int length) { switch (cmd_id) { case GAME_STATUS: - if (length != static_cast(sizeof(game_status))) return false; + if (length != static_cast(sizeof(game_status))) + return false; memcpy(&game_status, data, sizeof(game_status)); break; case GAME_RESULT: - if (length != static_cast(sizeof(game_result))) return false; + if (length != static_cast(sizeof(game_result))) + return false; memcpy(&game_result, data, sizeof(game_result)); break; case GAME_ROBOT_HP: - if (length != static_cast(sizeof(game_robot_HP))) return false; + if (length != static_cast(sizeof(game_robot_HP))) + return false; memcpy(&game_robot_HP, data, sizeof(game_robot_HP)); break; case EVENT_DATA: - if (length != static_cast(sizeof(event_data))) return false; + if (length != static_cast(sizeof(event_data))) + return false; memcpy(&event_data, data, sizeof(event_data)); break; case SUPPLY_PROJECTILE_ACTION: - if (length != static_cast(sizeof(supply_projectile_action))) return false; + if (length != static_cast(sizeof(supply_projectile_action))) + return false; memcpy(&supply_projectile_action, data, sizeof(supply_projectile_action)); break; case REFEREE_WARNING: - if (length != static_cast(sizeof(referee_warning))) return false; + if (length != static_cast(sizeof(referee_warning))) + return false; memcpy(&referee_warning, data, sizeof(referee_warning)); break; case DART_REMAINING_TIME: - if (length != static_cast(sizeof(dart_remaining_time))) return false; + if (length != static_cast(sizeof(dart_remaining_time))) + return false; memcpy(&dart_remaining_time, data, sizeof(dart_remaining_time)); break; case GAME_ROBOT_STATUS: - if (length != static_cast(sizeof(game_robot_status))) return false; + if (length != static_cast(sizeof(game_robot_status))) + return false; memcpy(&game_robot_status, data, sizeof(game_robot_status)); break; case POWER_HEAT_DATA: - if (length != static_cast(sizeof(power_heat_data))) return false; + if (length != static_cast(sizeof(power_heat_data))) + return false; memcpy(&power_heat_data, data, sizeof(power_heat_data)); break; case GAME_ROBOT_POS: - if (length != static_cast(sizeof(game_robot_pos))) return false; + if (length != static_cast(sizeof(game_robot_pos))) + return false; memcpy(&game_robot_pos, data, sizeof(game_robot_pos)); break; case BUFF: - if (length != static_cast(sizeof(buff))) return false; + if (length != static_cast(sizeof(buff))) + return false; memcpy(&buff, data, sizeof(buff)); break; case AERIAL_ROBOT_ENERGY: - if (length != static_cast(sizeof(aerial_robot_energy))) return false; + if (length != static_cast(sizeof(aerial_robot_energy))) + return false; memcpy(&aerial_robot_energy, data, sizeof(aerial_robot_energy)); break; case ROBOT_HURT: - if (length != static_cast(sizeof(robot_hurt))) return false; + if (length != static_cast(sizeof(robot_hurt))) + return false; memcpy(&robot_hurt, data, sizeof(robot_hurt)); break; case SHOOT_DATA: - if (length != static_cast(sizeof(shoot_data))) return false; + if (length != static_cast(sizeof(shoot_data))) + return false; memcpy(&shoot_data, data, sizeof(shoot_data)); break; case BULLET_REMAINING: - if (length != static_cast(sizeof(bullet_remaining))) return false; + if (length != static_cast(sizeof(bullet_remaining))) + return false; memcpy(&bullet_remaining, data, sizeof(bullet_remaining)); break; case RFID_STATUS: - if (length != static_cast(sizeof(rfid_status))) return false; + if (length != static_cast(sizeof(rfid_status))) + return false; memcpy(&rfid_status, data, sizeof(rfid_status)); break; case DART_CLIENT_CMD: - if (length != static_cast(sizeof(dart_client_cmd))) return false; + if (length != static_cast(sizeof(dart_client_cmd))) + return false; memcpy(&dart_client_cmd, data, sizeof(dart_client_cmd)); break; default: @@ -347,44 +371,54 @@ namespace communication { bool Host::ProcessDataRx(int cmd_id, const uint8_t* data, int length) { switch (cmd_id) { case PACK: - if (length != static_cast(sizeof(pack))) return false; + if (length != static_cast(sizeof(pack))) + return false; memcpy(&pack, data, sizeof(pack)); break; case TARGET_ANGLE: // memset(&target_angle, 0, sizeof(target_angle)); - if (length != static_cast(sizeof(target_angle))) return false; + if (length != static_cast(sizeof(target_angle))) + return false; memcpy(&target_angle, data, sizeof(target_angle)); break; case NO_TARGET_FLAG: - if (length != static_cast(sizeof(no_target_flag))) return false; + if (length != static_cast(sizeof(no_target_flag))) + return false; memcpy(&no_target_flag, data, sizeof(no_target_flag)); break; case SHOOT_CMD: - if (length != static_cast(sizeof(shoot_cmd))) return false; + if (length != static_cast(sizeof(shoot_cmd))) + return false; memcpy(&shoot_cmd, data, sizeof(shoot_cmd)); break; case ROBOT_MOVE_SPEED: - if (length != static_cast(sizeof(robot_move))) return false; + if (length != static_cast(sizeof(robot_move))) + return false; memcpy(&robot_move, data, sizeof(robot_move)); break; case ROBOT_POWER_HEAT_HP_UPLOAD: - if (length != static_cast(sizeof(robot_power_heat_hp_upload))) return false; + if (length != static_cast(sizeof(robot_power_heat_hp_upload))) + return false; memcpy(&robot_power_heat_hp_upload, data, sizeof(robot_power_heat_hp_upload)); break; case GIMBAL_CURRENT_STATUS: - if (length != static_cast(sizeof(gimbal_current_status))) return false; + if (length != static_cast(sizeof(gimbal_current_status))) + return false; memcpy(&gimbal_current_status, data, sizeof(gimbal_current_status)); break; case CHASSIS_CURRENT_STATUS: - if (length != static_cast(sizeof(chassis_current_status))) return false; + if (length != static_cast(sizeof(chassis_current_status))) + return false; memcpy(&chassis_current_status, data, sizeof(chassis_current_status)); break; case AUTOAIM_ENABLE: - if (length != static_cast(sizeof(autoaim_enable))) return false; + if (length != static_cast(sizeof(autoaim_enable))) + return false; memcpy(&autoaim_enable, data, sizeof(autoaim_enable)); break; case ROBOT_STATUS_UPLOAD: - if (length != static_cast(sizeof(robot_status_upload))) return false; + if (length != static_cast(sizeof(robot_status_upload))) + return false; memcpy(&robot_status_upload, data, sizeof(robot_status_upload)); break; default: @@ -451,44 +485,54 @@ namespace communication { bool HostUSB::ProcessDataRx(int cmd_id, const uint8_t* data, int length) { switch (cmd_id) { case PACK: - if (length != static_cast(sizeof(pack))) return false; + if (length != static_cast(sizeof(pack))) + return false; memcpy(&pack, data, sizeof(pack)); break; case TARGET_ANGLE: // memset(&target_angle, 0, sizeof(target_angle)); - if (length != static_cast(sizeof(target_angle))) return false; + if (length != static_cast(sizeof(target_angle))) + return false; memcpy(&target_angle, data, sizeof(target_angle)); break; case NO_TARGET_FLAG: - if (length != static_cast(sizeof(no_target_flag))) return false; + if (length != static_cast(sizeof(no_target_flag))) + return false; memcpy(&no_target_flag, data, sizeof(no_target_flag)); break; case SHOOT_CMD: - if (length != static_cast(sizeof(shoot_cmd))) return false; + if (length != static_cast(sizeof(shoot_cmd))) + return false; memcpy(&shoot_cmd, data, sizeof(shoot_cmd)); break; case ROBOT_MOVE_SPEED: - if (length != static_cast(sizeof(robot_move))) return false; + if (length != static_cast(sizeof(robot_move))) + return false; memcpy(&robot_move, data, sizeof(robot_move)); break; case ROBOT_POWER_HEAT_HP_UPLOAD: - if (length != static_cast(sizeof(robot_power_heat_hp_upload))) return false; + if (length != static_cast(sizeof(robot_power_heat_hp_upload))) + return false; memcpy(&robot_power_heat_hp_upload, data, sizeof(robot_power_heat_hp_upload)); break; case GIMBAL_CURRENT_STATUS: - if (length != static_cast(sizeof(gimbal_current_status))) return false; + if (length != static_cast(sizeof(gimbal_current_status))) + return false; memcpy(&gimbal_current_status, data, sizeof(gimbal_current_status)); break; case CHASSIS_CURRENT_STATUS: - if (length != static_cast(sizeof(chassis_current_status))) return false; + if (length != static_cast(sizeof(chassis_current_status))) + return false; memcpy(&chassis_current_status, data, sizeof(chassis_current_status)); break; case AUTOAIM_ENABLE: - if (length != static_cast(sizeof(autoaim_enable))) return false; + if (length != static_cast(sizeof(autoaim_enable))) + return false; memcpy(&autoaim_enable, data, sizeof(autoaim_enable)); break; case ROBOT_STATUS_UPLOAD: - if (length != static_cast(sizeof(robot_status_upload))) return false; + if (length != static_cast(sizeof(robot_status_upload))) + return false; memcpy(&robot_status_upload, data, sizeof(robot_status_upload)); break; default: diff --git a/examples/DJI_Board_TypeA_general/chassis/mecanum_example.cpp b/examples/DJI_Board_TypeA_general/chassis/mecanum_example.cpp index 61029cc1..bca0dcaa 100644 --- a/examples/DJI_Board_TypeA_general/chassis/mecanum_example.cpp +++ b/examples/DJI_Board_TypeA_general/chassis/mecanum_example.cpp @@ -107,8 +107,7 @@ void RM_RTOS_Default_Task(const void* args) { ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus_state.left_switch == Up || - dbus_state.left_switch == Down) { + if (dbus_state.left_switch == Up || dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/examples/DJI_Board_TypeA_general/chassis/omni_example.cpp b/examples/DJI_Board_TypeA_general/chassis/omni_example.cpp index e27bf763..8176612c 100644 --- a/examples/DJI_Board_TypeA_general/chassis/omni_example.cpp +++ b/examples/DJI_Board_TypeA_general/chassis/omni_example.cpp @@ -108,8 +108,7 @@ void RM_RTOS_Default_Task(const void* args) { ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus_state.left_switch == Up || - dbus_state.left_switch == Down) { + if (dbus_state.left_switch == Up || dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/examples/DJI_Board_TypeC_general/chassis/mecanum_example.cpp b/examples/DJI_Board_TypeC_general/chassis/mecanum_example.cpp index 725b4ce8..66fd98cb 100644 --- a/examples/DJI_Board_TypeC_general/chassis/mecanum_example.cpp +++ b/examples/DJI_Board_TypeC_general/chassis/mecanum_example.cpp @@ -106,8 +106,7 @@ void RM_RTOS_Default_Task(const void* args) { ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus_state.left_switch == Up || - dbus_state.left_switch == Down) { + if (dbus_state.left_switch == Up || dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/examples/DJI_Board_TypeC_general/chassis/omni_example.cpp b/examples/DJI_Board_TypeC_general/chassis/omni_example.cpp index 7661daf3..73ab45c0 100644 --- a/examples/DJI_Board_TypeC_general/chassis/omni_example.cpp +++ b/examples/DJI_Board_TypeC_general/chassis/omni_example.cpp @@ -108,8 +108,7 @@ void RM_RTOS_Default_Task(const void* args) { ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus_state.left_switch == Up || - dbus_state.left_switch == Down) { + if (dbus_state.left_switch == Up || dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/examples/DJI_Board_TypeC_general/chassis/power_limit_test.cpp b/examples/DJI_Board_TypeC_general/chassis/power_limit_test.cpp index bc2bb892..3038933c 100644 --- a/examples/DJI_Board_TypeC_general/chassis/power_limit_test.cpp +++ b/examples/DJI_Board_TypeC_general/chassis/power_limit_test.cpp @@ -137,8 +137,7 @@ void RM_RTOS_Default_Task(const void* args) { ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus_state.left_switch == Up || - dbus_state.left_switch == Down) { + if (dbus_state.left_switch == Up || dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->UpdatePower(true, 60, battery_vol->GetBatteryVol(), 50); diff --git a/examples/DM_MC01_general/chassis/mecanum_example.cpp b/examples/DM_MC01_general/chassis/mecanum_example.cpp index 710b4d28..c7d9ebd1 100644 --- a/examples/DM_MC01_general/chassis/mecanum_example.cpp +++ b/examples/DM_MC01_general/chassis/mecanum_example.cpp @@ -106,8 +106,7 @@ void RM_RTOS_Default_Task(const void* args) { ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus_state.left_switch == Up || - dbus_state.left_switch == Down) { + if (dbus_state.left_switch == Up || dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/examples/DM_MC01_general/chassis/omni_example.cpp b/examples/DM_MC01_general/chassis/omni_example.cpp index 51e86c74..a509b549 100644 --- a/examples/DM_MC01_general/chassis/omni_example.cpp +++ b/examples/DM_MC01_general/chassis/omni_example.cpp @@ -108,8 +108,7 @@ void RM_RTOS_Default_Task(const void* args) { ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus_state.left_switch == Up || - dbus_state.left_switch == Down) { + if (dbus_state.left_switch == Up || dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/programs/Ares/chassis/src/chassis_example.cpp b/programs/Ares/chassis/src/chassis_example.cpp index 3d146fa6..65f8454a 100644 --- a/programs/Ares/chassis/src/chassis_example.cpp +++ b/programs/Ares/chassis/src/chassis_example.cpp @@ -109,8 +109,7 @@ void RM_RTOS_Default_Task(const void* args) { ->SetSpeed(dbus_state.channels[0] * ratio, dbus_state.channels[1] * ratio, dbus_state.channels[2] * ratio); // Kill switch - if (dbus_state.left_switch == Up || - dbus_state.left_switch == Down) { + if (dbus_state.left_switch == Up || dbus_state.left_switch == Down) { RM_ASSERT_TRUE(false, "Operation killed"); } chassis->SetPower(false, 30, 20, 60); diff --git a/programs/Ares/gimbal/src/chassis_task.cpp b/programs/Ares/gimbal/src/chassis_task.cpp index 0625bbf0..ef889708 100644 --- a/programs/Ares/gimbal/src/chassis_task.cpp +++ b/programs/Ares/gimbal/src/chassis_task.cpp @@ -67,8 +67,8 @@ void chassisTask(void* arg) { continue; } - const bool vt13_c_mode = (refereerc != nullptr) && refereerc->IsOnline() && - (refereerc_state.mode == controller::RefereeRcMode::C); + const bool vt13_c_mode = + (refereerc != nullptr) && refereerc->IsOnline() && (refereerc_state.mode == controller::RefereeRcMode::C); controller::KeyboardState keyboard{}; if (dbus->IsOnline()) { diff --git a/programs/Ares/gimbal/src/gimbal_task.cpp b/programs/Ares/gimbal/src/gimbal_task.cpp index 8c8b8413..c5c4651c 100644 --- a/programs/Ares/gimbal/src/gimbal_task.cpp +++ b/programs/Ares/gimbal/src/gimbal_task.cpp @@ -105,8 +105,8 @@ void gimbalTask(void* arg) { const float mouse_ratio = 0.5; const float remote_ratio = 0.005; - const bool vt13_c_mode = (refereerc != nullptr) && refereerc->IsOnline() && - (refereerc_state.mode == controller::RefereeRcMode::C); + const bool vt13_c_mode = + (refereerc != nullptr) && refereerc->IsOnline() && (refereerc_state.mode == controller::RefereeRcMode::C); if (dbus->IsOnline()) { if (dbus_state.mouse.x != 0 || dbus_state.mouse.y != 0) { diff --git a/programs/Ares/gimbal/src/main.cpp b/programs/Ares/gimbal/src/main.cpp index 8e67551f..baf92a99 100644 --- a/programs/Ares/gimbal/src/main.cpp +++ b/programs/Ares/gimbal/src/main.cpp @@ -184,8 +184,7 @@ void RM_RTOS_Default_Task(const void* arg) { print("\r\n"); print( "[Referee RC %s] ", - (refereerc != nullptr && refereerc->IsOnline()) ? "\033[32mOnline\033[0m" : - "\033[31mOffline\033[0m" + (refereerc != nullptr && refereerc->IsOnline()) ? "\033[32mOnline\033[0m" : "\033[31mOffline\033[0m" ); print("\r\n"); diff --git a/programs/Ares/gimbal/src/remote_task.cpp b/programs/Ares/gimbal/src/remote_task.cpp index d4ffeb23..7960076c 100644 --- a/programs/Ares/gimbal/src/remote_task.cpp +++ b/programs/Ares/gimbal/src/remote_task.cpp @@ -98,8 +98,8 @@ void remoteTask(void* arg) { refereerc->GetState(refereerc_state); } - const bool vt13_c_mode = (refereerc != nullptr && refereerc->IsOnline()) && - (refereerc_state.mode == controller::RefereeRcMode::C); + const bool vt13_c_mode = + (refereerc != nullptr && refereerc->IsOnline()) && (refereerc_state.mode == controller::RefereeRcMode::C); // Offline Detection && Security Check is_dbus_offline = (!dbus->IsOnline()) || dbus_state.right_switch == Down; diff --git a/programs/Ares/gimbal/src/remote_task_automata.cpp b/programs/Ares/gimbal/src/remote_task_automata.cpp index 5a4df6dc..ced408b9 100644 --- a/programs/Ares/gimbal/src/remote_task_automata.cpp +++ b/programs/Ares/gimbal/src/remote_task_automata.cpp @@ -157,12 +157,11 @@ void remoteTask(void* arg) { refereerc->GetState(refereerc_state); } - const bool is_dbus_offline = - (!dbus->IsOnline()) || (dbus_state.right_switch == Down); + const bool is_dbus_offline = (!dbus->IsOnline()) || (dbus_state.right_switch == Down); // VT13必须在线且处于C模式才算可控 const bool is_vt13_offline = - !((refereerc != nullptr && refereerc->IsOnline()) && - (refereerc_state.mode == controller::RefereeRcMode::C)); + !((refereerc != nullptr && refereerc->IsOnline()) && (refereerc_state.mode == controller::RefereeRcMode::C) + ); is_controller_online = !is_dbus_offline || !is_vt13_offline; #ifdef HAS_REFEREE @@ -194,8 +193,8 @@ void remoteTask(void* arg) { keyboard = {}; mouse = {}; - const bool vt13_c_mode = (refereerc != nullptr && refereerc->IsOnline()) && - (refereerc_state.mode == controller::RefereeRcMode::C); + const bool vt13_c_mode = + (refereerc != nullptr && refereerc->IsOnline()) && (refereerc_state.mode == controller::RefereeRcMode::C); if (dbus->IsOnline()) { // DBUS state_r = dbus_state.right_switch; diff --git a/programs/DGStandard/gimbal/src/remote_task.cpp b/programs/DGStandard/gimbal/src/remote_task.cpp index 08a23115..4a5fd4c0 100644 --- a/programs/DGStandard/gimbal/src/remote_task.cpp +++ b/programs/DGStandard/gimbal/src/remote_task.cpp @@ -88,8 +88,8 @@ void remoteTask(void* arg) { // 检测遥控器是否离线,或者遥控器是否在安全模式下 is_dbus_offline = (!dbus->IsOnline()) || dbus_state.right_switch == Down; - is_vt13_offline = (!(refereerc != nullptr && refereerc->IsOnline())) || - refereerc_state.mode != controller::RefereeRcMode::C; + is_vt13_offline = + (!(refereerc != nullptr && refereerc->IsOnline())) || refereerc_state.mode != controller::RefereeRcMode::C; #ifdef HAS_REFEREE // Kill Detection is_robot_dead = referee->game_robot_status.remain_HP == 0; diff --git a/programs/Hero/gimbal/src/main.cpp b/programs/Hero/gimbal/src/main.cpp index 34a8f692..0ff04e3f 100644 --- a/programs/Hero/gimbal/src/main.cpp +++ b/programs/Hero/gimbal/src/main.cpp @@ -161,8 +161,7 @@ void RM_RTOS_Default_Task(const void* arg) { print("\r\n"); print( "[Referee RC %s] ", - (refereerc != nullptr && refereerc->IsOnline()) ? "\033[32mOnline\033[0m" : - "\033[31mOffline\033[0m" + (refereerc != nullptr && refereerc->IsOnline()) ? "\033[32mOnline\033[0m" : "\033[31mOffline\033[0m" ); print("\r\n"); print("[Yaw %s] ", yaw_motor->IsOnline() ? "\033[32mOnline\033[0m" : "\033[31mOffline\033[0m"); diff --git a/programs/Hero/gimbal/src/remote_task.cpp b/programs/Hero/gimbal/src/remote_task.cpp index 00d7936c..d4288a60 100644 --- a/programs/Hero/gimbal/src/remote_task.cpp +++ b/programs/Hero/gimbal/src/remote_task.cpp @@ -82,8 +82,8 @@ void remoteTask(void* arg) { // 检测遥控器是否离线,或者遥控器是否在安全模式下 is_dbus_offline = (!dbus->IsOnline()) || dbus_state.right_switch == Down; // 检测VT13是否离线或不在C模式 - is_vt13_offline = (!(refereerc != nullptr && refereerc->IsOnline())) || - refereerc_state.mode != controller::RefereeRcMode::C; + is_vt13_offline = + (!(refereerc != nullptr && refereerc->IsOnline())) || refereerc_state.mode != controller::RefereeRcMode::C; #ifdef HAS_REFEREE is_robot_dead = referee->game_robot_status.remain_HP == 0; is_shoot_available = (referee->game_robot_status.shooter_heat_limit -