Skip to content

Add UART Protocol Support for PC10/PC11 (USART3)#101

Closed
perara wants to merge 4 commits intomjbots:mainfrom
Newbringer:main
Closed

Add UART Protocol Support for PC10/PC11 (USART3)#101
perara wants to merge 4 commits intomjbots:mainfrom
Newbringer:main

Conversation

@perara
Copy link
Copy Markdown

@perara perara commented Nov 15, 2025

As previously discussed. Some are in need of UART support. Since it was not natively supported, we thought it nice to add. Feel free to adopt for the main repo if interesting.

Summary

This PR adds support for using the moteus firmware over UART with the fdcanusb ASCII protocol, enabling communication via serial adapters (e.g., USB-UART, RS485) as an alternative to CAN-FD. Its guarded behind compile macro.

Motivation

  • Enables development and testing without CAN-FD hardware
  • Provides a fallback communication method for debugging
  • Allows use of low-cost USB-UART adapters for prototyping
  • Simplifies integration with systems that have limited CAN-FD support and generally do not need CAN

Changes

Firmware (fw/)

  • fw/uart_fdcanusb_micro_server.h (new): Complete implementation of fdcanusb ASCII protocol over UART
    • Handles can send commands and rcv/OK responses
    • Full protocol compliance including ID mapping, DLC rounding, and flags (E/B/F)
    • Efficient single-buffer design with minimal RAM overhead
  • fw/moteus.cc: Conditional UART initialization and multiplex routing
    • Dual transport support (CAN-FD + UART) with proper stream routing
    • UART configured at 460800 baud on PC10 (TX) / PC11 (RX)
  • fw/moteus_hw.cc: Pin configuration for USART3 (PC10/PC11)
  • fw/moteus_controller.cc: Disable debug UART when protocol enabled to prevent pin contention
  • fw/BUILD: Fixed macro name from MOTEUS_ENABLE_UART_FDCANUSB to MOTEUS_ENABLE_UART_PROTOCOL

Python Library (lib/python/moteus/)

  • fdcanusb_device.py: Add baudrate parameter support
    • Uses explicit baudrate if provided, otherwise defaults to 9600
    • Opens serial port with exclusive=True to prevent multi-access issues
  • transport_factory.py: Add --fdcanusb-baud command-line argument
    • Allows specifying custom baud rates for serial adapters
    • Example: --fdcanusb /dev/ttyUSB0 --fdcanusb-baud 460800

Other

  • .gitignore: Added .history/ for VS Code local history files

Testing

Tested with:

# moteus_tool
python3 -m moteus.moteus_tool --target 1 --fdcanusb /dev/ttyUSB0 --fdcanusb-baud 460800 --info
python3 -m moteus.moteus_tool --target 1 --fdcanusb /dev/ttyUSB0 --fdcanusb-baud 460800 --calibrate
# tview GUI
python3 -m moteus_gui.tview --fdcanusb /dev/ttyUSB0 --fdcanusb-baud 460800 --target 1

Technical Details

  • Protocol: Implements the fdcanusb text protocol (can send XXXX PAYLOAD FLAGS\nOK\n / rcv ...)
  • Baud Rate: Default 460800 baud (configurable via --fdcanusb-baud)
  • Pins: PC10 (TX), PC11 (RX) - USART3 on STM32G4
  • Compatibility: Maintains full backward compatibility with existing CAN-FD communication

Breaking Changes

None. UART support is opt-in and does not affect existing CAN-FD functionality.

Code Size Impact

  • Firmware: +268 lines (uart_fdcanusb_micro_server.h)
  • Python: +11 lines (minimal changes for baudrate support)
  • Total: Clean, minimal implementation focused on core functionality

- Introduced `uart_fdcanusb_micro_server.h` to handle UART communication using the FDCAN USB protocol.
- Updated `BUILD` file to enable UART FDCAN USB configuration.
- Modified `moteus_controller.cc` and `moteus.cc` to integrate UART protocol handling and server polling.
- Adjusted hardware pin definitions in `moteus_hw.cc` for UART functionality.
- Updated the constructor of `FdcanusbDevice` to include an optional `baudrate` parameter, defaulting to 9600 if not provided.
- Modified the `FdcanusbFactory` to accept a command-line argument for specifying the baudrate for the serial adapter, improving flexibility for different hardware configurations.
- Changed the compilation flag from `-DMOTEUS_ENABLE_UART_FDCANUSB` to `-DMOTEUS_ENABLE_UART_PROTOCOL` to reflect the new UART protocol implementation.
- Added '.history/' to the .gitignore to prevent tracking of history files in the repository.
@jpieper
Copy link
Copy Markdown
Member

jpieper commented Nov 16, 2025

Thanks for sharing! I can't commit to merging this, but I have questions/requests:

  1. It looks like this is either/or, i.e. if you have the UART compiled in, then CAN-FD doesn't work. Is that correct? I see at least the diagnostic channel is associated with only one or the other.
  2. If it were to be merged, I'd want to have the pins used by configurable, in the same manner as the kDebug uart mechanism. I'd probably want it to be enabled by default on the aux2/abs UART pins for whatever those are for the board in question.

I admit to using the fdcanusb protocol is quite ingenious and solves a lot of problems, like maintaining interoperability with all existing tools and the python and C++ library for desktops. It was not a design alternative I had considered and makes it much more feasible. It could even be used in an RS485 multiplex bus using either a direction pin, or ignoring self sends like if the n1/x1 RS422 wires are connected together. Some downsides:

  1. It is not very simple to use on say an Arduino with limited flash space. I'm not sure that this is a problem, as the other logical alternative, the existing diagnostic protocol, does not work very well as it doesn't make it very easy to query the current state.
  2. There is no checksum or consistency check. With a UART alone, and a motor control system, bit errors are very likely as people have all kinds of electrical and EMI issues in their systems. Maybe adding a NMEA style *XX checksum at the end, which the device requires as mandatory as soon as it sees it at least once?

As mentioned, I can't commit to merging this even if every request was addressed, so take them for what you will!

@perara
Copy link
Copy Markdown
Author

perara commented Dec 13, 2025

Thanks for the feedback. We will have a look into them.

Yes for many applications the CAN does makes sense with the issues you point out. The downside of CAN is that you would for many applications / systems need intermediate chip, like the CAN to USB or even CAN to Serial. I would agree that for applications where robustness are of utmost criticality, CAN would be the top choice, but for applications without these same needs, it is a good option to interface with simple serial. For now i have kept everything identical to your protocol, but with a bit building ontop of it (not changing it) we could add the desired robustness. Essentially, changing as little as i could to make it work well.

we will address both :)

@jpieper
Copy link
Copy Markdown
Member

jpieper commented Jan 24, 2026

FYI: I'm taking a look at doing something along these lines myself in the event you were still doing anything with it.

@perara
Copy link
Copy Markdown
Author

perara commented Feb 2, 2026

This is awesome! It would be perfect to have this suppored upstream

@ChampionDesigns
Copy link
Copy Markdown

@jpieper we would use this feature.

sp-mzhang added a commit to sp-mzhang/moteus that referenced this pull request Mar 17, 2026
- Add fdcanusb ASCII protocol over UART (PC10/PC11, 460800 baud)
- New fw/uart_fdcanusb_micro_server.h for moteus_tool/tview over serial
- BUILD: enable MOTEUS_ENABLE_UART_PROTOCOL, add uart_fdcanusb_micro_server.h
- moteus.cc: UART server, dual transport, pool 24k when UART enabled
- moteus_controller.cc: disable debug UART when protocol on same pins
- moteus_hw.cc: family 0 UART pins PC_10/PC_11
- Python: FdcanusbDevice baudrate param, exclusive=True; --fdcanusb-baud
- .gitignore: .history/

