In this project, we will show you how to control the LEGO® Technic Liebherr Crawler Crane (42146) with the Xbox Controller.

This gives you precise control over each of the crane’s functions without having to use a phone or tablet. You can drive it around with the left joystick and control the functions with the buttons and triggers.

This crane has two hubs, so we’ll also show you how to connect them via Bluetooth.

Driving the LEGO® Technic Liebherr Crawler Crane (42146) with the Xbox Controller.
Driving the LEGO® Technic Liebherr Crawler Crane (42146) with the Xbox Controller.

Requirements

To follow this project, you will need the following:

See this overview for all compatible models.

Understanding the code

This project has two programs, one for each hub. The hub in the base connects to the Xbox Controller and drives the vehicle. It also calculates the required speeds of the crane functions based on your input, and broadcasts these to the other hub in the crane.

The crane hub receives these messages and controls the crane functions accordingly. While the order of installation doesn’t matter, it’s practical to download and run the crane program first. Because it simply starts and stops the crane functions based on the incoming signals, you can customize all the actions in the program for the hub in the base instead.

When sending numbers, communication works best if you send small numbers. So we just send the percentage values from the joysticks, and multiply them by a factor in the crane program to get the desired speed.

The program for the hub in the crane receives three values and sets the crane motor speed functions accordingly.
The program for the hub in the crane receives three values and sets the crane motor speed functions accordingly.
The program for the hub in the base receives the Xbox Controller input, drives and turns the base, and broadcasts the required speeds for the crane functions to the other hub.
The program for the hub in the base receives the Xbox Controller input, drives and turns the base, and broadcasts the required speeds for the crane functions to the other hub.

Running the Pybricks program

This project uses Pybricks on your LEGO hub. Pybricks makes your creations come alive and helps you unlock the full potential of your LEGO Technic, City, MINDSTORMS, BOOST, or Spike sets.

If you haven’t already, install Pybricks on your hub as shown below, or check out our getting started guide for more details. You can go back to the LEGO firmware and apps at any time.

Install the Pybricks firmware.
settings
install

Now import the program you downloaded earlier, as shown below. Click to connect your hub and ▶ to start!

Import a Pybricks Code project.
files
import
open
connect
run

You can run imported block programs even if you’re not signed up. This is a great way to try out Pybricks and see how it works.

In this project, you have two hubs. Installation works the same for both. During installation, you can give each hub a unique name such as Base or Crane, which makes it easier to tell them apart when you connect later.

Pairing with the Xbox Controller

The very first time, you’ll need to pair the hub with your controller:

  1. Turn the controller on.
  2. Press and hold the pairing button on the back.
  3. Release after a few seconds. The controller light will start flashing more rapidly. This is pairing mode.
  4. Then start your program. Either using the Pybricks app, or using the green button on the hub if you’ve already loaded the program earlier.

The hub will start looking for your controller when the program starts. When the connection is successful, the controller light will stop flashing and stay on for as long as the program is running.

You can see this in the video below.

Connecting without pairing

The next time you use it, pairing is not required. Just turn the controller on. The hub will connect to it automatically when your program runs.

The Xbox controller remembers only one device. If you use the controller with another LEGO hub or your Xbox console, and then with this hub again, you’ll need to pair them again as above.

Updating the Xbox Controller

If you often use the Xbox Controller with your console, it is probably already up to date. If you have not used it for a while or if you bought one recently, you may need to update it.

To update the controller without a console, you can use the Xbox Accessories app on a Windows computer. Connect the controller via USB to the computer and follow the instructions in the app to click on “Update now”. If it is already at firmware version 5.17 or later, you don’t need to do anything.

Technic Hub limitations

Once you start your program, the Technic Hub will disconnect from your computer to free up the connection for the Xbox Controller. This means you can’t use the Pybricks app to stop the program or change the code while the Xbox Controller is connected.

To change your program, stop the program by pressing the green button on the hub. Then you can connect to the hub with the Pybricks app again, and change your program as needed.

The crane in action

When you’re ready, you can operate the crane as shown below!

Communication between the two hubs works best if you disconnect them from your computer.

Running it as a Python program

You can also run this project as a Python (MicroPython) program. The following code was generated from the block program above. To run it, create a new empty Python program in Pybricks and copy the code into it.

# pybricks blocks file:{"blocks":{"languageVersion":0,"blocks":[{"type":"blockGlobalSetup","id":"bjK,wS1MYO7aiYkFSwd{","x":172,"y":280,"deletable":false,"next":{"block":{"type":"variables_set_technic_hub","id":"gp(=11-+rR7XV,H(Kz3)","extraState":{"optionLevel":3},"fields":{"VAR":{"id":"i#u8,ZT,l2iPEM`;lnA@"},"FIELDBROADCAST":0,"FIELDOBSERVE0":5},"inputs":{"AXIS_TOP":{"shadow":{"type":"blockParametersAxis","id":"X#%3uk$HRKke7-$x61?_","fields":{"VALUE":"z"}}},"AXIS_FRONT":{"shadow":{"type":"blockParametersAxis","id":"t6svMY`f{#wcs{O_V(3m","fields":{"VALUE":"x"}}}},"next":{"block":{"type":"variables_set_motor","id":"g=O6sK{#.90KNfvnR{3l","fields":{"VAR":{"id":"._x2WX|z0x*L@Q%1?Oey"}},"inputs":{"PORT":{"shadow":{"type":"blockParametersPort","id":"D*][0)m_^se#;]?i?nE~","fields":{"NAME":"A"}}},"POSITIVE_DIRECTION":{"shadow":{"type":"blockParametersDirection","id":"ts6pK}D}12wK?-A7rdcH","fields":{"SELECTION":"Direction.CLOCKWISE"}}}},"next":{"block":{"type":"variables_set_motor","id":"$=xhOYJ^ftcYuvA1[:R8","fields":{"VAR":{"id":"$n#Nfds#E0z.%x{D?N?j"}},"inputs":{"PORT":{"shadow":{"type":"blockParametersPort","id":"p!6p@JZi%jsz4X-{UbX)","fields":{"NAME":"D"}}},"POSITIVE_DIRECTION":{"shadow":{"type":"blockParametersDirection","id":"R$^/X.)X.[ug3MtZ.A3H","fields":{"SELECTION":"Direction.CLOCKWISE"}}}},"next":{"block":{"type":"variables_set_motor","id":"$gK`*.B=^D#Sb*GM}@o0","fields":{"VAR":{"id":"OBSfiq9+`s6)T412+4--"}},"inputs":{"PORT":{"shadow":{"type":"blockParametersPort","id":"1=vO3e10f`.G2/~mNPRF","fields":{"NAME":"B"}}},"POSITIVE_DIRECTION":{"shadow":{"type":"blockParametersDirection","id":"Gzy?NnDeNd6;2}DJNrD(","fields":{"SELECTION":"Direction.CLOCKWISE"}}}},"next":{"block":{"type":"variables_setup_any","id":"PVya@6UaVs-6?tW}Lh^U","fields":{"VAR":{"id":"n_]YQ6iELb+nyPy]]+U:"}},"inputs":{"VALUE0":{"shadow":{"type":"blockMathNumber","id":"7NHOATM7n7ev6M:J{Rw+","fields":{"NUM":0}}}},"next":{"block":{"type":"variables_setup_any","id":"s9?/Lvn.hcI#=5+cLhwQ","fields":{"VAR":{"id":"8w7g{`ViwcpAD;3E!~u+"}},"inputs":{"VALUE0":{"shadow":{"type":"blockMathNumber","id":")+N/:!F`HJiBss){b=(C","fields":{"NUM":0}}}},"next":{"block":{"type":"variables_setup_any","id":"??7xH4OIC/qGE.Bmz0|,","fields":{"VAR":{"id":"vnW2nU]#v`UU)%BHG(/]"}},"inputs":{"VALUE0":{"shadow":{"type":"blockMathNumber","id":"=c?^@d/}|C$4RaHD?6+G","fields":{"NUM":0}}}}}}}}}}}}}}}}}}},{"type":"blockGlobalStart","id":"3tJe|AWl0baN(wH9a$@.","x":170,"y":754,"deletable":false,"next":{"block":{"type":"blockFlowWhile","id":"wco]@xabtlt#dtq|TrZ{","fields":{"MODE":"WHILE"},"inputs":{"BOOL":{"shadow":{"type":"blockLogicTrue","id":"@6BOn#UM|kptQ,+-Gjh#"}},"DO":{"block":{"type":"blockComment","id":"O4fq1kN78eO?UP2y1Qk_","fields":{"FIELDNAME":"Get and unpack data sent from the hub in the base.\nThis unpack block sets the variables to 0 if there is no data."},"next":{"block":{"type":"blockListUnpack","id":"307ic~W}VYEwDztNSIKY","extraState":{"optionLevel":2},"inputs":{"LIST":{"shadow":{"type":"blockListEmpty","id":"l=^}qe#UvB)UHNWUQM^/"},"block":{"type":"blockBleObserve","id":"S:,m#cHuM8(,SLiF#7[g","fields":{"CHANNEL":"5"},"inputs":{"VAR":{"shadow":{"type":"variables_get_ble_hub","id":"e`WUjEf7Ntfvks4`{c|@","fields":{"VAR":{"id":"i#u8,ZT,l2iPEM`;lnA@","name":"hub","type":"TechnicHub"}}}}}}},"VAR":{"shadow":{"type":"variables_get_any","id":"iX^`ei`?E3|I5h,Pi|;;","fields":{"VAR":{"id":"n_]YQ6iELb+nyPy]]+U:","name":"boom speed","type":"Any"}}}},"VAR0":{"shadow":{"type":"variables_get_any","id":"]|:8*jtILbfu/%Ow-Qkm","fields":{"VAR":{"id":"8w7g{`ViwcpAD;3E!~u+","name":"jib speed","type":"Any"}}}},"VAR1":{"shadow":{"type":"variables_get_any","id":"gH]G_T6ye%Ca%_LddL%H","fields":{"VAR":{"id":"vnW2nU]#v`UU)%BHG(/]","name":"hoist speed","type":"Any"}}}}},"next":{"block":{"type":"blockComment","id":"ke=P%VXY*)tfJyXzr=2F","fields":{"FIELDNAME":"Operate the boom."},"next":{"block":{"type":"blockIfElse","id":"k3VV;c{)p%qhuCO!Q1O4","extraState":{"optionLevel":1},"inputs":{"IF0":{"shadow":{"type":"blockLogicTrue","id":"hagrZ8|VDiqh3X`507iV"},"block":{"type":"blockVariableGetValue","id":"q%_{gMR,;ej9hmuxc(Z:","inputs":{"VAR":{"shadow":{"type":"variables_get_any","id":"gs2rr9JyYDGSHWG`E{wW","fields":{"VAR":{"id":"n_]YQ6iELb+nyPy]]+U:","name":"boom speed","type":"Any"}}}}}}},"DO0":{"block":{"type":"blockMotorRun","id":"Zy8F:`j(*Pd2}~uu`9~M","extraState":{"optionLevel":0},"fields":{"METHOD":"MOTOR_RUN_FOREVER"},"inputs":{"VAR":{"shadow":{"type":"variables_get_motor_device","id":"=!DWATjX]I#!S+an,JFP","fields":{"VAR":{"id":"._x2WX|z0x*L@Q%1?Oey","name":"boom","type":"Motor"}}}},"VALUE0":{"shadow":{"type":"unit_angularVelocity","id":"A9mVB:Fww7!Po3Z?V|Wr","fields":{"VALUE0":500}},"block":{"type":"blockMathArithmetic","id":"`]00b5gDm2bI%y!74QS+","fields":{"OP":"MULTIPLY"},"inputs":{"A":{"shadow":{"type":"blockMathNumber","id":"$6y(Ap=O/~ruy4zVBHRO","fields":{"NUM":1}},"block":{"type":"blockVariableGetValue","id":"/~z(jh8m;vO[libomQr,","inputs":{"VAR":{"shadow":{"type":"variables_get_any","id":"nsyBW]VMNn!r$Zd3+p+5","fields":{"VAR":{"id":"n_]YQ6iELb+nyPy]]+U:","name":"boom speed","type":"Any"}}}}}}},"B":{"shadow":{"type":"blockMathNumber","id":"RcIkNCI5LNMueiJR;q?=","fields":{"NUM":8}}}}}}}}},"ELSE":{"block":{"type":"blockMotorStop","id":"5Bm|]rd;,XX_!VpTYN(p","inputs":{"VAR":{"shadow":{"type":"variables_get_simple_motor_device","id":"rDO@-h#7bI6Thk_nG|7p","fields":{"VAR":{"id":"._x2WX|z0x*L@Q%1?Oey","name":"boom","type":"Motor"}}}},"VALUE0":{"shadow":{"type":"parameters_stop_3","id":"rOqV:1Akqn5K(I?6bgJs","fields":{"VALUE":"Stop.COAST"}}}}}}},"next":{"block":{"type":"blockComment","id":"97}pMbpzKVu#}YSAQ8,/","fields":{"FIELDNAME":"Operate the jib."},"next":{"block":{"type":"blockIfElse","id":")XQv_j~Mg[D/wmh]@aMG","extraState":{"optionLevel":1},"inputs":{"IF0":{"shadow":{"type":"blockLogicTrue","id":"hagrZ8|VDiqh3X`507iV"},"block":{"type":"blockVariableGetValue","id":"O*$XNpCfyY[7MRx.OKm-","inputs":{"VAR":{"shadow":{"type":"variables_get_any","id":"j*@6GMrk]!4_-C^~fY?H","fields":{"VAR":{"id":"8w7g{`ViwcpAD;3E!~u+","name":"jib speed","type":"Any"}}}}}}},"DO0":{"block":{"type":"blockMotorRun","id":"6n*#Q#][nhabD_[%ejh]","extraState":{"optionLevel":0},"fields":{"METHOD":"MOTOR_RUN_FOREVER"},"inputs":{"VAR":{"shadow":{"type":"variables_get_motor_device","id":"Eku[JwP/Mp?d)ah76,%.","fields":{"VAR":{"id":"$n#Nfds#E0z.%x{D?N?j","name":"jib","type":"Motor"}}}},"VALUE0":{"shadow":{"type":"unit_angularVelocity","id":"A9mVB:Fww7!Po3Z?V|Wr","fields":{"VALUE0":500}},"block":{"type":"blockMathArithmetic","id":"lP%#WB]{@i@MX/-fNm~$","fields":{"OP":"MULTIPLY"},"inputs":{"A":{"shadow":{"type":"blockMathNumber","id":"$6y(Ap=O/~ruy4zVBHRO","fields":{"NUM":1}},"block":{"type":"blockVariableGetValue","id":"04/)TN=be[dni~Blbg[c","inputs":{"VAR":{"shadow":{"type":"variables_get_any","id":":-kfMi@L$A@||aP%M(e+","fields":{"VAR":{"id":"8w7g{`ViwcpAD;3E!~u+","name":"jib speed","type":"Any"}}}}}}},"B":{"shadow":{"type":"blockMathNumber","id":"[XmOiM-yl{;$!WQW@2$~","fields":{"NUM":8}}}}}}}}},"ELSE":{"block":{"type":"blockMotorStop","id":"it9|R:W.Q:XqKf,Hi_D~","inputs":{"VAR":{"shadow":{"type":"variables_get_simple_motor_device","id":"N=syNkY8CFRprRsNthx%","fields":{"VAR":{"id":"$n#Nfds#E0z.%x{D?N?j","name":"jib","type":"Motor"}}}},"VALUE0":{"shadow":{"type":"parameters_stop_3","id":"XtlFkb1[`P+umBV]f,Pt","fields":{"VALUE":"Stop.COAST"}}}}}}},"next":{"block":{"type":"blockComment","id":"ya5l*WsWRqu%38rw{_;1","fields":{"FIELDNAME":"Operate the hoist."},"next":{"block":{"type":"blockIfElse","id":"/*0VU,R@0pej=L)SC02$","extraState":{"optionLevel":1},"inputs":{"IF0":{"shadow":{"type":"blockLogicTrue","id":"hagrZ8|VDiqh3X`507iV"},"block":{"type":"blockVariableGetValue","id":"B3bKc+TB_%$2p,W5X?PN","inputs":{"VAR":{"shadow":{"type":"variables_get_any","id":"HUfG,R?#|mvmFPvXlRaJ","fields":{"VAR":{"id":"vnW2nU]#v`UU)%BHG(/]","name":"hoist speed","type":"Any"}}}}}}},"DO0":{"block":{"type":"blockMotorRun","id":"v/pWVg_-^)D}s6gryM@e","extraState":{"optionLevel":0},"fields":{"METHOD":"MOTOR_RUN_FOREVER"},"inputs":{"VAR":{"shadow":{"type":"variables_get_motor_device","id":"r$KgiMUNAtY8uImGVg)S","fields":{"VAR":{"id":"OBSfiq9+`s6)T412+4--","name":"hoist","type":"Motor"}}}},"VALUE0":{"shadow":{"type":"unit_angularVelocity","id":"A9mVB:Fww7!Po3Z?V|Wr","fields":{"VALUE0":500}},"block":{"type":"blockMathArithmetic","id":"7gHoS^fq%XW,`K{e11B2","fields":{"OP":"MULTIPLY"},"inputs":{"A":{"shadow":{"type":"blockMathNumber","id":"$6y(Ap=O/~ruy4zVBHRO","fields":{"NUM":1}},"block":{"type":"blockVariableGetValue","id":"c@qG.4vl@~YKBXKs[ntC","inputs":{"VAR":{"shadow":{"type":"variables_get_any","id":")BZ--/CfD288C,Zezkvj","fields":{"VAR":{"id":"vnW2nU]#v`UU)%BHG(/]","name":"hoist speed","type":"Any"}}}}}}},"B":{"shadow":{"type":"blockMathNumber","id":",hL3:$o}kjm]$*E5hT%6","fields":{"NUM":10}}}}}}}}},"ELSE":{"block":{"type":"blockMotorStop","id":"PL^oIahHYL_w(bW!Y,fN","inputs":{"VAR":{"shadow":{"type":"variables_get_simple_motor_device","id":"z~W`Gtl`w?/Ksecv;.`[","fields":{"VAR":{"id":"OBSfiq9+`s6)T412+4--","name":"hoist","type":"Motor"}}}},"VALUE0":{"shadow":{"type":"parameters_stop_3","id":"0o/opA(V!wbx`LrP0^Ag","fields":{"VALUE":"Stop.COAST"}}}}}}},"next":{"block":{"type":"blockWaitTime","id":"NdR7p!{d!K*L_B$SvOmI","inputs":{"VALUE0":{"shadow":{"type":"unit_time","id":"~kQ^@__a(=9ZHRGv_^Ex","fields":{"VALUE0":50}}}}}}}}}}}}}}}}}}}}}}}}}}]},"variables":[{"name":"red","id":"*k/eSiSsxc:qB)!Kqd5{","type":"ColorDef"},{"name":"orange","id":"$k6mO5?H[1`yo$d5,y)p","type":"ColorDef"},{"name":"yellow","id":"F/tUN.IV(ZU?*hYlVmef","type":"ColorDef"},{"name":"green","id":"!3RvaC?EP]fx)4Ov`w$6","type":"ColorDef"},{"name":"cyan","id":"f=Yx7-$|||Ysonu}EU(U","type":"ColorDef"},{"name":"blue","id":"V5P*Y7wk%]%;g5x8;wq[","type":"ColorDef"},{"name":"violet","id":"i7R|%ut339[(.NE0@ase","type":"ColorDef"},{"name":"magenta","id":"vu6)(D9.Fvx}];fSP9jy","type":"ColorDef"},{"name":"white","id":"T]hTr(tgkzCBL1:Wz:F#","type":"ColorDef"},{"name":"none","id":"LPHKZ{MgM40/0}Yxtc#M","type":"ColorDef"},{"name":"hub","id":"i#u8,ZT,l2iPEM`;lnA@","type":"TechnicHub"},{"name":"boom speed","id":"n_]YQ6iELb+nyPy]]+U:","type":"Any"},{"name":"jib speed","id":"8w7g{`ViwcpAD;3E!~u+","type":"Any"},{"name":"hoist speed","id":"vnW2nU]#v`UU)%BHG(/]","type":"Any"},{"name":"boom","id":"._x2WX|z0x*L@Q%1?Oey","type":"Motor"},{"name":"jib","id":"$n#Nfds#E0z.%x{D?N?j","type":"Motor"},{"name":"hoist","id":"OBSfiq9+`s6)T412+4--","type":"Motor"}],"info":{"type":"pybricks","version":"1.2.2"}}
from pybricks.hubs import TechnicHub
from pybricks.parameters import Axis, Direction, Port, Stop
from pybricks.pupdevices import Motor
from pybricks.tools import wait

