Short-distance, low-pin-count buses: I2C, SPI, and UART
UART (Universal Asynchronous Receiver/Transmitter) is the simplest of the three: a single pair of wires (TX and RX) carries data one bit at a time between exactly two devices, with both sides agreeing in advance on a baud rate rather than sharing a clock signal. It's commonly used for MCU-to-SBC communication, an MCU streaming encoder counts or receiving velocity commands over a UART link (often through a USB-serial adapter) is a very common pattern in mobile robots. Its main limitation is that it's point-to-point: only two devices, no built-in way to address multiple peripherals on the same wires.
I2C (Inter-Integrated Circuit) and SPI (Serial Peripheral Interface) both solve the 'many devices, few wires' problem but trade off differently. I2C uses just two wires (a shared clock line and a shared data line) and addresses each device with a unique ID, so you can chain a dozen sensors, an IMU, a barometer, a couple of ADCs, off the same two pins, at the cost of relatively low speed (typically under a few Mbps) and some complexity around bus arbitration if two devices try to talk at once. SPI uses four wires (clock, two data lines, and a separate chip-select line per device) and is significantly faster and simpler in timing, but needs an extra pin for every device on the bus, which doesn't scale as gracefully as I2C when you have many peripherals. In practice, robots often use I2C for lower-bandwidth sensors like IMUs and environmental sensors, and SPI for anything needing higher throughput, like an SD card logger or a fast ADC.
