Combining LEGO PowerFunctions and LEGO Powered UP

My son got the LEGO Boost set for his birthday and is really loving it. In the past we used an ESP8266 microcontroller to hack the LEGO train remote controls (LEGO PowerFunctions) using MQTT to communicate with the ESP8266 which was build into the train which in turn used an IR led to control the train speed.

Now with LEGO Boost we got our first experience with the newer LEGO Powered Up and our search for ways to hack this began…

Legoino

We found a very interesting Arduino library which makes it possible to use the ESP32 buildin BLE to control LEGO Powered Up and thus the LEGO Boost movehub.

https://github.com/corneliusmunz/legoino

I have tested this library and it works like a charm:

By the way, thanks JKBrickworks for the instructions for the Candy Catapult!

Power Functions

Our first goal was to try to read out the LEGO Power Functions IR remote control and use that to drive the LEGO Boost movehub.
As said, we have experience with emulating the IR remote but never attempted to receive its signals. Fortunately I fount this little gem:

Arduino-LPF: Lego Power Functions IR receiver with LCD

This also proved to be fairly simple:

Combining Arduino-LPF and Legoino

Now nothing stands in the way of combining both and use the “old” LEGO Power Functions remote controls in conjunction with the “new” LEGO Powered Up hubs:

//Lego Power Functions receiver: https://github.com/thordreier/Arduino-LPF
#include "Arduino-LPF-receiver.h"
#include "Arduino-LPF-driver.h"

const byte IRreceiverPin = 2; // datapin of the IR receiver (TSOP38238)
byte       address     = 0;   // is always 0 in normal Power Functions
byte       channel     = 0;   // between 0 and 3 (for channel 1-4)
LPFDriver driver( address, channel );

// Lego Boost library: https://github.com/corneliusmunz/legoino
#include "BoostHub.h"

// create a hub instance
BoostHub myBoostHub;

// declare the ports
BoostHub::Port _portA = BoostHub::Port::A;
BoostHub::Port _portB = BoostHub::Port::B;
BoostHub::Port _portC = BoostHub::Port::C;
BoostHub::Port _portD = BoostHub::Port::D;

// Variables to hold the PF values
int8_t iRED;
int8_t iBLUE;
byte bRED_BRAKE;
byte bBLUE_BRAKE;

// Interrupt service routine called whenever IR signal is received and decoded
void control_motor( int8_t speed0, byte brake0, int8_t speed1, byte brake1 ) {
   iRED = speed0;
   iBLUE = speed1;
   bRED_BRAKE = brake0;
   bBLUE_BRAKE = brake1;

   Serial.print("RED = ");Serial.print(iRED);Serial.print(" RED brake = ");Serial.print(bRED_BRAKE);
   Serial.print(" | BLUE = ");Serial.print(iBLUE);Serial.print(" BLUE brake = ");Serial.println(bBLUE_BRAKE);
}

void setup() {
  Serial.begin(115200);
  Serial.println("Lego Power Functions 2 Powered Up");
  
  // Initialize the Lego Power Functions
  pinMode(IRreceiverPin, INPUT);
  lpf_receiver_set_pin(IRreceiverPin);
  attachInterrupt(digitalPinToInterrupt(IRreceiverPin), lpf_receiver_interrupt, CHANGE);
  driver.set_driverfunction( control_motor );

  // initalize the BoostHub instance
  myBoostHub.init(); 
}

void loop() {
  // Receive the Lego Power Functions IR messages 
  while( lpf_msg msg = lpf_receiver_get_next_msg() ) {
    driver.parse_msg(msg);
    //Serial.println( msg, BIN );
  }
  
  // connect flow. Search for BLE services and try to connect if the uuid of the hub is found
  if (myBoostHub.isConnecting()) {
    myBoostHub.connectHub();
    if (myBoostHub.isConnected()) {
      Serial.println("Connected to HUB");
    } else {
      Serial.println("Failed to connect to HUB");
    }
  }

  if (myBoostHub.isConnected()) {
    char hubName[] = "myBoostHub";
    myBoostHub.setHubName(hubName);

    if (bRED_BRAKE){
      myBoostHub.setLedColor(RED);
      myBoostHub.stopMotor(_portA);
    }
    else {
      if (iRED != 0){
        myBoostHub.setLedRGBColor(255, 50, 30);
      }
      myBoostHub.setMotorSpeed(_portA, map(iRED,-7,7,-100,100));
    }

    if (bBLUE_BRAKE){
      myBoostHub.setLedColor(BLUE);
      myBoostHub.stopMotor(_portB);
    }
    else {
      if (iBLUE != 0){
        myBoostHub.setLedRGBColor(255, 50, 30);
      }
      myBoostHub.setMotorSpeed(_portB, map(iBLUE,-7,7,-100,100));
    }
  }
}