# Set up all devices.
hub = TechnicHub(top_side=Axis.Z, front_side=Axis.X, broadcast_channel=0, observe_channels=[5])
boom = Motor(Port.A, Direction.CLOCKWISE)
jib = Motor(Port.D, Direction.CLOCKWISE)
hoist = Motor(Port.B, Direction.CLOCKWISE)

# Initialize variables.
boom_speed = 0
jib_speed = 0
hoist_speed = 0


# The main program starts here.
while True:
    # Get and unpack data sent from the hub in the base.
    # This unpack block sets the variables to 0 if there is no data.
    boom_speed, jib_speed, hoist_speed = hub.ble.observe(5) or [0] * 3
    # Operate the boom.
    if boom_speed:
        boom.run(boom_speed * 8)
    else:
        boom.stop()
    # Operate the jib.
    if jib_speed:
        jib.run(jib_speed * 8)
    else:
        jib.stop()
    # Operate the hoist.
    if hoist_speed:
        hoist.run(hoist_speed * 10)
    else:
        hoist.stop()
    wait(50)

Program for the crane hub.
# pybricks blocks file:{"blocks":{"languageVersion":0,"blocks":[{"type":"blockGlobalSetup","id":"bjK,wS1MYO7aiYkFSwd{","x":0,"y":0,"deletable":false,"next":{"block":{"type":"variables_set_technic_hub","id":"eGDWK2wG:3dfN~J[f(6h","extraState":{"optionLevel":2},"fields":{"VAR":{"id":",s{9VvtO*UTz|3O7odYk"},"FIELDBROADCAST":5},"inputs":{"AXIS_TOP":{"shadow":{"type":"blockParametersAxis","id":"iw?OG,`,5`CK8K?4-uCs","fields":{"VALUE":"z"}}},"AXIS_FRONT":{"shadow":{"type":"blockParametersAxis","id":"2Ji{yq=o8k})5RaS7G|#","fields":{"VALUE":"x"}}}},"next":{"block":{"type":"variables_set_motor","id":"z(}72bH*Eg:!^9K:C3/v","fields":{"VAR":{"id":"#[Q|2vwDf?Q!wdxC#]Jw"}},"inputs":{"PORT":{"shadow":{"type":"blockParametersPort","id":"-}-s))osAmb`C`0Jac9L","fields":{"NAME":"C"}}},"POSITIVE_DIRECTION":{"shadow":{"type":"blockParametersDirection","id":"j}VSg+J/|rSdjSya*j;)","fields":{"SELECTION":"Direction.CLOCKWISE"}}}},"next":{"block":{"type":"variables_set_motor","id":"`2PDE/$vh)05pqRG4.)/","fields":{"VAR":{"id":"FN}[i60b|[RL~AY8,LIu"}},"inputs":{"PORT":{"shadow":{"type":"blockParametersPort","id":"5^-%Th:)~!i.$dcx@gXV","fields":{"NAME":"D"}}},"POSITIVE_DIRECTION":{"shadow":{"type":"blockParametersDirection","id":"eIek8ZTcJm%LOlmZmtU5","fields":{"SELECTION":"Direction.COUNTERCLOCKWISE"}}}},"next":{"block":{"type":"variables_set_motor","id":"|+O]pa7HG?Y/D^.3TuG/","fields":{"VAR":{"id":"j6O*TQ9p!!~wOS2+ejmx"}},"inputs":{"PORT":{"shadow":{"type":"blockParametersPort","id":"F]:~d~0,yk?JB98X7kH~","fields":{"NAME":"B"}}},"POSITIVE_DIRECTION":{"shadow":{"type":"blockParametersDirection","id":"vk4W^$6[uOvJYuj?N%CY","fields":{"SELECTION":"Direction.COUNTERCLOCKWISE"}}}},"next":{"block":{"type":"variables_set_drive_base","id":"!pt_A}}{~Y0yMF}jrEEn","fields":{"VAR":{"id":"JL+H+s8l}amP8s=pHvRu"}},"inputs":{"VAR":{"shadow":{"type":"variables_get_motor_device","id":"b4^t5/aq`*yy$+#l6.,k","fields":{"VAR":{"id":"#[Q|2vwDf?Q!wdxC#]Jw","name":"left","type":"Motor"}}}},"VAR2":{"shadow":{"type":"variables_get_motor_device","id":"p|ebPnRZLiwFNX+.ZCp~","fields":{"VAR":{"id":"FN}[i60b|[RL~AY8,LIu","name":"right","type":"Motor"}}}},"VALUE0":{"shadow":{"type":"unit_distance","id":"NLTRi9=UV_yqL~s#7]4}","fields":{"VALUE0":48}}},"VALUE1":{"shadow":{"type":"unit_distance","id":"cf~{dU!jV5I=|nF7h:Gr","fields":{"VALUE0":208}}}},"next":{"block":{"type":"variables_setup_any","id":"s9?/Lvn.hcI#=5+cLhwQ","fields":{"VAR":{"id":"2$8QA`jF?z^}g)5K3}Eg"}},"inputs":{"VALUE0":{"shadow":{"type":"blockMathNumber","id":")+N/:!F`HJiBss){b=(C","fields":{"NUM":0}}}},"next":{"block":{"type":"variables_setup_any","id":"PVya@6UaVs-6?tW}Lh^U","fields":{"VAR":{"id":"-M{(3[=2KvNq:!0qkKcR"}},"inputs":{"VALUE0":{"shadow":{"type":"blockMathNumber","id":"7NHOATM7n7ev6M:J{Rw+","fields":{"NUM":0}}}},"next":{"block":{"type":"variables_setup_any","id":"??7xH4OIC/qGE.Bmz0|,","fields":{"VAR":{"id":"2#HSYq/*kK?5brey!U9G"}},"inputs":{"VALUE0":{"shadow":{"type":"blockMathNumber","id":"=c?^@d/}|C$4RaHD?6+G","fields":{"NUM":0}}}},"next":{"block":{"type":"variables_set_xbox_controller","id":"B]xH=?-=[Tc}=#v6kgg@","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14"}}}}}}}}}}}}}}}}}}}}},{"type":"blockGlobalStart","id":"3tJe|AWl0baN(wH9a$@.","x":0,"y":518,"deletable":false,"next":{"block":{"type":"blockFlowWhile","id":":9BYRSWnd^Ss5@-tjvkY","fields":{"MODE":"WHILE"},"inputs":{"BOOL":{"shadow":{"type":"blockLogicTrue","id":"IyQebs@}T5mj]!Xd^fvo"}},"DO":{"block":{"type":"blockComment","id":"SH7Z31KK$Gc@?b|l^|V%","fields":{"FIELDNAME":"If Y or X have a nonzero value:\n- Then use Y for speed  and X for steering.\n- Otherwise stop."},"next":{"block":{"type":"blockIfElse","id":"f~hf;^xoE52=JS+s`YMv","extraState":{"optionLevel":1},"inputs":{"IF0":{"shadow":{"type":"blockLogicTrue","id":"R67bmjWs8Oq^{vu6%#4U"},"block":{"type":"blockLogicOperation","id":"yjL_;:tex$j@7phUY0H?","fields":{"OP":"OR"},"inputs":{"A":{"shadow":{"type":"blockLogicTrue","id":"NUvbZY/nXPq/WpQeCkSs"},"block":{"type":"blockJoystickValue","id":"!jS*FWR:P1FrD[r`bb$]","fields":{"JOYSTICK":"XBOX_LJ_Y"},"inputs":{"VAR":{"shadow":{"type":"variables_get_gamepad","id":"X~6qsPtMPS[*cIDD]*w(","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}}}}},"B":{"shadow":{"type":"blockLogicTrue","id":"Kwl[`JW_`F)p|4wQ,JiM"},"block":{"type":"blockJoystickValue","id":";n!#h,FMrJ0.BUPhA5nS","fields":{"JOYSTICK":"XBOX_LJ_X"},"inputs":{"VAR":{"shadow":{"type":"variables_get_gamepad","id":"I[5aYychdSI~gE9Hce2C","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}}}}}}}},"DO0":{"block":{"type":"blockDriveBaseDrive","id":"(8Pdv;=~e@%R6]K:ZGvO","extraState":{"optionLevel":1},"fields":{"METHOD":"DRIVEBASE_DRIVE_FOREVER"},"inputs":{"VAR":{"shadow":{"type":"variables_get_drive_base_device","id":"iHctDUbx{7lZcEIs^1/@","fields":{"VAR":{"id":"JL+H+s8l}amP8s=pHvRu","name":"drive base","type":"DriveBase"}}}},"ARG0":{"shadow":{"type":"unit_speed","id":"y)}H]cqaKEuPjI?1E/2-","fields":{"VALUE0":100}},"block":{"type":"blockMathArithmetic","id":"2b)*V4uSgtBU9MU45J4m","fields":{"OP":"MULTIPLY"},"inputs":{"A":{"shadow":{"type":"blockMathNumber","id":"8Qv~dYRDujHy4bX2_g)#","fields":{"NUM":1}},"block":{"type":"blockJoystickValue","id":"K_;ZSnr=nrm}KyrY*BiL","fields":{"JOYSTICK":"XBOX_LJ_Y"},"inputs":{"VAR":{"shadow":{"type":"variables_get_gamepad","id":"3PrdO9_W$u=l7NVk!j:Y","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}}}}},"B":{"shadow":{"type":"blockMathNumber","id":"9@g{n-902gM~:,1h9aTP","fields":{"NUM":2}}}}}},"ARG1":{"shadow":{"type":"unit_angularVelocity","id":"K]YXRY|_K5|8Zd2e|MHl","fields":{"VALUE0":0}},"block":{"type":"blockMathArithmetic","id":"keLgMpB%fGF5Q@.o2dt]","fields":{"OP":"MULTIPLY"},"inputs":{"A":{"shadow":{"type":"blockMathNumber","id":"^_4FmN|jfdRRB9pj3s_3","fields":{"NUM":1}},"block":{"type":"blockJoystickValue","id":"Jj^_UAgR*AY`Q0~d~=LV","fields":{"JOYSTICK":"XBOX_LJ_X"},"inputs":{"VAR":{"shadow":{"type":"variables_get_gamepad","id":"F]9%c{v[ivNK7--Q^r#L","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}}}}},"B":{"shadow":{"type":"blockMathNumber","id":"MfY3)K8yXlb_~{P{gI;)","fields":{"NUM":2}}}}}}}}},"ELSE":{"block":{"type":"blockDriveBaseStop","id":"O+0g.-$*:(5MkPIW-cM!","inputs":{"VAR":{"shadow":{"type":"variables_get_drive_base_device","id":"i.B/;,Et@d3,jQW9pnBF","fields":{"VAR":{"id":"JL+H+s8l}amP8s=pHvRu","name":"drive base","type":"DriveBase"}}}},"VALUE0":{"shadow":{"type":"parameters_stop_3","id":"LmwcSSEco#VF]E-YHqht","fields":{"VALUE":"Stop.COAST"}}}}}}},"next":{"block":{"type":"blockComment","id":"}x)Qs%TXtN|hg|_Sjeuc","fields":{"FIELDNAME":"We use the left minus the right trigger to control the turn table.\nThis lets you rotate it by pressing one or the other.\nIf that speed is zero, then coast the motor."},"next":{"block":{"type":"blockIfElse","id":"mX?=7?JFZ|6xD|9n^;ZP","extraState":{"optionLevel":1},"inputs":{"IF0":{"shadow":{"type":"blockLogicTrue","id":"R67bmjWs8Oq^{vu6%#4U"},"block":{"type":"blockMathArithmetic","id":"+([_.]BPZQBXh1Z-ZZUc","fields":{"OP":"MINUS"},"inputs":{"A":{"shadow":{"type":"blockMathNumber","id":"qW+1HC(ZriM=PLlqUS-,","fields":{"NUM":1}},"block":{"type":"blockJoystickValue","id":"tl(+_$h6nZKCMNS;zX-1","fields":{"JOYSTICK":"XBOX_LT"},"inputs":{"VAR":{"shadow":{"type":"variables_get_gamepad","id":"x[#e*F~r=DPgoP(RtWlM","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}}}}},"B":{"shadow":{"type":"blockMathNumber","id":"V6]_8qK2pNACUOO#]iQi","fields":{"NUM":1}},"block":{"type":"blockJoystickValue","id":"TS;:#nPzfpf^o[]a[-HM","fields":{"JOYSTICK":"XBOX_RT"},"inputs":{"VAR":{"shadow":{"type":"variables_get_gamepad","id":"mF@Nc;|Y/%XOk5aXko;z","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}}}}}}}},"DO0":{"block":{"type":"blockMotorRun","id":"4XYL[(gZ[+e2lO3)@3,`","extraState":{"optionLevel":0},"fields":{"METHOD":"MOTOR_RUN_FOREVER"},"inputs":{"VAR":{"shadow":{"type":"variables_get_motor_device","id":"Q:/GLaygV]qGs9yYSJ?g","fields":{"VAR":{"id":"j6O*TQ9p!!~wOS2+ejmx","name":"turntable","type":"Motor"}}}},"VALUE0":{"shadow":{"type":"unit_angularVelocity","id":"F}gZf5N9$)1ItQ_md?nH","fields":{"VALUE0":500}},"block":{"type":"blockMathArithmetic","id":"2E]r(054Mw,580Dk3q/H","fields":{"OP":"MULTIPLY"},"inputs":{"A":{"shadow":{"type":"blockMathNumber","id":"nuukBh4)x^3lD[ROxwLL","fields":{"NUM":1}},"block":{"type":"blockMathArithmetic","id":"y6Y67tR}~8gbVsgFLvcM","fields":{"OP":"MINUS"},"inputs":{"A":{"shadow":{"type":"blockMathNumber","id":"qW+1HC(ZriM=PLlqUS-,","fields":{"NUM":1}},"block":{"type":"blockJoystickValue","id":"[1,iZs`EJZ)kyFJDdR2M","fields":{"JOYSTICK":"XBOX_LT"},"inputs":{"VAR":{"shadow":{"type":"variables_get_gamepad","id":"7aHvck}VXehp{rxrsN0a","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}}}}},"B":{"shadow":{"type":"blockMathNumber","id":"V6]_8qK2pNACUOO#]iQi","fields":{"NUM":1}},"block":{"type":"blockJoystickValue","id":"%{ZaMDy,}]2F[7|8qY*Q","fields":{"JOYSTICK":"XBOX_RT"},"inputs":{"VAR":{"shadow":{"type":"variables_get_gamepad","id":"n(uc*B-U^t+MkIGS(}v)","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}}}}}}}},"B":{"shadow":{"type":"blockMathNumber","id":"1ir0f-{^0b`vSO*WD6)R","fields":{"NUM":10}}}}}}}}},"ELSE":{"block":{"type":"blockMotorStop","id":"_=gMDa{iD!D2]K9yn;u1","inputs":{"VAR":{"shadow":{"type":"variables_get_simple_motor_device","id":"-YiTvYRy0*!wxUbf9WG2","fields":{"VAR":{"id":"j6O*TQ9p!!~wOS2+ejmx","name":"turntable","type":"Motor"}}}},"VALUE0":{"shadow":{"type":"parameters_stop_3","id":";LMv#OH!a4oLjQmKoCP|","fields":{"VALUE":"Stop.COAST"}}}}}}},"next":{"block":{"type":"blockComment","id":"GI,cftp8$x6^.lT{*YdG","fields":{"FIELDNAME":"Operate boom using direction pad up/down."},"next":{"block":{"type":"blockVariableSetValue","id":"g=BN0c8d`P*eV.XFl:Q1","inputs":{"VAR":{"shadow":{"type":"variables_get_any","id":"Z/OYALcQ87[]7s:^@H@b","fields":{"VAR":{"id":"2$8QA`jF?z^}g)5K3}Eg","name":"boom speed","type":"Any"}}}},"VALUE0":{"shadow":{"type":"blockMathNumber","id":"9-O:XmUA((~_:LDWlX2O","fields":{"NUM":0}},"block":{"type":"blockLogicTernaryDouble","id":"npG*+NOv8Yh,^WmNJOt4","inputs":{"VAL_A":{"shadow":{"type":"blockMathNumber","id":"KaF=L0Ca43km3y^,bVrd","fields":{"NUM":100}}},"IF_0":{"shadow":{"type":"blockLogicTrue","id":"$xEP.5fN9]3n.![,l6n^"},"block":{"type":"blockButtonIsPressed","id":")u`A*xCw(@|M40l2u|/.","inputs":{"VAR":{"shadow":{"type":"variables_get_keypad","id":"Pg5f=i^Mjn[y$qh(kmTn","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}},"VALUE0":{"shadow":{"type":"blockParametersButton","id":"1(GdHoM5dpV7[{RifQb3","fields":{"VALUE":"UP"}}}}}},"VAL_B":{"shadow":{"type":"blockMathNumber","id":"UliAM:mh$4nr7]XeWEaN","fields":{"NUM":-100}}},"IF_1":{"shadow":{"type":"blockLogicTrue","id":"Q[Lx1_BhjU==^Ikee/;/"},"block":{"type":"blockButtonIsPressed","id":"BcU*/_4d].ktOKK%[}wc","inputs":{"VAR":{"shadow":{"type":"variables_get_keypad","id":"IUD9{O9EAvHhnw|!I~.$","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}},"VALUE0":{"shadow":{"type":"blockParametersButton","id":"q7.TUof$s#4xjygy$h[J","fields":{"VALUE":"DOWN"}}}}}},"VAL_C":{"shadow":{"type":"blockMathNumber","id":"Yd7@:_nyEf8fF8oVgZ{T","fields":{"NUM":0}}}}}}},"next":{"block":{"type":"blockComment","id":"@BfFP$!tPga{L-X~8@+I","fields":{"FIELDNAME":"Operate jib using right joystick vertical movement."},"next":{"block":{"type":"blockVariableSetValue","id":"`HaQhR;*|tJj#axb4GU%","inputs":{"VAR":{"shadow":{"type":"variables_get_any","id":"j5?};JGa?2Sh85Q}wM7j","fields":{"VAR":{"id":"-M{(3[=2KvNq:!0qkKcR","name":"jib speed","type":"Any"}}}},"VALUE0":{"shadow":{"type":"blockMathNumber","id":"9-O:XmUA((~_:LDWlX2O","fields":{"NUM":0}},"block":{"type":"blockJoystickValue","id":"98{^w,[LXJ({cz@Btlqw","fields":{"JOYSTICK":"XBOX_RJ_Y"},"inputs":{"VAR":{"shadow":{"type":"variables_get_gamepad","id":"99NEh,onTrEB!GmfndS6","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}}}}}},"next":{"block":{"type":"blockComment","id":"%I=_Q6Nbo|Cs*Sa]RSCm","fields":{"FIELDNAME":"Operate hoist using bumpers."},"next":{"block":{"type":"blockVariableSetValue","id":"DI9:v_l3u=hQ_rI^C_Dp","inputs":{"VAR":{"shadow":{"type":"variables_get_any","id":"[}e5HeZEufpR%`~3|t9f","fields":{"VAR":{"id":"2#HSYq/*kK?5brey!U9G","name":"hoist speed","type":"Any"}}}},"VALUE0":{"shadow":{"type":"blockMathNumber","id":"9-O:XmUA((~_:LDWlX2O","fields":{"NUM":0}},"block":{"type":"blockLogicTernaryDouble","id":",.fbyK9:HMTD-r;@-[gk","inputs":{"VAL_A":{"shadow":{"type":"blockMathNumber","id":"o112W[FYVeuBGl#8yLEZ","fields":{"NUM":100}}},"IF_0":{"shadow":{"type":"blockLogicTrue","id":"$xEP.5fN9]3n.![,l6n^"},"block":{"type":"blockButtonIsPressed","id":"E/L$NUP94];.h1su^4t^","inputs":{"VAR":{"shadow":{"type":"variables_get_keypad","id":"(dwAS})E)Y:?+7C2T3q7","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}},"VALUE0":{"shadow":{"type":"blockParametersButton","id":"z@64K8^a$%KW~5aQdAQ?","fields":{"VALUE":"LB"}}}}}},"VAL_B":{"shadow":{"type":"blockMathNumber","id":"RBg+AASXiib;E]un14y:","fields":{"NUM":-100}}},"IF_1":{"shadow":{"type":"blockLogicTrue","id":"-e_WJDMnngR%oU:4W$l}"},"block":{"type":"blockButtonIsPressed","id":"4l)W8CSAHKiWbtWbjNk2","inputs":{"VAR":{"shadow":{"type":"variables_get_keypad","id":"=hw/A]C.tqUb]CM-KY1y","fields":{"VAR":{"id":"kv#upqR95=t$fHR]Tv14","name":"xbox","type":"XboxController"}}}},"VALUE0":{"shadow":{"type":"blockParametersButton","id":"b.=NCiI$*NhCY6S:._C+","fields":{"VALUE":"RB"}}}}}},"VAL_C":{"shadow":{"type":"blockMathNumber","id":"$1tmiXFp}ZnP]dxf^):$","fields":{"NUM":0}}}}}}},"next":{"block":{"type":"blockComment","id":"=/ms4P$mi~5g.U^2Bd@^","fields":{"FIELDNAME":"Broadcast the values, so the hub in the crane can observe it."},"next":{"block":{"type":"blockBleBroadcast","id":"nx?~|q{?h1)@cUnQOH.w","inputs":{"VAR":{"shadow":{"type":"variables_get_ble_hub","id":"hU1.iJ)d6.(mDb}Sy[rs","fields":{"VAR":{"id":",s{9VvtO*UTz|3O7odYk","name":"hub","type":"TechnicHub"}}}},"VALUE0":{"shadow":{"type":"blockMathNumber","id":"iS%ywNK14,1ny4aC`%MW","fields":{"NUM":0}},"block":{"type":"blockListCreate","id":"Ma{nzo3_N{P-*;%g4=P`","extraState":{"optionLevel":3},"inputs":{"ADD0":{"shadow":{"type":"blockMathNumber","id":"6QXX)VFsrMqxe^}X5XS%","fields":{"NUM":0}},"block":{"type":"blockVariableGetValue","id":"%E1~d,/@HbV;HGTF+@:b","inputs":{"VAR":{"shadow":{"type":"variables_get_any","id":"gVz2/,ZdIT^EV[v9CF#9","fields":{"VAR":{"id":"2$8QA`jF?z^}g)5K3}Eg","name":"boom speed","type":"Any"}}}}}}},"ADD1":{"shadow":{"type":"blockMathNumber","id":"+(U*w~i$lC7;#Ge~1}|3","fields":{"NUM":0}},"block":{"type":"blockVariableGetValue","id":"uu_g!zwaH7NM0xl+B`G+","inputs":{"VAR":{"shadow":{"type":"variables_get_any","id":"O:s*qFy]m=C:Yfdhoa80","fields":{"VAR":{"id":"-M{(3[=2KvNq:!0qkKcR","name":"jib speed","type":"Any"}}}}}}},"ADD2":{"shadow":{"type":"blockMathNumber","id":"FZqOE,xov)on)jP1yUkq","fields":{"NUM":0}},"block":{"type":"blockVariableGetValue","id":"^VU[:Pr4S1S*QNe!jf`N","inputs":{"VAR":{"shadow":{"type":"variables_get_any","id":"^}z/wy7=Z`*U[_8F^BL6","fields":{"VAR":{"id":"2#HSYq/*kK?5brey!U9G","name":"hoist speed","type":"Any"}}}}}}}}}}},"next":{"block":{"type":"blockWaitTime","id":"GeY5}[g=jnv#s-%7nJ]u","inputs":{"VALUE0":{"shadow":{"type":"unit_time","id":"duz7]AaE4[1-(TB}KUF=","fields":{"VALUE0":50}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}]},"variables":[{"name":"red","id":"3|UN2i._9vZ[3eLjGv0_","type":"ColorDef"},{"name":"orange","id":"#K$d9T1Y/Z*b5{l-8:nb","type":"ColorDef"},{"name":"yellow","id":"zbg+L`0EO|mQP7E6rt,p","type":"ColorDef"},{"name":"green","id":"_$kJGMcQ6L6A*x$M0HMo","type":"ColorDef"},{"name":"cyan","id":"J^g,2/HDrs|{P|mc7VK?","type":"ColorDef"},{"name":"blue","id":"B=YrHDt/`9_zl;(8|%Lb","type":"ColorDef"},{"name":"violet","id":"HJmBZ)?{G(D$lUcTri,7","type":"ColorDef"},{"name":"magenta","id":"S!=(Gg!@AW1uFM|3^W}*","type":"ColorDef"},{"name":"white","id":"4no6^I}RX-,bcE5k0.YG","type":"ColorDef"},{"name":"none","id":"xV)%k%yZ|3[]Wq,O(Jks","type":"ColorDef"},{"name":"drive base","id":"JL+H+s8l}amP8s=pHvRu","type":"DriveBase"},{"name":"hub","id":",s{9VvtO*UTz|3O7odYk","type":"TechnicHub"},{"name":"xbox","id":"kv#upqR95=t$fHR]Tv14","type":"XboxController"},{"name":"boom speed","id":"2$8QA`jF?z^}g)5K3}Eg","type":"Any"},{"name":"jib speed","id":"-M{(3[=2KvNq:!0qkKcR","type":"Any"},{"name":"hoist speed","id":"2#HSYq/*kK?5brey!U9G","type":"Any"},{"name":"left","id":"#[Q|2vwDf?Q!wdxC#]Jw","type":"Motor"},{"name":"right","id":"FN}[i60b|[RL~AY8,LIu","type":"Motor"},{"name":"turntable","id":"j6O*TQ9p!!~wOS2+ejmx","type":"Motor"}],"info":{"type":"pybricks","version":"1.2.2"}}
from pybricks.hubs import TechnicHub
from pybricks.iodevices import XboxController
from pybricks.parameters import Axis, Button, Direction, Port, Stop
from pybricks.pupdevices import Motor
from pybricks.robotics import DriveBase
from pybricks.tools import wait

# Set up all devices.
hub = TechnicHub(top_side=Axis.Z, front_side=Axis.X, broadcast_channel=5)
left = Motor(Port.C, Direction.CLOCKWISE)
right = Motor(Port.D, Direction.COUNTERCLOCKWISE)
turntable = Motor(Port.B, Direction.COUNTERCLOCKWISE)
drive_base = DriveBase(left, right, 48, 208)
xbox = XboxController()

# Initialize variables.
boom_speed = 0
jib_speed = 0
hoist_speed = 0


# The main program starts here.
while True:
    # If Y or X have a nonzero value:
    # - Then use Y for speed  and X for steering.
    # - Otherwise stop.
    if xbox.joystick_left()[1] or xbox.joystick_left()[0]:
        drive_base.drive(xbox.joystick_left()[1] * 2, xbox.joystick_left()[0] * 2)
    else:
        drive_base.stop()
    # We use the left minus the right trigger to control the turn table.
    # This lets you rotate it by pressing one or the other.
    # If that speed is zero, then coast the motor.
    if xbox.triggers()[0] - xbox.triggers()[1]:
        turntable.run((xbox.triggers()[0] - xbox.triggers()[1]) * 10)
    else:
        turntable.stop()
    # Operate boom using direction pad up/down.
    boom_speed = 100 if Button.UP in xbox.buttons.pressed() else (-100 if Button.DOWN in xbox.buttons.pressed() else 0)
    # Operate jib using right joystick vertical movement.
    jib_speed = xbox.joystick_right()[1]
    # Operate hoist using bumpers.
    hoist_speed = 100 if Button.LB in xbox.buttons.pressed() else (-100 if Button.RB in xbox.buttons.pressed() else 0)
    # Broadcast the values, so the hub in the crane can observe it.
    hub.ble.broadcast([boom_speed, jib_speed, hoist_speed])
    wait(50)

Program for the base hub.