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 4ac579e8..2fa82b5b 100644 --- a/boards/CMakeLists.txt +++ b/boards/CMakeLists.txt @@ -3,4 +3,4 @@ add_subdirectory(platform) add_subdirectory(algorithm) add_subdirectory(drivers) add_subdirectory(components) -add_subdirectory(third_party) \ No newline at end of file +add_subdirectory(third_party) 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 diff --git a/boards/drivers/CMakeLists.txt b/boards/drivers/CMakeLists.txt index 3562e590..863160ba 100644 --- a/boards/drivers/CMakeLists.txt +++ b/boards/drivers/CMakeLists.txt @@ -7,6 +7,7 @@ set(DRIVER_SOURCES ${CRC_CHECK_SOURCES}) set(DRIVER_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/include/controller ${CMAKE_CURRENT_SOURCE_DIR}/include/Motor ${CMAKE_CURRENT_SOURCE_DIR}/../third_party/crc_check/include) @@ -99,4 +100,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/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/drivers/include/controller/controller.h b/boards/drivers/include/controller/controller.h new file mode 100644 index 00000000..2e70c1fe --- /dev/null +++ b/boards/drivers/include/controller/controller.h @@ -0,0 +1,288 @@ +/*########################################################### +# 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 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 不提供内部同步;与接收中断并发读取时,不保证各字段来自同一帧。 + * UpdateData 只允许单一接收上下文调用;解析、重置及协议配置不得并发执行。 + */ + class ControllerReceiver { + public: + /** + * @brief 设置接收器的初始在线超时。 + * @param[in] online_threshold_ms 超时阈值,单位毫秒,默认 250。 + */ + explicit ControllerReceiver(uint32_t online_threshold_ms = 250) : online_threshold_ms_(online_threshold_ms) { + } + + /** @brief 支持通过基类指针销毁派生接收器。 */ + virtual ~ControllerReceiver() = 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 controller diff --git a/boards/drivers/include/controller/dbus.h b/boards/drivers/include/controller/dbus.h new file mode 100644 index 00000000..05a59a66 --- /dev/null +++ b/boards/drivers/include/controller/dbus.h @@ -0,0 +1,144 @@ +/*########################################################### + # 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 "controller.h" +#include "bsp_uart.h" + +namespace controller { + /** + * @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{}; + 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 回调接收;并发读取不保证整帧一致性。 + * UpdateData 与 SetChannelRange 不得并发调用,UART 模式下修改范围须先停止接收。 + */ + class DBUS final : public ControllerReceiver { + 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 内部配置 100000 baud、8E1(HAL 使用 9 位字长以包含偶校验位)。 + * 引脚、DMA、中断及信号反相由板级配置;绑定前不得启动该 UART 的收发。 + * 对象须覆盖中断使用周期。 + */ + explicit DBUS(UART_HandleTypeDef* huart, uint32_t online_threshold_ms = 250); + + /** @brief 释放本接收器拥有的 UART;调用前须停止相关接收中断。 */ + ~DBUS() override; + + DBUS(const DBUS&) = delete; + + DBUS& operator=(const DBUS&) = delete; + + /** @brief 使用系统毫秒时钟判断有效 DBUS 帧是否在线,无需调用方传时间。 */ + bool IsOnline() const; + + /** + * @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 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 校验五通道原始范围、左右拨杆及鼠标按钮;转换通道中心与死区,解码键鼠。 + * 所有校验通过后才整体替换最后状态并调用 CommitFrame;失败时状态、序号及有效时间不变。 + * @note 仅由内部完整候选帧入口调用,不负责收集半包或恢复字节边界。 + */ + bool Decode(const uint8_t* data, uint32_t now_ms); + static void UartCallback(void* context); ///< UART 回调转发入口。 + bsp::UART* uart_ = nullptr; ///< 内部独占的 UART。 + uint16_t channel_min_ = CHANNEL_MIN; ///< 原始通道值校验下限。 + uint16_t channel_max_ = CHANNEL_MAX; ///< 原始通道值校验上限。 + DbusFrame state_{}; ///< 最后一帧有效状态。 + }; +} // 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/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 f9b6e652..1c6a7b30 100644 --- a/boards/drivers/include/protocol.h +++ b/boards/drivers/include/protocol.h @@ -25,7 +25,7 @@ #include "bsp_uart.h" #include "bsp_usb.h" #include "connection_driver.h" -#include "dji_remote.h" +#include "refereerc.h" namespace communication { @@ -46,6 +46,9 @@ namespace communication { * @return true for success; false for failure */ bool Receive(package_t package); + const controller::RefereeRC& RefereeRc() const { + return refereerc_; + } /** * @brief Generate the package to be sent according to the command and save to the internal @@ -64,15 +67,6 @@ 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; - /** * @brief verify the header of frame with crc8 * @@ -126,6 +120,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; + controller::RefereeRC refereerc_; + void DiscardRx(size_t size); + void ResyncRx(); }; class UARTProtocol : public Protocol { @@ -215,7 +215,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 +239,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,13 +532,6 @@ namespace communication { uint8_t cmd_source; } __packed map_command_t; - /* ===== REMOTE_CONTROL_DATA 0x0304 30Hz ===== */ - 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; @@ -610,14 +600,11 @@ namespace communication { custom_robot_data_t custom_robot_data{}; // 0x0302 map_command_t map_command{}; // 0x0303 - remote_control_t remote_control{}; // 0x0304 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: @@ -859,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/controller/dbus.cpp b/boards/drivers/src/controller/dbus.cpp new file mode 100644 index 00000000..ecaa508f --- /dev/null +++ b/boards/drivers/src/controller/dbus.cpp @@ -0,0 +1,133 @@ +/*########################################################### + # 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 "dbus.h" + +#include "bsp_os.h" + +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); + } + + DBUS::~DBUS() { + delete uart_; + } + + bool DBUS::IsOnline() const { + return ControllerReceiver::IsOnline(bsp::GetHighresTickMilliSec()); + } + + void DBUS::UartCallback(void* context) { + static_cast(context)->RxCompleteCallback(); + } + + 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()); + } + + 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 DBUS::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 DBUS::GetState(DbusFrame& output) const { + if (!HasState()) { + return false; + } + output = state_; + return true; + } + + 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 + 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 (!DecodeSwitch(right, next.right_switch) || !DecodeSwitch(left, next.left_switch) || data[12] > 1 || + data[13] > 1) { + return false; + } + 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 controller diff --git a/boards/drivers/src/controller/refereerc.cpp b/boards/drivers/src/controller/refereerc.cpp new file mode 100644 index 00000000..56967909 --- /dev/null +++ b/boards/drivers/src/controller/refereerc.cpp @@ -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 # + # . # + ###########################################################*/ +#include "refereerc.h" + +#include "bsp_os.h" +#include "crc_check.h" + +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; + } + 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 RefereeRC::ResetStream() { + used_ = 0; + } + + bool RefereeRC::GetState(RefereeRcFrame& output) const { + if (!HasState()) { + return false; + } + output = state_; + return true; + } + + 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; + } + 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); + 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 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/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 272cf974..01907f0c 100644 --- a/boards/drivers/src/protocol.cpp +++ b/boards/drivers/src/protocol.cpp @@ -24,7 +24,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 +33,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] != controller::RefereeRC::SOF) { + ++next; + } + DiscardRx(next); + } + 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 != 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] != controller::RefereeRC::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] == controller::RefereeRC::SOF) { + if (rx_used_ < 2) + break; + if (bufferRx[1] != controller::RefereeRC::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_ < controller::RefereeRC::FRAME_SIZE) + break; + // Protocol owns stream framing; the receiver owns VT13 + // validation, decoding and the independent input timestamp. + refereerc_.ResetStream(); + const auto sequence = refereerc_.GetSequence(); + refereerc_.UpdateData(bufferRx, controller::RefereeRC::FRAME_SIZE, now_ms); + refereerc_.ResetStream(); + if (refereerc_.GetSequence() == sequence) { + ResyncRx(); + continue; + } + DiscardRx(controller::RefereeRC::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 +111,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 +167,8 @@ 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,8 @@ 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 +222,89 @@ 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; @@ -299,8 +358,6 @@ namespace communication { default: data_len = -1; } - if (data_len > 0) - uart_->Write(data, data_len); return data_len; } @@ -314,35 +371,55 @@ 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 +485,55 @@ 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/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/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] = { 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..bca0dcaa 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,27 @@ 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..8176612c 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,27 @@ 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 diff --git a/examples/DJI_Board_TypeC_general/CMakeLists.txt b/examples/DJI_Board_TypeC_general/CMakeLists.txt index 411274d9..0425a0fb 100644 --- a/examples/DJI_Board_TypeC_general/CMakeLists.txt +++ b/examples/DJI_Board_TypeC_general/CMakeLists.txt @@ -5,7 +5,7 @@ add_subdirectory(buzzer) add_subdirectory(can_bridge) add_subdirectory(chassis) add_subdirectory(cybergear) -add_subdirectory(dbus) +add_subdirectory(controller) add_subdirectory(gimbal) add_subdirectory(imu) add_subdirectory(ist8310) @@ -15,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..66fd98cb 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,27 @@ 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..73ab45c0 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,27 @@ 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 +126,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..3038933c 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,22 @@ 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/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..e619bc99 --- /dev/null +++ b/examples/DJI_Board_TypeC_general/controller/dt7.cpp @@ -0,0 +1,75 @@ +/*########################################################### +# 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 "dbus.h" + +namespace { + controller::DBUS* receiver = nullptr; +} + +void RM_RTOS_Init(void) { + print_use_uart(&huart1); + + receiver = new controller::DBUS(&huart3); +} + +void RM_RTOS_Default_Task(const void* argument) { + UNUSED(argument); + while (true) { + 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(); + 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: %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); + 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..dcf6d12a --- /dev/null +++ b/examples/DJI_Board_TypeC_general/controller/fs_i6x.cpp @@ -0,0 +1,82 @@ +/*########################################################### +# 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 "sbus.h" + +static controller::I6x* receiver = nullptr; + +void RM_RTOS_Init(void) { + print_use_uart(&huart1); + + // I6x 继承 SBUS 的 UART 接收,无需另外创建 SBUS 或注册回调。 + receiver = new controller::I6x(&huart3); +} + +void RM_RTOS_Default_Task(const void* argument) { + UNUSED(argument); + while (true) { + controller::I6xState state; + controller::SbusFrame raw; + + 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(); + 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(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( + "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 < 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"); + } + 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..51998f8f --- /dev/null +++ b/examples/DJI_Board_TypeC_general/controller/vt13.cpp @@ -0,0 +1,76 @@ +/*########################################################### +# 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 "refereerc.h" + +static controller::RefereeRC* receiver = nullptr; + +void RM_RTOS_Init(void) { + print_use_uart(&huart1); + + // 只接收纯遥控字节流;UART 接入、分帧及校验均由 RefereeRC 完成。 + receiver = new controller::RefereeRC(&huart6); +} + +void RM_RTOS_Default_Task(const void* argument) { + UNUSED(argument); + while (true) { + 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(); + // 只有有效遥控帧刷新在线状态;离线后仍保留最后有效输入。 + 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 == 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); + 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); + } +} 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); - } -} 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..c7d9ebd1 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,27 @@ 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..a509b549 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,27 @@ 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; 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; 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; 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(); }; diff --git a/programs/Ares/chassis/src/chassis_example.cpp b/programs/Ares/chassis/src/chassis_example.cpp index 30cd208d..65f8454a 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,27 @@ 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..ef889708 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) { @@ -60,14 +67,14 @@ void chassisTask(void* arg) { continue; } - const bool vt13_c_mode = (refereerc != nullptr) && 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); - 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..c5c4651c 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; @@ -98,28 +105,25 @@ 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->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()) { - 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..baf92a99 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,23 @@ 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..7960076c 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) { + 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->IsOnline() && (refereerc->vt13_packet.remote.mode_sw == remote::vt13_remote_t::MODE_C); + (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..ced408b9 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,18 @@ 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 +188,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); + (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 +216,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 +231,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); 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); 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..4a5fd4c0 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_dbus_offline = (!dbus->IsOnline()) || dbus_state.right_switch == Down; 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; #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); } 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..0ff04e3f 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,10 @@ 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..d4288a60 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; + (!(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); 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);