Made-with: Cursor
@jpieper
Copy link
Copy Markdown
Member

jpieper commented Mar 19, 2026

So, I have a draft here: https://github.com/mjbots/moteus/tree/serial_command

It requires both firmware and client side changes in order to use checksums. Is anyone watching this PR willing to test it? If so, do you need help with firmware binaries?

@ChampionDesigns
Copy link
Copy Markdown

Hi @jpieper, I'll test it this weekend.

@ChampionDesigns
Copy link
Copy Markdown

@jpieper, I'm not sure where is best to talk you about your serial_command code. I have migrated to it now and its working ok for me. I enabled CRC in my scripts to test that as well and so far its fine. I cannot really give much feedback as I rely on AI most of the time to do the coding so I not a good tester. Let me know if you have any questions and I'll try to answer them

@perara
Copy link
Copy Markdown
Author

perara commented Mar 24, 2026

In my case, we will need to use PC11 and PC10 for the UART. The ones being DEBUG_TX/DEBUG_RX in schematics for the R4.11.

Is this something that could be a compile flag?

EDIT: Newbringer@390b343#diff-16813c55826128cf3a224a3168e1ca02c4edc359a59cb4c06ecde51315621dce

would something like this be acceptable?

@jpieper
Copy link
Copy Markdown
Member

jpieper commented Mar 24, 2026

What about something like this?

diff --git a/fw/moteus_controller.cc b/fw/moteus_controller.cc
index f54fe970..bd0bee11 100644
--- a/fw/moteus_controller.cc
+++ b/fw/moteus_controller.cc
@@ -424,8 +424,17 @@ aux::AuxHardwareConfig GetAux2HardwareConfig() {
           //          ADC#  CHN    I2C      SPI      USART    TIMER
           { 0, PB_8,   -1,   0,    I2C1,    nullptr, USART3,  nullptr },
           { 1, PB_9,   -1,   0,    I2C1,    nullptr, USART3,  nullptr },
+          // Select which two stm32 pins are used for the
+          // non-connectorized aux2 pins for moteus-r4.  By default,
+          // the DBG1/DBG2, but if MOTEUS_R4_AUX2_RT is
+          // defined, then they will be the R and T pads.
+#ifndef MOTEUS_R4_AUX2_RT
           { 2, PC_14,  -1,   0,    nullptr, nullptr, nullptr, nullptr },
           { 3, PC_15,  -1,   0,    nullptr, nullptr, nullptr, nullptr },
+#else
+          { 2, PC_10,  -1,   0,    nullptr, nullptr, USART3, nullptr },
+          { 3, PC_11,  -1,   0,    nullptr, nullptr, USART3, nullptr },
+#endif
           { -1, NC, },
               }},
           aux_options,

@jpieper
Copy link
Copy Markdown
Member

jpieper commented Mar 24, 2026

Oh, you edited your comment with a proposed diff that seems to basically accomplish a similar thing to mine. I think the only practical difference is the compile time default baud rate, which sure, but can you really not change the baud rate of your client? ;)

@jpieper
Copy link
Copy Markdown
Member

jpieper commented Mar 24, 2026

@perara like this?

9a294a1

@perara
Copy link
Copy Markdown
Author

perara commented Mar 24, 2026

Ah yes, the baud is not critical. The only reason I would keep it configurable is to support dev on windows through UART-TO-USB bridges like CP2102 which dont like bauds this high. But this is just minor :)

Will test @9a294a1

@jpieper
Copy link
Copy Markdown
Member

jpieper commented Mar 24, 2026

Let's move discussion to this new PR with the code in question: #108

@jpieper jpieper closed this Mar 24, 2026
@jpieper
Copy link
Copy Markdown
Member

jpieper commented Mar 25, 2026

@perara If you are willing, can you comment in #108 if that PR works for you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants