...update result codes
This commit is contained in:
parent
252209dd1b
commit
29c851d4e2
|
|
@ -13,43 +13,42 @@ DShotCommandManager::DShotCommandManager(DShotRMT &dshot_instance)
|
|||
: _dshot(dshot_instance),
|
||||
_total_commands_sent(0),
|
||||
_failed_commands(0),
|
||||
_last_execution_time_us(0),
|
||||
_last_command_timestamp(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Init command manager
|
||||
bool DShotCommandManager::begin()
|
||||
dshot_result_t DShotCommandManager::begin()
|
||||
{
|
||||
resetStatistics();
|
||||
return true;
|
||||
dshot_result_t result;
|
||||
result.success = true;
|
||||
result.error_message = "Success";
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- BASIC COMMAND METHODS ---
|
||||
dshot_command_result_t DShotCommandManager::sendCommand(dshot_commands_t command, uint16_t repeat_count)
|
||||
dshot_result_t DShotCommandManager::sendCommand(dshot_commands_t command, uint16_t repeat_count)
|
||||
{
|
||||
return sendCommandWithDelay(command, repeat_count, DEFAULT_COMMAND_DELAY_MS);
|
||||
}
|
||||
|
||||
//
|
||||
dshot_command_result_t DShotCommandManager::sendCommandWithDelay(dshot_commands_t command, uint16_t repeat_count, uint32_t delay_ms)
|
||||
dshot_result_t DShotCommandManager::sendCommandWithDelay(dshot_commands_t command, uint16_t repeat_count, uint32_t delay_ms)
|
||||
{
|
||||
dshot_command_result_t result = {false, 0, "Unknown error"};
|
||||
dshot_result_t result = {false, "Unknown error"};
|
||||
|
||||
if (!isValidCommand(command))
|
||||
{
|
||||
result.error_message = "Invalid command";
|
||||
_updateStatistics(false, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t start_time = esp_timer_get_time();
|
||||
bool all_successful = true;
|
||||
|
||||
// Send command multiple times with delay
|
||||
for (uint16_t i = 0; i < repeat_count; i++)
|
||||
{
|
||||
dshot_command_result_t single_result = _executeCommand(command);
|
||||
dshot_result_t single_result = _executeCommand(command);
|
||||
|
||||
if (!single_result.success)
|
||||
{
|
||||
|
|
@ -61,12 +60,11 @@ dshot_command_result_t DShotCommandManager::sendCommandWithDelay(dshot_commands_
|
|||
// Add delay between repetitions (except for last repetition)
|
||||
if (i < repeat_count - 1)
|
||||
{
|
||||
_delay(delay_ms);
|
||||
_delay_ms(delay_ms);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t end_time = esp_timer_get_time();
|
||||
result.execution_time_us = (uint32_t)(end_time - start_time);
|
||||
//
|
||||
result.success = all_successful;
|
||||
|
||||
if (result.success)
|
||||
|
|
@ -74,57 +72,54 @@ dshot_command_result_t DShotCommandManager::sendCommandWithDelay(dshot_commands_
|
|||
result.error_message = "Success";
|
||||
}
|
||||
|
||||
_updateStatistics(result.success, result.execution_time_us);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- MOTOR CONTROL COMMANDS ---
|
||||
dshot_command_result_t DShotCommandManager::stopMotor()
|
||||
dshot_result_t DShotCommandManager::stopMotor()
|
||||
{
|
||||
return sendCommand(DSHOT_CMD_MOTOR_STOP);
|
||||
}
|
||||
|
||||
//
|
||||
dshot_command_result_t DShotCommandManager::set3DMode(bool enable)
|
||||
dshot_result_t DShotCommandManager::set3DMode(bool enable)
|
||||
{
|
||||
dshot_commands_t command = enable ? DSHOT_CMD_3D_MODE_ON : DSHOT_CMD_3D_MODE_OFF;
|
||||
return sendCommandWithDelay(command, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_MS);
|
||||
}
|
||||
|
||||
//
|
||||
dshot_command_result_t DShotCommandManager::setSpinDirection(bool reversed)
|
||||
dshot_result_t DShotCommandManager::setSpinDirection(bool reversed)
|
||||
{
|
||||
dshot_commands_t command = reversed ? DSHOT_CMD_SPIN_DIRECTION_REVERSED : DSHOT_CMD_SPIN_DIRECTION_NORMAL;
|
||||
return sendCommandWithDelay(command, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_MS);
|
||||
}
|
||||
|
||||
//
|
||||
dshot_command_result_t DShotCommandManager::saveSettings()
|
||||
dshot_result_t DShotCommandManager::saveSettings()
|
||||
{
|
||||
return sendCommandWithDelay(DSHOT_CMD_SAVE_SETTINGS, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_MS);
|
||||
}
|
||||
|
||||
// --- TELEMETRY COMMANDS ---
|
||||
dshot_command_result_t DShotCommandManager::setExtendedTelemetry(bool enable)
|
||||
dshot_result_t DShotCommandManager::setExtendedTelemetry(bool enable)
|
||||
{
|
||||
dshot_commands_t command = enable ? DSHOT_CMD_EXTENDED_TELEMETRY_ENABLE : DSHOT_CMD_EXTENDED_TELEMETRY_DISABLE;
|
||||
return sendCommand(command);
|
||||
}
|
||||
|
||||
//
|
||||
dshot_command_result_t DShotCommandManager::requestESCInfo()
|
||||
dshot_result_t DShotCommandManager::requestESCInfo()
|
||||
{
|
||||
return sendCommand(DSHOT_CMD_ESC_INFO);
|
||||
}
|
||||
|
||||
// --- LED CONTROL COMMANDS ---
|
||||
dshot_command_result_t DShotCommandManager::setLED(uint8_t led_number, bool state)
|
||||
dshot_result_t DShotCommandManager::setLED(uint8_t led_number, bool state)
|
||||
{
|
||||
if (led_number > 3)
|
||||
{
|
||||
dshot_command_result_t result = {false, 0, "Invalid LED number (0-3)"};
|
||||
_updateStatistics(false, 0);
|
||||
dshot_result_t result = {false, "Invalid LED number (0-3)"};
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -172,12 +167,11 @@ dshot_command_result_t DShotCommandManager::setLED(uint8_t led_number, bool stat
|
|||
}
|
||||
|
||||
// --- BEACON COMMANDS ---
|
||||
dshot_command_result_t DShotCommandManager::activateBeacon(uint8_t beacon_number)
|
||||
dshot_result_t DShotCommandManager::activateBeacon(uint8_t beacon_number)
|
||||
{
|
||||
if (beacon_number < 1 || beacon_number > 5)
|
||||
{
|
||||
dshot_command_result_t result = {false, 0, "Invalid beacon number (1-5)"};
|
||||
_updateStatistics(false, 0);
|
||||
dshot_result_t result = {false, "Invalid beacon number (1-5)"};
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -186,28 +180,28 @@ dshot_command_result_t DShotCommandManager::activateBeacon(uint8_t beacon_number
|
|||
}
|
||||
|
||||
// --- KISS ESC SPECIFIC COMMANDS ---
|
||||
dshot_command_result_t DShotCommandManager::setAudioStreamMode(bool enable)
|
||||
dshot_result_t DShotCommandManager::setAudioStreamMode(bool enable)
|
||||
{
|
||||
// KISS audio stream mode is a toggle command
|
||||
return sendCommand(DSHOT_CMD_AUDIO_STREAM_MODE_ON_OFF);
|
||||
}
|
||||
|
||||
//
|
||||
dshot_command_result_t DShotCommandManager::setSilentMode(bool enable)
|
||||
dshot_result_t DShotCommandManager::setSilentMode(bool enable)
|
||||
{
|
||||
// KISS silent mode is a toggle command
|
||||
return sendCommand(DSHOT_CMD_SILENT_MODE_ON_OFF);
|
||||
}
|
||||
|
||||
// --- SEQUENCE COMMANDS ---
|
||||
dshot_command_result_t DShotCommandManager::executeSequence(const dshot_command_sequence_item_t *sequence, size_t sequence_length)
|
||||
dshot_result_t DShotCommandManager::executeSequence(const dshot_command_sequence_item_t *sequence, size_t sequence_length)
|
||||
{
|
||||
dshot_command_result_t result = {true, 0, "Success"};
|
||||
dshot_result_t result = {true, "Success"};
|
||||
uint64_t total_start_time = esp_timer_get_time();
|
||||
|
||||
for (size_t i = 0; i < sequence_length; i++)
|
||||
{
|
||||
dshot_command_result_t item_result = sendCommandWithDelay(
|
||||
dshot_result_t item_result = sendCommandWithDelay(
|
||||
sequence[i].command,
|
||||
sequence[i].repeat_count,
|
||||
DEFAULT_COMMAND_DELAY_MS);
|
||||
|
|
@ -222,18 +216,17 @@ dshot_command_result_t DShotCommandManager::executeSequence(const dshot_command_
|
|||
// Add delay after command if specified
|
||||
if (sequence[i].delay_ms > 0)
|
||||
{
|
||||
_delay(sequence[i].delay_ms);
|
||||
_delay_ms(sequence[i].delay_ms);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t total_end_time = esp_timer_get_time();
|
||||
result.execution_time_us = (uint32_t)(total_end_time - total_start_time);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
dshot_command_result_t DShotCommandManager::executeInitSequence()
|
||||
dshot_result_t DShotCommandManager::executeInitSequence()
|
||||
{
|
||||
// Basic ESC initialization sequence
|
||||
dshot_command_sequence_item_t init_sequence[] = {
|
||||
|
|
@ -246,7 +239,7 @@ dshot_command_result_t DShotCommandManager::executeInitSequence()
|
|||
}
|
||||
|
||||
//
|
||||
dshot_command_result_t DShotCommandManager::executeCalibrationSequence()
|
||||
dshot_result_t DShotCommandManager::executeCalibrationSequence()
|
||||
{
|
||||
// Basic ESC calibration sequence
|
||||
dshot_command_sequence_item_t calibration_sequence[] = {
|
||||
|
|
@ -330,64 +323,25 @@ bool DShotCommandManager::isValidCommand(dshot_commands_t command)
|
|||
return (command >= DSHOT_CMD_MOTOR_STOP && command <= DSHOT_CMD_MAX);
|
||||
}
|
||||
|
||||
//
|
||||
void DShotCommandManager::printStatistics(Stream &output) const
|
||||
{
|
||||
output.println("\n--- DShot Command Manager Statistics ---");
|
||||
output.printf("Total commands sent: %u\n", _total_commands_sent);
|
||||
output.printf("Failed commands: %u\n", _failed_commands);
|
||||
output.printf("Success rate: %.2f%%\n",
|
||||
_total_commands_sent > 0 ? (float)(_total_commands_sent - _failed_commands) / _total_commands_sent * 100.0f : 0.0f);
|
||||
output.printf("Last execution time: %u us\n", _last_execution_time_us);
|
||||
output.printf("Last command timestamp: %llu us\n", _last_command_timestamp);
|
||||
}
|
||||
|
||||
//
|
||||
void DShotCommandManager::resetStatistics()
|
||||
{
|
||||
_total_commands_sent = 0;
|
||||
_failed_commands = 0;
|
||||
_last_execution_time_us = 0;
|
||||
_last_command_timestamp = 0;
|
||||
}
|
||||
|
||||
// --- PRIVATE METHODS ---
|
||||
dshot_command_result_t DShotCommandManager::_executeCommand(dshot_commands_t command)
|
||||
dshot_result_t DShotCommandManager::_executeCommand(dshot_commands_t command)
|
||||
{
|
||||
dshot_command_result_t result = {false, 0, "Execution failed"};
|
||||
|
||||
uint64_t start_time = esp_timer_get_time();
|
||||
|
||||
// Execute the command using the DShotRMT instance
|
||||
bool success = _dshot.sendCommand(static_cast<uint16_t>(command));
|
||||
dshot_result_t result = _dshot.sendCommand(static_cast<uint16_t>(command));
|
||||
|
||||
uint64_t end_time = esp_timer_get_time();
|
||||
|
||||
result.success = success;
|
||||
result.execution_time_us = (uint32_t)(end_time - start_time);
|
||||
result.error_message = success ? "Success" : "Command transmission failed";
|
||||
|
||||
_last_command_timestamp = end_time;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
void DShotCommandManager::_delay(uint32_t delay_ms)
|
||||
void DShotCommandManager::_delay_ms(uint32_t delay_ms)
|
||||
{
|
||||
if (delay_ms > 0)
|
||||
{
|
||||
delay(delay_ms);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
void DShotCommandManager::_updateStatistics(bool success, uint32_t execution_time_us)
|
||||
{
|
||||
_total_commands_sent++;
|
||||
if (!success)
|
||||
{
|
||||
_failed_commands++;
|
||||
}
|
||||
_last_execution_time_us = execution_time_us;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,17 +12,6 @@
|
|||
#include <DShotRMT.h>
|
||||
#include <dshot_commands.h>
|
||||
|
||||
// Naming convention
|
||||
typedef dshotCommands_e dshot_commands_t;
|
||||
|
||||
// Command execution result structure
|
||||
typedef struct
|
||||
{
|
||||
bool success;
|
||||
uint32_t execution_time_us;
|
||||
const char *error_message;
|
||||
} dshot_command_result_t;
|
||||
|
||||
// Command sequence item
|
||||
typedef struct
|
||||
{
|
||||
|
|
@ -39,63 +28,61 @@ public:
|
|||
explicit DShotCommandManager(DShotRMT &dshot_instance);
|
||||
|
||||
// Initialize command manager
|
||||
bool begin();
|
||||
|
||||
bool printMenu(Stream &output);
|
||||
dshot_result_t begin();
|
||||
|
||||
void handleMenuInput(const String &input, Stream &output = Serial);
|
||||
|
||||
// Send a single DShot command
|
||||
dshot_command_result_t sendCommand(dshot_commands_t command, uint16_t repeat_count = 1);
|
||||
dshot_result_t sendCommand(dshot_commands_t command, uint16_t repeat_count = 1);
|
||||
|
||||
// Send command with specified delay between repetitions
|
||||
dshot_command_result_t sendCommandWithDelay(dshot_commands_t command, uint16_t repeat_count, uint32_t delay_ms);
|
||||
dshot_result_t sendCommandWithDelay(dshot_commands_t command, uint16_t repeat_count, uint32_t delay_ms);
|
||||
|
||||
// --- MOTOR CONTROL COMMANDS ---
|
||||
// Stop motor (send MOTOR_STOP command)
|
||||
dshot_command_result_t stopMotor();
|
||||
dshot_result_t stopMotor();
|
||||
|
||||
// Enable/disable 3D mode
|
||||
dshot_command_result_t set3DMode(bool enable);
|
||||
dshot_result_t set3DMode(bool enable);
|
||||
|
||||
// Set motor spin direction
|
||||
dshot_command_result_t setSpinDirection(bool reversed);
|
||||
dshot_result_t setSpinDirection(bool reversed);
|
||||
|
||||
// Save current settings to ESC
|
||||
dshot_command_result_t saveSettings();
|
||||
dshot_result_t saveSettings();
|
||||
|
||||
// --- TELEMETRY COMMANDS ---
|
||||
// Enable/disable extended telemetry
|
||||
dshot_command_result_t setExtendedTelemetry(bool enable);
|
||||
dshot_result_t setExtendedTelemetry(bool enable);
|
||||
|
||||
// Request ESC information
|
||||
dshot_command_result_t requestESCInfo();
|
||||
dshot_result_t requestESCInfo();
|
||||
|
||||
// --- LED CONTROL COMMANDS (BLHeli32 only) ---
|
||||
|
||||
// Control ESC LEDs (BLHeli32 only)
|
||||
dshot_command_result_t setLED(uint8_t led_number, bool state);
|
||||
dshot_result_t setLED(uint8_t led_number, bool state);
|
||||
|
||||
// --- BEACON COMMANDS ---
|
||||
// Activate beacon (motor beeping)
|
||||
dshot_command_result_t activateBeacon(uint8_t beacon_number);
|
||||
dshot_result_t activateBeacon(uint8_t beacon_number);
|
||||
|
||||
// --- KISS ESC SPECIFIC COMMANDS ---
|
||||
// Enable/disable audio stream mode (KISS ESCs)
|
||||
dshot_command_result_t setAudioStreamMode(bool enable);
|
||||
dshot_result_t setAudioStreamMode(bool enable);
|
||||
|
||||
// Enable/disable silent mode (KISS ESCs)
|
||||
dshot_command_result_t setSilentMode(bool enable);
|
||||
dshot_result_t setSilentMode(bool enable);
|
||||
|
||||
// --- SEQUENCE COMMANDS ---
|
||||
// Execute a sequence of DShot commands
|
||||
dshot_command_result_t executeSequence(const dshot_command_sequence_item_t *sequence, size_t sequence_length);
|
||||
dshot_result_t executeSequence(const dshot_command_sequence_item_t *sequence, size_t sequence_length);
|
||||
|
||||
// Execute ESC initialization sequence
|
||||
dshot_command_result_t executeInitSequence();
|
||||
dshot_result_t executeInitSequence();
|
||||
|
||||
// Execute ESC calibration sequence
|
||||
dshot_command_result_t executeCalibrationSequence();
|
||||
dshot_result_t executeCalibrationSequence();
|
||||
|
||||
// --- UTILITY METHODS ---
|
||||
// Get command name as string
|
||||
|
|
@ -104,12 +91,6 @@ public:
|
|||
// Check if command is valid
|
||||
static bool isValidCommand(dshot_commands_t command);
|
||||
|
||||
// Print command execution statistics
|
||||
void printStatistics(Stream &output = Serial) const;
|
||||
|
||||
// Reset execution statistics
|
||||
void resetStatistics();
|
||||
|
||||
// --- GETTERS ---
|
||||
// Get total number of commands sent
|
||||
uint32_t getTotalCommandCount() const { return _total_commands_sent; }
|
||||
|
|
@ -117,26 +98,23 @@ public:
|
|||
// Get number of failed commands
|
||||
uint32_t getFailedCommandCount() const { return _failed_commands; }
|
||||
|
||||
// Get last command execution time
|
||||
uint32_t getLastExecutionTime() const { return _last_execution_time_us; }
|
||||
// Get reference to underlying DShotRMT instance
|
||||
DShotRMT &getDShotRMT() { return _dshot; }
|
||||
const DShotRMT &getDShotRMT() const { return _dshot; }
|
||||
|
||||
private:
|
||||
// --- PRIVATE MEMBERS ---
|
||||
DShotRMT &_dshot; // Reference to DShotRMT instance
|
||||
uint32_t _total_commands_sent; // Total commands sent counter
|
||||
uint32_t _failed_commands; // Failed commands counter
|
||||
uint32_t _last_execution_time_us; // Last command execution time
|
||||
uint64_t _last_command_timestamp; // Timestamp of last command
|
||||
|
||||
// --- PRIVATE METHODS ---
|
||||
// Execute single command with timing
|
||||
dshot_command_result_t _executeCommand(dshot_commands_t command);
|
||||
dshot_result_t _executeCommand(dshot_commands_t command);
|
||||
|
||||
// Wait for specified delay
|
||||
void _delay(uint32_t delay_ms);
|
||||
|
||||
// Update execution statistics
|
||||
void _updateStatistics(bool success, uint32_t execution_time_us);
|
||||
void _delay_ms(uint32_t delay_ms);
|
||||
|
||||
// --- CONSTANTS ---
|
||||
static constexpr uint32_t DEFAULT_COMMAND_DELAY_MS = 10;
|
||||
|
|
|
|||
107
DShotRMT.cpp
107
DShotRMT.cpp
|
|
@ -29,6 +29,8 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional)
|
|||
_last_erpm(0),
|
||||
_parsed_packet(0),
|
||||
_packet{0},
|
||||
_total_transmissions(0),
|
||||
_failed_transmissions(0),
|
||||
_rmt_tx_channel(nullptr),
|
||||
_rmt_rx_channel(nullptr),
|
||||
_dshot_encoder(nullptr),
|
||||
|
|
@ -90,33 +92,43 @@ DShotRMT::~DShotRMT()
|
|||
}
|
||||
|
||||
// Initialize DShotRMT
|
||||
uint16_t DShotRMT::begin()
|
||||
dshot_result_t DShotRMT::begin()
|
||||
{
|
||||
dshot_result_t result = {false, UNKNOWN_ERROR};
|
||||
uint64_t start_time = esp_timer_get_time();
|
||||
|
||||
// Init RX channel first
|
||||
if (_is_bidirectional)
|
||||
{
|
||||
if (!_initRXChannel())
|
||||
{
|
||||
result.error_message = RX_INIT_FAILED;
|
||||
_dshot_log(RX_INIT_FAILED);
|
||||
return DSHOT_ERROR;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Init TX channel
|
||||
if (!_initTXChannel())
|
||||
{
|
||||
result.error_message = TX_INIT_FAILED;
|
||||
_dshot_log(TX_INIT_FAILED);
|
||||
return DSHOT_ERROR;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Init DShot encoder
|
||||
if (_initDShotEncoder() != DSHOT_OK)
|
||||
{
|
||||
result.error_message = ENCODER_INIT_FAILED;
|
||||
_dshot_log(ENCODER_INIT_FAILED);
|
||||
return DSHOT_ERROR;
|
||||
return result;
|
||||
}
|
||||
|
||||
return DSHOT_OK;
|
||||
uint64_t end_time = esp_timer_get_time();
|
||||
result.success = true;
|
||||
result.error_message = INIT_SUCCESS;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Init RMT TX channel
|
||||
|
|
@ -212,9 +224,10 @@ bool DShotRMT::_initDShotEncoder()
|
|||
}
|
||||
|
||||
// Send throttle value
|
||||
bool DShotRMT::sendThrottle(uint16_t throttle)
|
||||
dshot_result_t DShotRMT::sendThrottle(uint16_t throttle)
|
||||
{
|
||||
static uint16_t last_throttle = DSHOT_CMD_MOTOR_STOP;
|
||||
dshot_result_t result = {false, UNKNOWN_ERROR};
|
||||
|
||||
// Special case: if throttle is 0, use sendCommand() instead
|
||||
if (throttle == 0)
|
||||
|
|
@ -226,6 +239,7 @@ bool DShotRMT::sendThrottle(uint16_t throttle)
|
|||
if ((throttle < DSHOT_THROTTLE_MIN || throttle > DSHOT_THROTTLE_MAX) && throttle != last_throttle)
|
||||
{
|
||||
_dshot_log(THROTTLE_NOT_IN_RANGE);
|
||||
result.error_message = THROTTLE_NOT_IN_RANGE;
|
||||
}
|
||||
|
||||
// Always store the original throttle value
|
||||
|
|
@ -234,17 +248,21 @@ bool DShotRMT::sendThrottle(uint16_t throttle)
|
|||
// Constrain throttle for transmission and send
|
||||
uint16_t new_throttle = constrain(throttle, DSHOT_THROTTLE_MIN, DSHOT_THROTTLE_MAX);
|
||||
_packet = _buildDShotPacket(new_throttle);
|
||||
|
||||
return _sendDShotFrame(_packet);
|
||||
}
|
||||
|
||||
// Send DShot command to ESC
|
||||
bool DShotRMT::sendCommand(uint16_t command)
|
||||
dshot_result_t DShotRMT::sendCommand(uint16_t command)
|
||||
{
|
||||
dshot_result_t result = {false, UNKNOWN_ERROR};
|
||||
|
||||
// Validate command is within DShot specification range
|
||||
if (command < DSHOT_CMD_MOTOR_STOP || command > DSHOT_CMD_MAX)
|
||||
{
|
||||
_dshot_log(COMMAND_NOT_VALID);
|
||||
return DSHOT_ERROR;
|
||||
result.error_message = COMMAND_NOT_VALID;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Build packet and transmit
|
||||
|
|
@ -252,7 +270,41 @@ bool DShotRMT::sendCommand(uint16_t command)
|
|||
return _sendDShotFrame(_packet);
|
||||
}
|
||||
|
||||
// Get RPM from ESC (bidirectional mode only)
|
||||
// Get telemetry data with timing and error handling
|
||||
dshot_telemetry_result_t DShotRMT::getTelemetry(uint8_t magnet_count)
|
||||
{
|
||||
dshot_telemetry_result_t result = {false, 0, 0, UNKNOWN_ERROR};
|
||||
|
||||
// Check if bidirectional mode is enabled
|
||||
if (!_is_bidirectional)
|
||||
{
|
||||
result.error_message = BIDIR_NOT_ENABLED;
|
||||
_dshot_log(BIDIR_NOT_ENABLED);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get eRPM
|
||||
uint16_t erpm = getERPM();
|
||||
|
||||
if (erpm == DSHOT_NULL_PACKET)
|
||||
{
|
||||
result.error_message = TELEMETRY_TIMEOUT;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Calculate motor RPM
|
||||
uint8_t pole_pairs = max(1, magnet_count / 2);
|
||||
uint32_t motor_rpm = erpm / pole_pairs;
|
||||
|
||||
result.success = true;
|
||||
result.erpm = erpm;
|
||||
result.motor_rpm = motor_rpm;
|
||||
result.error_message = TELEMETRY_SUCCESS;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get RPM from ESC (bidirectional mode only) - backward compatibility
|
||||
uint16_t DShotRMT::getERPM()
|
||||
{
|
||||
// Check if bidirectional mode is enabled
|
||||
|
|
@ -278,13 +330,6 @@ uint16_t DShotRMT::getERPM()
|
|||
return _last_erpm;
|
||||
}
|
||||
|
||||
// Convert eRPM to actual motor RPM
|
||||
uint32_t DShotRMT::getMotorRPM(uint8_t magnet_count)
|
||||
{
|
||||
uint8_t pole_pairs = max(1, magnet_count / 2);
|
||||
return getERPM() / pole_pairs;
|
||||
}
|
||||
|
||||
// Build a complete DShot packet
|
||||
dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t value)
|
||||
{
|
||||
|
|
@ -338,12 +383,15 @@ uint16_t DShotRMT::_calculateCRC(const uint16_t data)
|
|||
}
|
||||
|
||||
// Transmit DShot packet via RMT
|
||||
bool DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
||||
dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
||||
{
|
||||
dshot_result_t result = {false, UNKNOWN_ERROR};
|
||||
uint64_t start_time = esp_timer_get_time();
|
||||
|
||||
// Check timing requirements
|
||||
if (!_timer_signal())
|
||||
{
|
||||
return DSHOT_ERROR;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Enable RMT RX before RMT TX
|
||||
|
|
@ -352,7 +400,11 @@ bool DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
|||
// Performance reasons
|
||||
rmt_symbol_word_t rx_symbols[DSHOT_BITS_PER_FRAME];
|
||||
|
||||
rmt_receive(_rmt_rx_channel, rx_symbols, sizeof(rx_symbols), &_receive_config);
|
||||
if (rmt_receive(_rmt_rx_channel, rx_symbols, sizeof(rx_symbols), &_receive_config) != DSHOT_OK)
|
||||
{
|
||||
result.error_message = RX_RMT_RECEIVER_ERROR;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Local for performance
|
||||
|
|
@ -370,16 +422,18 @@ bool DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
|||
// Disable RMT RX for sending
|
||||
if (rmt_disable(_rmt_rx_channel) != DSHOT_OK)
|
||||
{
|
||||
result.error_message = RX_RMT_RECEIVER_ERROR;
|
||||
_dshot_log(RX_RMT_RECEIVER_ERROR);
|
||||
return DSHOT_ERROR;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform RMT transmission
|
||||
if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, tx_symbols, tx_size_bytes, &_transmit_config) != DSHOT_OK)
|
||||
{
|
||||
result.error_message = TRANSMITTER_ERROR;
|
||||
_dshot_log(TRANSMITTER_ERROR);
|
||||
return DSHOT_ERROR;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Re-enable RMT RX
|
||||
|
|
@ -387,15 +441,20 @@ bool DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
|||
{
|
||||
if (rmt_enable(_rmt_rx_channel) != DSHOT_OK)
|
||||
{
|
||||
result.error_message = RX_RMT_RECEIVER_ERROR;
|
||||
_dshot_log(RX_RMT_RECEIVER_ERROR);
|
||||
return DSHOT_ERROR;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Update timestamp and return success
|
||||
// Update timestamp and calculate execution time
|
||||
_timer_reset();
|
||||
uint64_t end_time = esp_timer_get_time();
|
||||
|
||||
return DSHOT_OK;
|
||||
result.success = true;
|
||||
result.error_message = TRANSMISSION_SUCCESS;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Encode DShot packet into RMT symbol format (placed in IRAM for performance)
|
||||
|
|
|
|||
74
DShotRMT.h
74
DShotRMT.h
|
|
@ -65,14 +65,31 @@ typedef struct
|
|||
uint16_t ticks_zero_low;
|
||||
} dshot_timing_t;
|
||||
|
||||
// Command execution result structure
|
||||
typedef struct
|
||||
{
|
||||
bool success;
|
||||
const char *error_message;
|
||||
} dshot_result_t;
|
||||
|
||||
// DShot telemetry result structure
|
||||
typedef struct
|
||||
{
|
||||
bool success;
|
||||
uint16_t erpm;
|
||||
uint32_t motor_rpm;
|
||||
const char *error_message;
|
||||
} dshot_telemetry_result_t;
|
||||
|
||||
// Naming convention
|
||||
typedef dshotCommands_e dshot_commands_t;
|
||||
|
||||
//
|
||||
class DShotRMT
|
||||
{
|
||||
public:
|
||||
// Constructor with GPIO enum
|
||||
explicit DShotRMT(gpio_num_t gpio = GPIO_NUM_16,
|
||||
dshot_mode_t mode = DSHOT300,
|
||||
bool is_bidirectional = false);
|
||||
explicit DShotRMT(gpio_num_t gpio = GPIO_NUM_16, dshot_mode_t mode = DSHOT300, bool is_bidirectional = false);
|
||||
|
||||
// Constructor with pin number
|
||||
DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional);
|
||||
|
|
@ -81,24 +98,29 @@ public:
|
|||
~DShotRMT();
|
||||
|
||||
// Initialize the RMT module and DShot config
|
||||
uint16_t begin();
|
||||
dshot_result_t begin();
|
||||
|
||||
// Send throttle value (48-2047)
|
||||
bool sendThrottle(uint16_t throttle);
|
||||
dshot_result_t sendThrottle(uint16_t throttle);
|
||||
|
||||
// Send DShot command (0-47)
|
||||
bool sendCommand(uint16_t command);
|
||||
dshot_result_t sendCommand(uint16_t command);
|
||||
|
||||
// Get telemetry data (bidirectional mode only)
|
||||
dshot_telemetry_result_t getTelemetry(uint8_t magnet_count = 14);
|
||||
|
||||
// Get eRPM only (bidirectional mode only)
|
||||
uint16_t getERPM();
|
||||
|
||||
// Convert eRPM to motor RPM
|
||||
uint32_t getMotorRPM(uint8_t magnet_count);
|
||||
|
||||
//
|
||||
// --- GETTERS ---
|
||||
gpio_num_t getGPIO() const { return _gpio; }
|
||||
uint16_t getDShotPacket() const { return _parsed_packet; }
|
||||
bool is_bidirectional() const { return _is_bidirectional; }
|
||||
dshot_mode_t getMode() const { return _mode; }
|
||||
|
||||
// Get execution statistics
|
||||
uint32_t getTotalTransmissions() const { return _total_transmissions; }
|
||||
uint32_t getFailedTransmissions() const { return _failed_transmissions; }
|
||||
|
||||
// --- INFO ---
|
||||
void printDShotInfo(Stream &output = Serial) const;
|
||||
|
|
@ -106,10 +128,25 @@ public:
|
|||
|
||||
// --- DEPRECATED METHODS ---
|
||||
[[deprecated("Use sendThrottle() instead")]]
|
||||
bool setThrottle(uint16_t throttle) { return sendThrottle(throttle); }
|
||||
bool setThrottle(uint16_t throttle)
|
||||
{
|
||||
auto result = sendThrottle(throttle);
|
||||
return result.success;
|
||||
}
|
||||
|
||||
[[deprecated("Use sendCommand() instead")]]
|
||||
bool sendDShotCommand(uint16_t command) { return sendCommand(command); }
|
||||
bool sendDShotCommand(uint16_t command)
|
||||
{
|
||||
auto result = sendCommand(command);
|
||||
return result.success;
|
||||
}
|
||||
|
||||
[[deprecated("Use getTelemetry() instead")]]
|
||||
uint32_t getMotorRPM(uint8_t magnet_count)
|
||||
{
|
||||
auto result = getTelemetry(magnet_count);
|
||||
return result.success;
|
||||
}
|
||||
|
||||
private:
|
||||
// --- CONFIG ---
|
||||
|
|
@ -125,6 +162,10 @@ private:
|
|||
uint16_t _parsed_packet;
|
||||
dshot_packet_t _packet;
|
||||
|
||||
// --- STATISTICS ---
|
||||
uint32_t _total_transmissions;
|
||||
uint32_t _failed_transmissions;
|
||||
|
||||
// --- RMT HARDWARE HANDLES ---
|
||||
rmt_channel_handle_t _rmt_tx_channel;
|
||||
rmt_channel_handle_t _rmt_rx_channel;
|
||||
|
|
@ -147,7 +188,7 @@ private:
|
|||
uint16_t _calculateCRC(const uint16_t data);
|
||||
|
||||
// --- FRAME PROCESSING ---
|
||||
bool _sendDShotFrame(const dshot_packet_t &packet);
|
||||
dshot_result_t _sendDShotFrame(const dshot_packet_t &packet);
|
||||
bool IRAM_ATTR _encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols);
|
||||
uint16_t _decodeDShotFrame(const rmt_symbol_word_t *symbols);
|
||||
|
||||
|
|
@ -164,13 +205,14 @@ private:
|
|||
static constexpr auto DSHOT_TELEMETRY_INVALID = (0xffff);
|
||||
|
||||
// --- ERROR HANDLING & LOGGING ---
|
||||
void _dshot_log(const char *msg, Stream &output = Serial) { output.println(msg); }
|
||||
void _dshot_log(const char *msg, Stream &output = Serial) const { output.println(msg); }
|
||||
|
||||
// --- CONSTANTS & ERROR MESSAGES ---
|
||||
static constexpr bool DSHOT_OK = 0;
|
||||
static constexpr bool DSHOT_ERROR = 1;
|
||||
|
||||
static constexpr char *NEW_LINE = " ";
|
||||
static constexpr char *UNKNOWN_ERROR = "Unknown Error!";
|
||||
static constexpr char *TX_INIT_FAILED = "Failed to initialize TX channel!";
|
||||
static constexpr char *RX_INIT_FAILED = "Failed to initialize RX channel!";
|
||||
static constexpr char *ENCODER_INIT_FAILED = "Failed to initialize DShot encoder!";
|
||||
|
|
@ -181,4 +223,8 @@ private:
|
|||
static constexpr char *RX_RMT_RECEIVER_ERROR = "RX RMT receiver error!";
|
||||
static constexpr char *PACKET_BUILD_ERROR = "Value too big for DShot Packet!";
|
||||
static constexpr char *TRANSMITTER_ERROR = "RMT TX Transmitter Error!";
|
||||
static constexpr char *INIT_SUCCESS = "DShotRMT initialized successfully";
|
||||
static constexpr char *TELEMETRY_SUCCESS = "Telemetry read successfully";
|
||||
static constexpr char *TELEMETRY_TIMEOUT = "Telemetry read timeout";
|
||||
static constexpr char *TRANSMISSION_SUCCESS = "Transmission successful";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
/*
|
||||
* command_manager_example.ino
|
||||
* Example sketch demonstrating DShotCommandManager usage
|
||||
* command_manager.ino
|
||||
* Example sketch for DShotCommandManager
|
||||
* Author: Wastl Kraus
|
||||
* Date: 2025-09-04
|
||||
* License: MIT
|
||||
*
|
||||
* Modified by Especiallist to support continuous throttle sending.
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
|
@ -28,7 +26,20 @@ DShotRMT motor01(MOTOR01_PIN, DSHOT300, IS_BIDIRECTIONAL);
|
|||
DShotCommandManager commandManager(motor01);
|
||||
|
||||
// Global variable to store the desired continuous throttle value
|
||||
static volatile uint16_t throttle_now = NULL;
|
||||
static volatile uint16_t throttle_now = 0;
|
||||
|
||||
// Helper function to print telemetry results
|
||||
void printTelemetryResult(const dshot_telemetry_result_t &result)
|
||||
{
|
||||
if (result.success)
|
||||
{
|
||||
USB_SERIAL.printf("Telemetry: eRPM=%u, Motor RPM=%u\n", result.erpm, result.motor_rpm);
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_SERIAL.printf("Telemetry: FAILED - %s\n", result.error_message);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
void setup()
|
||||
|
|
@ -36,25 +47,11 @@ void setup()
|
|||
// Start USB Serial Port
|
||||
USB_SERIAL.begin(USB_SERIAL_BAUD);
|
||||
|
||||
USB_SERIAL.println("=== DShotRMT Command Manager Example ===");
|
||||
|
||||
// Initialize DShot
|
||||
if (motor01.begin() != 0)
|
||||
{
|
||||
USB_SERIAL.println("ERROR: Failed to initialize DShotRMT!");
|
||||
while (1)
|
||||
delay(1000);
|
||||
}
|
||||
motor01.begin();
|
||||
|
||||
// Init Command Manager
|
||||
if (!commandManager.begin())
|
||||
{
|
||||
USB_SERIAL.println("ERROR: Failed to initialize DShotCommandManager!");
|
||||
while (1)
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
USB_SERIAL.println("Initialization successful!");
|
||||
commandManager.begin();
|
||||
|
||||
// Print Menu
|
||||
printMenu();
|
||||
|
|
@ -75,9 +72,15 @@ void loop()
|
|||
}
|
||||
|
||||
// Continuously send the stored throttle value
|
||||
if (throttle_now != NULL)
|
||||
if (throttle_now != 0)
|
||||
{
|
||||
motor01.sendThrottle(throttle_now);
|
||||
dshot_result_t result = motor01.sendThrottle(throttle_now);
|
||||
|
||||
// Only print errors to avoid spam
|
||||
if (!result.success)
|
||||
{
|
||||
printResult(result);
|
||||
}
|
||||
|
||||
// Print motor stats every 2 seconds
|
||||
if (esp_timer_get_time() - last_stats_print >= 2000000)
|
||||
|
|
@ -87,8 +90,8 @@ void loop()
|
|||
// Get Motor RPM
|
||||
if (IS_BIDIRECTIONAL)
|
||||
{
|
||||
uint32_t rpm = motor01.getMotorRPM(MOTOR01_MAGNET_COUNT);
|
||||
USB_SERIAL.printf("Motor RPM: %u\n", rpm);
|
||||
dshot_telemetry_result_t telem_result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT);
|
||||
printTelemetryResult(telem_result);
|
||||
}
|
||||
|
||||
// Time Stamp
|
||||
|
|
@ -100,92 +103,64 @@ void loop()
|
|||
//
|
||||
void handleUserInput(const String &input)
|
||||
{
|
||||
dshot_command_result_t result;
|
||||
dshot_result_t cmd_result;
|
||||
|
||||
if (input == "1")
|
||||
{
|
||||
// Stop motor command should also reset the continuous throttle value
|
||||
throttle_now = 0;
|
||||
USB_SERIAL.print("Stopping motor... ");
|
||||
result = commandManager.stopMotor();
|
||||
printResult(result);
|
||||
cmd_result = commandManager.stopMotor();
|
||||
printResult(cmd_result);
|
||||
}
|
||||
else if (input == "2")
|
||||
{
|
||||
USB_SERIAL.print("Activating beacon 1... ");
|
||||
result = commandManager.activateBeacon(1);
|
||||
printResult(result);
|
||||
cmd_result = commandManager.activateBeacon(1);
|
||||
printResult(cmd_result);
|
||||
}
|
||||
else if (input == "3")
|
||||
{
|
||||
USB_SERIAL.print("Setting normal spin direction... ");
|
||||
result = commandManager.setSpinDirection(false);
|
||||
printResult(result);
|
||||
cmd_result = commandManager.setSpinDirection(false);
|
||||
printResult(cmd_result);
|
||||
}
|
||||
else if (input == "4")
|
||||
{
|
||||
USB_SERIAL.print("Setting reversed spin direction... ");
|
||||
result = commandManager.setSpinDirection(true);
|
||||
printResult(result);
|
||||
cmd_result = commandManager.setSpinDirection(true);
|
||||
printResult(cmd_result);
|
||||
}
|
||||
else if (input == "5")
|
||||
{
|
||||
USB_SERIAL.print("Enabling 3D mode... ");
|
||||
result = commandManager.set3DMode(true);
|
||||
printResult(result);
|
||||
USB_SERIAL.print("Getting ESC Info... ");
|
||||
cmd_result = commandManager.requestESCInfo();
|
||||
printResult(cmd_result);
|
||||
}
|
||||
else if (input == "6")
|
||||
{
|
||||
USB_SERIAL.print("Disabling 3D mode... ");
|
||||
result = commandManager.set3DMode(false);
|
||||
printResult(result);
|
||||
USB_SERIAL.print("Turning LED 0 ON... ");
|
||||
cmd_result = commandManager.setLED(0, true);
|
||||
printResult(cmd_result);
|
||||
}
|
||||
else if (input == "7")
|
||||
{
|
||||
USB_SERIAL.print("Saving settings... ");
|
||||
result = commandManager.saveSettings();
|
||||
printResult(result);
|
||||
}
|
||||
else if (input == "8")
|
||||
{
|
||||
USB_SERIAL.print("Turning LED 0 ON... ");
|
||||
result = commandManager.setLED(0, true);
|
||||
printResult(result);
|
||||
}
|
||||
else if (input == "9")
|
||||
{
|
||||
USB_SERIAL.print("Turning LED 0 OFF... ");
|
||||
result = commandManager.setLED(0, false);
|
||||
printResult(result);
|
||||
cmd_result = commandManager.setLED(0, false);
|
||||
printResult(cmd_result);
|
||||
}
|
||||
else if (input == "i")
|
||||
{
|
||||
USB_SERIAL.print("Executing initialization sequence... ");
|
||||
result = commandManager.executeInitSequence();
|
||||
printResult(result);
|
||||
}
|
||||
else if (input == "c")
|
||||
{
|
||||
USB_SERIAL.print("Executing calibration sequence... ");
|
||||
result = commandManager.executeCalibrationSequence();
|
||||
printResult(result);
|
||||
}
|
||||
else if (input == "s")
|
||||
{
|
||||
commandManager.printStatistics();
|
||||
}
|
||||
else if (input == "r")
|
||||
{
|
||||
commandManager.resetStatistics();
|
||||
USB_SERIAL.println("Statistics reset.");
|
||||
}
|
||||
else if (input == "h")
|
||||
else if (input == "h" || input == "help")
|
||||
{
|
||||
printMenu();
|
||||
}
|
||||
else if (input == "help")
|
||||
else if (input == "info")
|
||||
{
|
||||
printMenu();
|
||||
motor01.printDShotInfo();
|
||||
}
|
||||
else if (input == "rpm" && IS_BIDIRECTIONAL)
|
||||
{
|
||||
dshot_telemetry_result_t result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT);
|
||||
printTelemetryResult(result);
|
||||
}
|
||||
else if (input.startsWith("cmd "))
|
||||
{
|
||||
|
|
@ -195,8 +170,8 @@ void handleUserInput(const String &input)
|
|||
{
|
||||
USB_SERIAL.printf("Sending command %d (%s)... ", cmd_num,
|
||||
DShotCommandManager::getCommandName(static_cast<dshot_commands_t>(cmd_num)));
|
||||
result = commandManager.sendCommand(static_cast<dshot_commands_t>(cmd_num));
|
||||
printResult(result);
|
||||
cmd_result = commandManager.sendCommand(static_cast<dshot_commands_t>(cmd_num));
|
||||
printResult(cmd_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -211,65 +186,139 @@ void handleUserInput(const String &input)
|
|||
{
|
||||
throttle_now = throttle_value;
|
||||
USB_SERIAL.printf("Setting continuous throttle to %d\n", throttle_now);
|
||||
|
||||
// Send first throttle command and show result
|
||||
dshot_result_t result = motor01.sendThrottle(throttle_now);
|
||||
printResult(result);
|
||||
|
||||
if (result.success)
|
||||
{
|
||||
USB_SERIAL.println("Continuous throttle mode enabled. Send '0' or 'throttle 0' to stop.");
|
||||
}
|
||||
}
|
||||
else if (throttle_value == 0)
|
||||
{
|
||||
throttle_now = 0;
|
||||
USB_SERIAL.println("Continuous throttle stopped.");
|
||||
|
||||
// Send stop command
|
||||
dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
|
||||
printResult(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_SERIAL.printf("Invalid throttle value: %d (valid range: 48-2047, use 0 to stop)\n", throttle_value);
|
||||
USB_SERIAL.printf("Invalid throttle value: %d (valid range: %d-%d, use 0 to stop)\n",
|
||||
throttle_value, DSHOT_THROTTLE_MIN, DSHOT_THROTTLE_MAX);
|
||||
}
|
||||
}
|
||||
else if (input == "0")
|
||||
{
|
||||
// Quick stop
|
||||
throttle_now = 0;
|
||||
USB_SERIAL.print("Emergency stop... ");
|
||||
dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
|
||||
printResult(result);
|
||||
}
|
||||
else if (input.startsWith("repeat "))
|
||||
{
|
||||
// Repeat command: "repeat cmd 5 count 10" - sends command 5 ten times
|
||||
String params = input.substring(7);
|
||||
if (params.startsWith("cmd "))
|
||||
{
|
||||
int space_pos = params.indexOf(' ', 4);
|
||||
if (space_pos > 0 && params.substring(space_pos + 1).startsWith("count "))
|
||||
{
|
||||
int cmd_num = params.substring(4, space_pos).toInt();
|
||||
int repeat_count = params.substring(space_pos + 7).toInt();
|
||||
|
||||
if (DShotCommandManager::isValidCommand(static_cast<dshot_commands_t>(cmd_num)) &&
|
||||
repeat_count > 0 && repeat_count <= 100)
|
||||
{
|
||||
USB_SERIAL.printf("Sending command %d (%s) %d times... ", cmd_num,
|
||||
DShotCommandManager::getCommandName(static_cast<dshot_commands_t>(cmd_num)),
|
||||
repeat_count);
|
||||
cmd_result = commandManager.sendCommand(static_cast<dshot_commands_t>(cmd_num), repeat_count);
|
||||
printResult(cmd_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_SERIAL.println("Invalid command or repeat count (1-100)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_SERIAL.println("Unknown command. Type 'h' for help.");
|
||||
USB_SERIAL.println("Usage: repeat cmd <number> count <repeat_count>");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_SERIAL.println("Usage: repeat cmd <number> count <repeat_count>");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_SERIAL.printf("Unknown command: '%s'. Type 'h' or 'help' for help.\n", input.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
void printResult(const dshot_command_result_t &result)
|
||||
void printResult(const dshot_result_t &result)
|
||||
{
|
||||
if (!result.success)
|
||||
if (result.success)
|
||||
{
|
||||
USB_SERIAL.printf("SUCCESS (%u us)\n", result.execution_time_us);
|
||||
USB_SERIAL.printf("SUCCESS\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_SERIAL.printf("FAILED - %s (%u us)\n", result.error_message, result.execution_time_us);
|
||||
USB_SERIAL.printf("FAILED - %s \n", result.error_message);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
void printSystemStatus()
|
||||
{
|
||||
USB_SERIAL.println("\n=== System Status ===");
|
||||
USB_SERIAL.printf("Current throttle: %u\n", throttle_now);
|
||||
USB_SERIAL.printf("Continuous mode: %s\n", throttle_now > 0 ? "ACTIVE" : "INACTIVE");
|
||||
USB_SERIAL.printf("GPIO Pin: %d\n", motor01.getGPIO());
|
||||
USB_SERIAL.printf("DShot Mode: DSHOT%d\n",
|
||||
motor01.getMode() == DSHOT150 ? 150 : motor01.getMode() == DSHOT300 ? 300
|
||||
: motor01.getMode() == DSHOT600 ? 600
|
||||
: motor01.getMode() == DSHOT1200 ? 1200
|
||||
: 0);
|
||||
USB_SERIAL.printf("Bidirectional: %s\n", motor01.is_bidirectional() ? "YES" : "NO");
|
||||
USB_SERIAL.printf("Free heap: %u bytes\n", ESP.getFreeHeap());
|
||||
USB_SERIAL.printf("Uptime: %lu seconds\n", millis() / 1000);
|
||||
}
|
||||
|
||||
//
|
||||
void printMenu()
|
||||
{
|
||||
USB_SERIAL.println("================================================");
|
||||
USB_SERIAL.println("\n=== DShot Command Manager Menu ===");
|
||||
USB_SERIAL.println("Basic Commands:");
|
||||
USB_SERIAL.println("**********************************************");
|
||||
USB_SERIAL.println(" DShot Command Manager Menu ");
|
||||
USB_SERIAL.println("**********************************************");
|
||||
USB_SERIAL.println(" 1 - Stop Motor");
|
||||
USB_SERIAL.println(" 2 - Activate Beacon 1");
|
||||
USB_SERIAL.println(" 3 - Set Normal Spin Direction");
|
||||
USB_SERIAL.println(" 4 - Set Reversed Spin Direction");
|
||||
USB_SERIAL.println(" 5 - Enable 3D Mode");
|
||||
USB_SERIAL.println(" 6 - Disable 3D Mode");
|
||||
USB_SERIAL.println(" 7 - Save Settings");
|
||||
USB_SERIAL.println(" 8 - Turn LED 0 ON");
|
||||
USB_SERIAL.println(" 9 - Turn LED 0 OFF");
|
||||
USB_SERIAL.println("");
|
||||
USB_SERIAL.println("Sequences:");
|
||||
USB_SERIAL.println(" i - Execute Initialization Sequence");
|
||||
USB_SERIAL.println(" c - Execute Calibration Sequence");
|
||||
USB_SERIAL.println("");
|
||||
USB_SERIAL.println("Advanced:");
|
||||
USB_SERIAL.println(" cmd <number> - Send DShot command (0 - 47)");
|
||||
USB_SERIAL.println(" 3 - Set Normal Spin");
|
||||
USB_SERIAL.println(" 4 - Set Reversed Spin");
|
||||
USB_SERIAL.println(" 5 - Get ESC Info");
|
||||
USB_SERIAL.println(" 6 - Turn LED 0 ON");
|
||||
USB_SERIAL.println(" 7 - Turn LED 0 OFF");
|
||||
USB_SERIAL.println(" 0 - Emergency Stop");
|
||||
USB_SERIAL.println("**********************************************");
|
||||
USB_SERIAL.println(" cmd <number> - Send Command (0 - 47)");
|
||||
USB_SERIAL.println(" throttle <value> - Set throttle (48 - 2047)");
|
||||
USB_SERIAL.println(" throttle 0 - Stop sending throttle");
|
||||
USB_SERIAL.println("");
|
||||
USB_SERIAL.println(" h - Show this Menu");
|
||||
USB_SERIAL.println("");
|
||||
USB_SERIAL.println("Examples:");
|
||||
USB_SERIAL.println(" cmd 1 - Stop Motor");
|
||||
USB_SERIAL.println(" throttle 1000 - Set throttle to 1000");
|
||||
USB_SERIAL.println("================================================");
|
||||
USB_SERIAL.println("**********************************************");
|
||||
USB_SERIAL.println(" info - Show DShot signal info");
|
||||
USB_SERIAL.println(" status - Show system status");
|
||||
if (IS_BIDIRECTIONAL)
|
||||
{
|
||||
USB_SERIAL.println(" rpm - Get telemetry data");
|
||||
}
|
||||
USB_SERIAL.println(" h / help - Show this Menu");
|
||||
USB_SERIAL.println("**********************************************");
|
||||
USB_SERIAL.println("EXAMPLE INPUT:");
|
||||
USB_SERIAL.println(" cmd 5 - Get ESC Info");
|
||||
USB_SERIAL.println(" throttle 1000 - Set throttle to 1000");
|
||||
USB_SERIAL.println("**********************************************");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@
|
|||
#include <Arduino.h>
|
||||
#include <DShotRMT.h>
|
||||
|
||||
// Debug output
|
||||
static constexpr auto DEBUG = false;
|
||||
|
||||
// USB serial port settings
|
||||
static constexpr auto &USB_SERIAL = Serial0;
|
||||
static constexpr auto USB_SERIAL_BAUD = 115200;
|
||||
|
|
@ -38,49 +35,169 @@ void setup()
|
|||
// Starts the USB Serial Port
|
||||
USB_SERIAL.begin(USB_SERIAL_BAUD);
|
||||
|
||||
// Initializes DShot Signal
|
||||
// Initialize DShot Signal
|
||||
motor01.begin();
|
||||
|
||||
// Print CPU Info
|
||||
motor01.printCpuInfo();
|
||||
|
||||
USB_SERIAL.println(" ");
|
||||
USB_SERIAL.println("***********************************");
|
||||
USB_SERIAL.println(" === DShotRMT Demo started. === ");
|
||||
USB_SERIAL.println("Enter a throttle value (48 – 2047):");
|
||||
//
|
||||
printMenu();
|
||||
}
|
||||
|
||||
//
|
||||
void loop()
|
||||
{
|
||||
/// ...safety first
|
||||
// Safety first
|
||||
static uint16_t throttle = DSHOT_CMD_MOTOR_STOP;
|
||||
static bool continuous_throttle = true;
|
||||
|
||||
// Time Measurement
|
||||
static uint32_t last_stats_print = 0;
|
||||
|
||||
// Read throttle value
|
||||
// Handle serial input
|
||||
if (USB_SERIAL.available() > 0)
|
||||
{
|
||||
throttle = USB_SERIAL.readStringUntil('\n').toInt();
|
||||
String input = USB_SERIAL.readStringUntil('\n');
|
||||
input.trim();
|
||||
|
||||
if (input.length() > 0)
|
||||
{
|
||||
handleSerialInput(input, throttle, continuous_throttle);
|
||||
}
|
||||
}
|
||||
|
||||
// Send the current throttle value
|
||||
// Send throttle value in continuous mode
|
||||
if (continuous_throttle)
|
||||
{
|
||||
motor01.sendThrottle(throttle);
|
||||
}
|
||||
|
||||
// Print motor stats every 2 seconds
|
||||
if (millis() - last_stats_print >= 2000)
|
||||
// Print motor stats every 5 seconds in continuous mode
|
||||
if (continuous_throttle && (millis() - last_stats_print >= 5000))
|
||||
{
|
||||
motor01.printDShotInfo();
|
||||
|
||||
// Get Motor RPM
|
||||
// Get Motor RPM if bidirectional
|
||||
if (IS_BIDIRECTIONAL)
|
||||
{
|
||||
uint32_t rpm = motor01.getMotorRPM(MOTOR01_MAGNET_COUNT);
|
||||
USB_SERIAL.printf("Motor RPM: %u\n", rpm);
|
||||
dshot_telemetry_result_t telem_result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT);
|
||||
printTelemetryResult(telem_result);
|
||||
}
|
||||
|
||||
// Time Stamp
|
||||
last_stats_print = millis();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
void printMenu()
|
||||
{
|
||||
USB_SERIAL.println(" ");
|
||||
USB_SERIAL.println("******************************************");
|
||||
USB_SERIAL.println(" DShotRMT Demo ");
|
||||
USB_SERIAL.println("******************************************");
|
||||
USB_SERIAL.println(" <value> - Set throttle (48 – 2047)");
|
||||
USB_SERIAL.println(" 0 - Stop motor");
|
||||
USB_SERIAL.println("******************************************");
|
||||
USB_SERIAL.println(" cmd <number> - Send DShot command (0-47)");
|
||||
USB_SERIAL.println(" info - Show motor info");
|
||||
if (IS_BIDIRECTIONAL)
|
||||
{
|
||||
USB_SERIAL.println(" rpm - Get telemetry data");
|
||||
}
|
||||
USB_SERIAL.println("******************************************");
|
||||
USB_SERIAL.println(" h / help - Show this Menu");
|
||||
USB_SERIAL.println("******************************************");
|
||||
}
|
||||
|
||||
// Helper function to print command results
|
||||
void printCommandResult(const dshot_result_t &result, const String &operation)
|
||||
{
|
||||
if (result.success)
|
||||
{
|
||||
USB_SERIAL.printf("%s: SUCCESS\n", operation.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_SERIAL.printf("%s: FAILED - %s\n", operation.c_str(), result.error_message);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to print telemetry results
|
||||
void printTelemetryResult(const dshot_telemetry_result_t &result)
|
||||
{
|
||||
if (result.success)
|
||||
{
|
||||
USB_SERIAL.printf("Telemetry: eRPM=%u, Motor RPM=%u (%s)\n", result.erpm, result.motor_rpm, result.error_message);
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_SERIAL.printf("Telemetry: FAILED - %s\n", result.error_message);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
void handleSerialInput(const String &input, uint16_t &throttle, bool &continuous_throttle)
|
||||
{
|
||||
if (input == "0")
|
||||
{
|
||||
// Stop motor
|
||||
throttle = 0;
|
||||
continuous_throttle = true; // kill motor for sure
|
||||
dshot_result_t result = motor01.sendCommand(DSHOT_CMD_MOTOR_STOP);
|
||||
printCommandResult(result, "Stop Motor");
|
||||
}
|
||||
else if (input == "info")
|
||||
{
|
||||
continuous_throttle = false;
|
||||
motor01.printDShotInfo();
|
||||
}
|
||||
else if (input == "rpm" && IS_BIDIRECTIONAL)
|
||||
{
|
||||
dshot_telemetry_result_t result = motor01.getTelemetry(MOTOR01_MAGNET_COUNT);
|
||||
printTelemetryResult(result);
|
||||
}
|
||||
else if (input.startsWith("cmd "))
|
||||
{
|
||||
continuous_throttle = false;
|
||||
|
||||
// Send DShot command
|
||||
int cmd_num = input.substring(4).toInt();
|
||||
|
||||
if (cmd_num >= DSHOT_CMD_MOTOR_STOP && cmd_num <= DSHOT_CMD_MAX)
|
||||
{
|
||||
dshot_result_t result = motor01.sendCommand(cmd_num);
|
||||
printCommandResult(result, "DShot Command " + String(cmd_num));
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_SERIAL.printf("Invalid command: %d (valid range: 0 - %d)\n", cmd_num, DSHOT_CMD_MAX);
|
||||
}
|
||||
}
|
||||
else if (input == "h" || input == "help")
|
||||
{
|
||||
printMenu();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Parse input throttle value
|
||||
int throttle_value = input.toInt();
|
||||
|
||||
if (throttle_value >= DSHOT_THROTTLE_MIN && throttle_value <= DSHOT_THROTTLE_MAX)
|
||||
{
|
||||
throttle = throttle_value;
|
||||
continuous_throttle = true;
|
||||
|
||||
dshot_result_t result = motor01.sendThrottle(throttle);
|
||||
printCommandResult(result, "Set Throttle " + String(throttle));
|
||||
|
||||
USB_SERIAL.println("Continuous throttle mode enabled. Send '0' to stop.");
|
||||
}
|
||||
else
|
||||
{
|
||||
USB_SERIAL.printf("Invalid input: '%s'\n", input.c_str());
|
||||
USB_SERIAL.printf("Valid throttle range: %d - %d\n", DSHOT_THROTTLE_MIN, DSHOT_THROTTLE_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue