[Doc] Collect "hardware hacker" documentation on Lego I/O and peripherals
I've been trying to understand:
- how many "generations" of Lego electronic peripherals exist, and which ones are compatible
- how the I/O ports on the EV3 work
- how peripheral auto-detection works
but I've been finding the relevant information scattered and somewhat unclear. I hope that this issue can be used to collect information to the detail level that would be useful for a hardware hacker.
Target markets / audiences
As part of Lego's strategy for making Lego a toy for everyone, different Lego products target different subgroups. Although there are no hard-and-fast boundaries, the nature of social networks (in the general, non-Internet, sense) results in at least the following (approximate and overlapping) clusters:
- Set builders (e.g. sets branded Lego Technic or Lego City)
- Train builders
- Robotics
- Classroom education
Hardware generations
A general overview of Lego electronics can be found here
Ancient history
Lego first introduced electronics into their sets since at least the 1960s. These used a number of systems, none of which are compatible with "modern" programmable Lego hubs. In general, these are relatively-electrically-simple DC motors. Several of these systems focused primarily on model trains.
RCX-era
The RCX was the first standalone programmable Lego hub and the first of the Mindstorms product line. It supported motors and sensors using a connector consisting of a 2x2 grid of Lego studs, with metal conductors along the sides of the studs. Although there are 4 studs in total, they are connected in pairs into two wires (in a manner that is tolerant of rotation).
This system did not originate from the RCX but has been used on prior Technic and train sets. It may also be called the "brick connector" or the "9V system" (especially by train/set builders).
These parts seem to use the "legacy" (bright solid colors) design language.
Motors are standard DC motors connected across the two conductors. On the RCX, these ports are connected directly to a motor driver IC.
Sensors can be "unpowered" or "powered". A simplified schematic of the RCX sensor port looks like this:
A slightly more detailed schematic can be found here.
An "unpowered" or "passive" sensor enables the 10k pull-up resistor but does not enable the 9V power source. The pull-up resistor allows for sensors such as a pushbutton or a passive resistive device such as a thermistor. These are connected between the "signal" and "ground" pins and form a voltage divider with the 10k pull-up resistor.
A "powered" or "active" sensor enables the 9V current-limited power source for a long period of time followed by disabling it and measuring the voltage during the remaining small period of time. This is explained in the NXT hardware developer kit:
Active sensors typically contain a large capacitor in order to remain powered during the time when the 9V supply is not present.
TODO: How does the RCX know if an active or passive sensor is connected? Do you have to manually specify?
TODO: Is the 10k pull-up enabled during the measuring time for active sensors?
Power Functions
These devices use a connector that has the size of a 2x2 Lego stud square, but the connector only has two Lego studs. The other half of the connector is replaced with an oval shape with four pins along the inside of the oval. Unlike the RCX-era connector, the shape of this connector restricts it to one possible orientation.
This connector succeeded the RCX-era connector for trains and Technic sets, but this connector was never used on a robotics platform. However, sensors using this connector existed as part of the "WeDo 1.0" system targeted for classroom education.
These parts seem to use the "NXT-era" (orange as the accent color) design language.
Two of the four pins supply battery voltage to devices. The other two pins are used for control signals. A diagram can be found on this page.
The Power Functions motors use these control pins to control the motor direction by connecting the motor across them (leaving the raw battery supply unused). The raw battery supply is used to power devices such as the infrared receiver and WeDo sensors.
TODO: Power Functions servo
TODO: WeDo sensors
An adapter, Lego part 8886, can be used to adapt between Power Functions and the RCX-era brick connector. This cable connects the two brick connector conductors to the two control pins and can only be used for motors.
NXT
These devices use a modified RJ12 with an offset tab. Cables have 6 wires.
These parts seem to use the "NXT-era" (orange as the accent color) design language.
Motor and sensor port circuitry appears to be a gradual evolution of the RCX-era ports.
Motors now contain encoders which send back digital pulses as they rotate. The following is a redrawn version of one motor port in the NXT schematics:
The motor power is supplied out from the NXT on pins 1 and 2. Pins 3 and 4 are used to power the encoders. Pins 5 and 6 receive digital pulses from the encoders. The input circuitry consists of some basic input filtering and protection followed by a Schmitt trigger.
Sensors can be either analog or digital. Most digital sensors, especially third-party ones, use I2C. The NXT color sensor uses a custom protocol. The following is a redrawn version of one sensor port in the NXT schematics:
Pin 1 is the pin normally used for passive analog sensors. It is also capable of supplying power to RCX active sensors, which can be connected using an adapter cable. Unlike the RCX, the 10k pull-up resistor cannot be disabled.
Pin 5 and 6 are normally used for digital signals. When using I2C, pin 5 is SCL and pin 6 is SDA. These pins contain basic input protection and then are connected directly to the main CPU. There are no pull-up resistors on these pins (the 82K resistor shown in the NXT schematics is NM not mounted). Compared to the motor ports, these pins have less filtering (significantly higher RC filter cutoff frequency) and do not have Schmitt trigger inputs.
The NXT HDK mentions that pin 6 is connected to an analog-capable pin on the NXT CPU, but this does not appear to ever have been enabled in the stock Lego firmware.
Port 4 is capable of RS485 communications over pins 5 and 6. This was used by at least one third-party peripheral.
All "5V" power supplies out of the brick to peripherals have a current limit which is not shown in the redrawn schematics.
The RCX<->NXT adapter cable ("x1676" or "54690") connects the RCX wires to pins 1 and 2 of the NXT port. This means that motors are connected directly (without speed feedback) and sensors are connected between the analog input pin and GND. On the NXT, this enables full compatibility.
EV3
These devices use the same modified RJ12 as the NXT.
These parts seem to use the "EV3-era" (red as the accent color) design language.
In general, the circuitry changes and increase in complexity between the NXT and the EV3 are to enable automatically detecting the type of peripheral connected to the brick. Some documentation on how this auto-detection works can be found here.
Motors are mostly interchangeable with the NXT, but EV3 motors have additional means for detecting the size of motor. EV3 motors also contain built-in Schmitt triggers (making them easier to interface with custom hardware). However, the EV3 hub still contains Schmitt triggers in order to support legacy motors.
The EV3 hub side of the motor circuitry is as follows:
Compared to the NXT, pin 5 has gained additional analog input capabilities. This is mostly used for autodetection but could theoretically be used for some form of data feedback.
Pin 6 has gained the ability to be driven to 0V or to 9V. This is supposedly used for autodetecting "new [dumb] actuators" (i.e. without encoders), but it does not appear that such devices were ever produced.
The EV3 has less input protection than the NXT on the motor encoder inputs.
Motor type detection is built around having the output impedance of the encoder signal on pin 5 be different depending on the type of motor. The "medium" motor contains an 8.2K series resistor and the "large" motor contains a 3.3K series resistor. This resistance parallels with the 100k resistors to 5V and 0V as well as the 4.7k resistor on the digital input path which can be pulled to 0V as part of the detection sequence. The resulting voltage is measured by the ADC.
Autodetection of the motor type needs to proceed in several steps because the encoder can be outputting either 5V or 0V depending on the mechanical position of the motor. The detection algorithm needs to handle both states.
Digital sensors now use UART communications, and the pinout is mostly compatible with NXT sensors. However, incompatibilities can arise due to the new use of pin 2 for autodetection.
Other than the addition of a filtering capacitor, the EV3 pin 1 circuitry is the same as the NXT. The EV3 retains the ability to supply power for legacy RCX active sensors. However, due to the changes to pin 2 to enable auto-detection (pin 2 is no longer wired directly to GND), the RCX<->NXT adapter does not work for sensors on the EV3 (although it still works for motors). It can be fixed by rewiring it to use pins 1 and 3 instead, but this would not be compatible with motors. Due to this incompatibility, the EV3 firmware never enabled support for legacy active sensors.
The EV3 pin 6 analog input's low pass filter has a lower cutoff frequency compared to the NXT.
EV3 analog sensors (i.e. the touch sensor) use pin 6 for the input, whereas NXT sensors use pin 1 for the input. The EV3 hardware is capable of reading analog values from either pin, which enables backwards-compatibility.
Pin 2 is now wired to a GPIO pin. This is typically used to detect whether the peripheral shorts pin 2 to pin 3 (indicating a legacy NXT peripheral), but it is theoretically possible to use it as an arbitrary digital signal. Pin 2 is tied to a particular voltage which is still a digital "high" but not 3.3V in order to be able to detect devices that connect pin 1 and pin 2. It is not clear if any such devices existed.
Pins 5 and 6 now contain very weak pull-up/down resistors optimized for the new UART protocol. I2C sensors designed according to the NXT HDK contain resistors which are strong enough (<= 82K) to overcome the pull-down.
When the UART protocol is used, the EV3 uses a separate buffer chip. It is not clear why this is necessary (stronger drive strength?)
Pybricks has documented the UART protocol here
Powered Up
These devices use a custom 6-pin connector. The pinout is a hybrid of the EV3's sensor and motor ports, and there is now no distinction between sensors and motors.
This system was called "Lego Power Functions 2.0" before the "Powered Up" branding was fully adopted.
This system uses a unified connector across all target markets, but not every device works with every hub and software combination when using official software. However, Pybricks aims to support every device on every hub.
In "mainstream" sets such as Technic, these parts seem to use the "EV3-era" (white and grey with red as the accent color) design language. The "robotics" product lines seem to use bright pastels, with teal accents in the "home education" Mindstorms product line and yellow accents in the "classroom education" Lego Education product lines
This system is also used for "WeDo 2.0" sensors.
The Powered Up UART protocol is an extension of the EV3 UART protocol. As part of the convergence into a single connector standard, motor encoders are now digital and speak the UART protocol rather than sending raw quadrature digital pulses.
Passive adapters between EV3 and SPIKE sensors are possible due to them both using a very-similar UART protocol. However, they may require special or custom software on the hubs to enable support. Examples of (likely) passive adapters include:
- mindsensors.com EV3<->SPIKE adapter. TODO: Is this actually a passive sensor? Does it work for motors?
- https://github.com/a10036gt/EV3-SPIKE_Sensor_Adapter-Staff . This adapter does not work with motors.
An active adapter is sold by QikEasy. This uses a microcontroller to fully adapt the protocol from EV3 to SPIKE and also contains circuitry to support motors.
One thing I'm notably confused by in the EV3 schematics is why the EV3 sensor circuitry has both a path directly connecting pins to the port (DIGIxn) as well as the 74HC125 buffers (TXINx, RXINx)
The official docs for NXT and EV3 are at the bottom of this page: https://www.lego.com/en-us/themes/mindstorms/downloads. LEGO didn't provide this type of resource much on other generations.
Philo's page also has lots of great info on all of this hardware: https://www.philohome.com/index.htm
I can do a brain dump later to share everything I know.
On this note, do we have documentation on various Lego IR protocols other than the RCX one (which seems to be well-documented)?
I noticed there have been many IR receivers over the years, but the remotes seem increasingly annoying to find. I also don't know which ones are or are not compatible with each other.
It'd be nice to have a universal IR blaster device.
Lego IR protocols
Philo's page has a copy of the Power Functions IR protocol docs from LEGO. The EV3 remote/IR Sensor is partially compatible with that. And IIRC, the BOOST Color/Distance sensor can transmit some compatible commands but not receive them.
https://philohome.com/pf/LEGO_Power_Functions_RC.pdf
IIRC, the BOOST Color/Distance sensor can transmit some compatible commands but not receive them.
We support this π
@ArcaneNibble, writing it all down could probably be whole book or two, but feel free to pick our brains on specifics as you run into them. Either here or on a video chat.
Our understanding of the bigger picture and a reasonable way to deal with LEGO sensors in code has gradually evolved and changed a couple of times over the years, but it is starting to get in a good place now. I'm happy to share the high level ideas as well as implementation specifics.
It is usually a balance of making things work....
- ... simple and effective for beginning users (e.g. useful classes available out of the box)
- ... configurable and extensive for advances users (e.g. calibrate your own colors if you want)
- ... consistent across platforms and generations (e.g. color sensors with 4 different protocols)
- ... while dealing with the quirks of each sensor (e.g. data split across different device modes, protocol bugs...)
The motor controllers are our own (which is a bit of a saga in itself β ). We generate a basic trajectory and follow it using a PID controller with a feedforward component based on a simple DC motor model with a state observer. Other than measuring model parameters and configuring control constants for the EV3/NXT motors, this code is in good shape and already enabled on NXT/EV3.
TODO: Why does ev3dev mention a difference between "EV3/Analog" sensors and "NXT/Analog" sensors?
In the end, there was only ever one EV3 analog sensor, the Touch sensor. Its value is measured on pin 6. The NXT and all third party sensors used the ADC value on pin 1. See code.
TODO: Are parts fully compatible across the product lines? (when using Pybricks / when using the official software)
With the official products, each theme or even set has its own app. Almost nothing is compatible, even if it has the same plug. Believe it or not, if the plastic has the wrong color you're out of luck on a $400 set (the Inventor Hub is the same as SPIKE Prime save for a USB device ID so you can't use it with the SPIKE app). Since the past 5 years or so, it is app-store only (no installers), so things just stop working when the app is pulled. This has already happened for a few sets (Boost Star Wars).
Pybricks' raison d'Γͺtre π
Our motto is if the cable fits, it should just work. We're pretty much there for Powered Up (except for WeDo 2.0 which can't be updated). For the NXT/EV3 generation we might get very close too. The only open question might be soft-UART support for NXT.
Does the Lego RCX <-> NXT adapter (part 54690) wire the RCX system wires to NXT pins 1 and 2? (which would mean that motors work and sensors work with the NXT but do not work with the EV3 unless pin 2 is driven low (and even then may not work well) )
Does the Lego RCX <-> NXT adapter (part 54690) wire the RCX system wires to NXT pins 1 and 2?
Yes. So motors work, there is just no speed feedback.
And yeah, with the extra series resistor on pin 2 passive sensors might not work so well and pin 2 might not be able to handle the current load of active sensors.
I've been going through the history of Lego programmable brick schematics and things seem to increasingly make sense once you've seen the progression of hardware. However, I'm still not sure why the EV3 has the SN74HC125 on its sensor ports. It really seems that such a buffer is redundant?
Is the 74HC125 active only for UART mode? Does I2C use the "raw" DIGIxn lines?
Is the 74HC125 active only for UART mode? Does I2C use the "raw"
DIGIxnlines?
I would have to look a the ev3dev source code to remind me, but for sure SDA is not using the buffer because it is bidirectional. I don't remember about SCL though.
RCX
This generation seems to also be called the "9V system"?
This is more commonly used among train enthusiasts rather than RCX, I think, but same connector, so same system.
TODO: Electrical characteristics of the inputs?
The NXT Hardware Developer SDK has some info on how these work. Passive sensors are basically just measuring resistance of the sensor and active sensors are powered for 3 ms, then read for 0.1 ms.
Power functions
Motors appear to use the two additional pins to control the direction.
And on the Power Functions servo motor, they control the position. And they serve as data lines for the WeDo sensors.
Sensors using this connector existed as part of the "WeDo 1.0" system. TODO: How do they work?
I think we mostly figured this out through reverse engineering. There is a WeDo USB hub that can connect to senses and drive small motors (no separate power, so 5V 500mA!). We wrote ev3dev drivers for it that should fill in some of how it works.
TODO: How does the adapter cable (Lego part 8886) work? How is it wired?
It just connects the two power wires and not the control wires.
NXT
Sensors can be either analog or digital using I2C.
The NXT Color sensor is a bit of a hybrid analog sensor where you can also fetch the calibration table and control which LED is turned on. It uses it's own bit-banging protocol rather than I2C.
EV3
TODO: Where do you find documentation on the UART protocol?
We made our own: https://github.com/pybricks/technical-info/blob/master/uart-protocol.md
The EV3 source code kind of documents it, but the code comments there seem to be for an earlier design revision and didn't get update to how it was actually implemented.
Powered Up
This seems to also be called "Lego Power Functions 2.0"?
This was a pre-release name before they went all-in on the Powered Up branding.
TODO: Are parts fully compatible across the product lines? (when using Pybricks / when using the official software)
Pybricks says, if it fits the plug, it works! LEGO, not so much. Official LEGO apps tend to only support the accessories that shipped with the kit that the app is targeted to and not the full ecosystem.
TODO: EV3 <-> Powered Up adapters
From a reputable vendor: https://www.mindsensors.com/home/28-spike-prime-sensor-adapter-for-ev3.html
It just connects the two power wires and not the control wires.
Do Power Functions motors just spin in one direction if the control lines are floating?
Was there never an autonomous "intelligent" hub that used these connectors? Or were there only train/model "battery boxes", remote controls, and the WeDo 1.0 hub?
Do Power Functions motors just spin in one direction if the control lines are floating?
I think the motor would just not run. Only the C1/C2 lines are connected to the motor. See the diagram at https://www.philohome.com/pf/pf.htm
The other 2 wires power the infrared receiver (and the servo motor).
Was there never an autonomous "intelligent" hub that used these connectors? Or were there only train/model "battery boxes", remote controls, and the WeDo 1.0 hub?
Correct, no 1st-party programmable brick. But there are some 3rd-party ones, like Buwizz.
Ohhhh, PF motor != PF servo
This now all makes sense electrically, thanks!
Hi! Just wanted to share two projects that might be useful:
-
π§ LUMP Device Builder Library:
A project that aims to provide a detailed and practical approach to LEGO-compatible Arduino control. based on LPF2 protocol, most of function is completed and already testing with lots of MCUs. -
π EV3-SPIKE Sensor Adapter:
A firmware/hardware solution that allows SPIKE Prime sensors to be used with EV3. (Or EV3 Sensor to SPIKE) Great for bridging legacy and modern LEGO systems.
https://www.youtube.com/watch?v=kYKOY--8tYQ
Hope you find them helpful!
**And Thanks to the Pybricks team for publishing a detailed LUMP specification. For our open-source release, we adopted the more comprehensive LUMP header file defined by Pybricks.
Could someone look over the edits I've made to the original post to see if there are any errors?
The Power Function connector I might call it a plate, but it is a bit thicker, so forget it. But an important thing about this connector is that it can be stacked to connect more than one device. Like this:
Not too important, but it was at the time.
was at the time
The RCX/brick connector system is also capable of this. Is this simply in contrast to the newer motors which cannot stack?
was at the time
The RCX/brick connector system is also capable of this. Is this simply in contrast to the newer motors which cannot stack?
yes. motors and ~~sensors~~ IR-receiver.
One difference I noticed between EV3 motors and NXT motors is that the EV3 motors also have a Schmitt trigger in the motor itself on pins 5/6. This makes using the EV3 motors with custom electronics easier, e.g. you can connect it directly to a quadrature encoder without having to add your own Schmitt trigger.
Pin 1 is the pin normally used for passive analog sensors. It is also capable of supplying power to RCX active sensors, which can be connected using an adapter cable. Unlike the RCX, the 10k pull-up resistor cannot be disabled.
Some I2C sensors, like the LEGO NXT Ultrasonic sensor, also require extra power on pin 1.
Port 4 is capable of RS485 communications over pins 5 and 6. It is not clear if this was ever used.
There is at least one 3rd-party product that made use of this: https://robotics.benedettelli.com/nxt2wifi-lego-wifi-module/
The NXT HDK mentions that pin 6 is connected to an analog-capable pin on the NXT CPU, but this does not appear to ever have been enabled in software.
Until Pybricks, that is. π
Powered Up
There are also some non-UART Powered up devices. The WeDo 2.0 Medium motor (aka Simple Medium Linear Motor - 45303) and the Powered Up Train Motor (88011) do not have speed feedback. And of course the Powered Up Light (88055) doesn't use UART.
There are a few other unused device IDs that we got names for by reverse-engineering the official LEGO firmware, but no products have a appeared that use any of these since then.
static const lego_device_type_id_t legodev_pup_type_id_lookup[3][3] = {
/* ID1 */ [DEV_ID_GROUP_GND] = {
/* ID2 */ [DEV_ID_GROUP_GND] = LEGO_DEVICE_TYPE_ID_LPF2_POWER,
/* ID2 */ [DEV_ID_GROUP_VCC] = LEGO_DEVICE_TYPE_ID_LPF2_TURN,
/* ID2 */ [DEV_ID_GROUP_PULL_DOWN] = LEGO_DEVICE_TYPE_ID_LPF2_LIGHT2,
},
/* ID1 */ [DEV_ID_GROUP_VCC] = {
/* ID2 */ [DEV_ID_GROUP_GND] = LEGO_DEVICE_TYPE_ID_LPF2_TRAIN,
/* ID2 */ [DEV_ID_GROUP_VCC] = LEGO_DEVICE_TYPE_ID_LPF2_LMOTOR,
/* ID2 */ [DEV_ID_GROUP_PULL_DOWN] = LEGO_DEVICE_TYPE_ID_LPF2_LIGHT1,
},
/* ID1 */ [DEV_ID_GROUP_PULL_DOWN] = {
/* ID2 */ [DEV_ID_GROUP_GND] = LEGO_DEVICE_TYPE_ID_LPF2_MMOTOR,
/* ID2 */ [DEV_ID_GROUP_VCC] = LEGO_DEVICE_TYPE_ID_LPF2_XMOTOR,
/* ID2 */ [DEV_ID_GROUP_PULL_DOWN] = LEGO_DEVICE_TYPE_ID_LPF2_LIGHT,
},
};
Speaking of IDs on Powered Up, there are lots of posts around the internet that imply there is an "ID resistor" as if the port detection was somehow measuring the resistance value of such a resistor. This likely comes from the assumption that the Powered Up port ID works like EV3. But this is simply not true. Powered Up ports don't have any analog inputs and the port ID algorithm uses purely digital I/O.
Some I2C sensors, like the LEGO NXT Ultrasonic sensor, also require extra power on pin 1.
How do you know if you need to turn the extra power on? Is it hardcoded according to the type of the device?
Is it hardcoded according to the type of the device?
For NXT I2C sensors, it is just hard-coded. There isn't any kind of device info we can get from the sensor other than the name and manufacturer.
There are Powered Up UART devices that have similar requirements (but not any EV3 UART devices that I recall) that also need power on pin 1 or pin 2. They have device info that is sent from the sensor that includes a bit flag to indicate this.
Is it hardcoded according to the type of the device?
For NXT I2C sensors, it is just hard-coded. There isn't any kind of device info we can get from the sensor other than the name and manufacturer.
Which other devices do we know of that use it? (Besides the NXT Ultrasonic Sensor.)
The HiTechnic NXT SuperPro Prototype Board
https://github.com/ev3dev/lego-linux-drivers/blob/1b387f3bacb4ab8f623494d29a855de6163c8dec/sensors/nxt_i2c_sensor_defs.c#L1420
That file should also be useful for seeing all of the other I2C sensors and their quirks.
And this one shows all of the addresses we need to probe for I2C devices that actually have the vendor and product ID in the expected registers.
https://github.com/ev3dev/lego-linux-drivers/blob/1b387f3bacb4ab8f623494d29a855de6163c8dec/sensors/nxt_i2c_sensor_core.c#L488
Another one seems to be https://github.com/ev3dev/ev3dev/issues/913 via @JorgePe
I forgot about that one. π
But that does remind me that for the generic I2C mode, we just always enable battery voltage on pin 1 in ev3dev so that it was there for any hobby projects that might need it or NXT sensors that you want full control of the communications. There aren't any known sensors where it would cause a problem (i.e. they don't have that pin connected at all).