Alvik Fight Club
The first rule about the Alvik fight club: Don’t talk about the Alvik fight club.
Components and supplies
Arduino® Nano ESP32
Various cables, bolts, nuts and screws
Modulino® Knob
Modulino® Pixels
Googly eyes
Nano Connector Carrier
Modulino Buttons
Arduino Alvik
Tools and machines
3D printer
Screwdrivers
Apps and platforms
Arduino MicroPyhton Installer
Arduino Lab for MicroPython
Project description
Code
Controller Sketch
python
The sketch for the controller
1import network 2import espnow 3import struct 4import random 5import sys 6import machine 7 8from arduino_alvik import ArduinoAlvik 9from time import sleep_ms, ticks_add, ticks_diff, ticks_ms 10 11try: 12 from modulino import ModulinoPixels, ModulinoColor 13except ImportError as e: 14 print("ImportError: ModulinoPixels not installed") 15 sys.exit(-1) 16 17LINEAR_VELOCITY = 10 # (max 13cm/s) 18ANGULAR_VELOCITY = 75 # (max 320.8988764044944) 19FREEZE_FOR_SECONDS = 5 20REVERT_CONTROLLER_FOR_SECONDS = 10 21 22 23# A WLAN interface must be active to send()/recv() 24sta = network.WLAN(network.STA_IF) 25sta.active(True) 26e = espnow.ESPNow() 27e.active(True) 28 29a = ArduinoAlvik() 30a.begin() 31 32pixels = ModulinoPixels(a.i2c) 33 34 35STOP = 0 36GO_FORWARD = 1 37GO_BACKWARD = 2 38TURN_LEFT = 3 39TURN_RIGHT = 4 40LIFT = 5 41 42 43isPlayingReverted = False # if true the controller action are reverted 44lifState = 0 # 0 = down, 1 = up 45 46lin = 0 47ang = 0 48 49def receiveAndExecuteFromEspNow(): 50 global lifState 51 global lin 52 global ang 53 _, msg = e.recv( 54 timeout_ms=0 55 ) # TODO: See ESPNow.irecv() for a memory-friendly alternative. 56 if msg is None: 57 return 58 if len(msg) < 1: # discard garbage 59 return 60 unpacked_message = struct.unpack("B", msg) 61 msg_type = unpacked_message[0] 62 63 if int(msg_type) == STOP: 64 lin, ang = 0, 0 65 a.drive(lin, ang) 66 elif int(msg_type) == GO_FORWARD: 67 lin = LINEAR_VELOCITY if isPlayingReverted else -LINEAR_VELOCITY 68 ang = 0 69 a.drive(lin, ang) 70 elif int(msg_type) == GO_BACKWARD: 71 lin = -LINEAR_VELOCITY if isPlayingReverted else LINEAR_VELOCITY 72 ang = 0 73 a.drive(lin, ang) 74 elif int(msg_type) == TURN_LEFT: 75 ang = -ANGULAR_VELOCITY if isPlayingReverted else ANGULAR_VELOCITY 76 a.drive(lin, ang) 77 elif int(msg_type) == TURN_RIGHT: 78 ang = ANGULAR_VELOCITY if isPlayingReverted else -ANGULAR_VELOCITY 79 a.drive(lin, ang) 80 elif int(msg_type) == LIFT: 81 if lifState == 0: 82 liftUp() 83 lifState = 1 84 else: 85 liftDown() 86 lifState = 0 87 else: 88 print("unknown command type ", msg_type) 89 90 91def liftUp(): 92 a.set_servo_positions(0, 180) 93 sleep_ms(25) 94 a.set_servo_positions(5, 175) 95 sleep_ms(25) 96 a.set_servo_positions(10, 170) 97 sleep_ms(25) 98 a.set_servo_positions(15, 165) 99 sleep_ms(25) 100 a.set_servo_positions(20, 160) 101 sleep_ms(25) 102 103 104def liftDown(): 105 a.set_servo_positions(15, 165) 106 sleep_ms(25) 107 a.set_servo_positions(10, 170) 108 sleep_ms(25) 109 a.set_servo_positions(15, 175) 110 sleep_ms(25) 111 a.set_servo_positions(0, 180) 112 113 114def showReadyToPlayLeds(): 115 if not pixels.connected: 116 a.left_led.set_color(red=False, green=True, blue=False) 117 a.right_led.set_color(red=False, green=True, blue=False) 118 return 119 pixels.set_all_color(ModulinoColor.GREEN, 15) 120 pixels.show() 121 122 123def showEndAnimation(): 124 if not pixels.connected: 125 a.left_led.set_color(red=True, green=False, blue=False) 126 a.right_led.set_color(red=True, green=False, blue=False) 127 sleep_ms(100) 128 a.left_led.set_color(red=False, green=False, blue=False) 129 a.right_led.set_color(red=False, green=False, blue=False) 130 sleep_ms(100) 131 return 132 133 for i in range(0, 8): 134 pixels.clear_all() 135 pixels.set_rgb(i, 255, 0, 0, 15) 136 pixels.show() 137 sleep_ms(50) 138 139 for i in range(7, -1, -1): 140 pixels.clear_all() 141 pixels.set_rgb(i, 255, 0, 0, 15) 142 pixels.show() 143 sleep_ms(50) 144 145 146def showRevertedAnimation(mapped): 147 if not pixels.connected: 148 a.left_led.set_color(red=True, green=False, blue=True) 149 a.right_led.set_color(red=True, green=False, blue=True) 150 sleep_ms(100) 151 a.left_led.set_color(red=False, green=False, blue=False) 152 a.right_led.set_color(red=False, green=False, blue=False) 153 sleep_ms(100) 154 return 155 pixels.clear_all() 156 pixels.set_range_color(0, mapped, ModulinoColor.VIOLET) 157 pixels.show() 158 159 160def showFreezeAnimation(): 161 for x in range(0, FREEZE_FOR_SECONDS): 162 sleep_ms(500) 163 if not pixels.connected: 164 a.left_led.set_color(red=False, green=False, blue=True) 165 a.right_led.set_color(red=False, green=False, blue=True) 166 else: 167 pixels.set_all_color(ModulinoColor.BLUE, 15) 168 pixels.show() 169 sleep_ms(500) 170 171def showSlipAnimation(): 172 if not pixels.connected: 173 print("pixels not connect, slip not") 174 return 175 pixels.set_all_color(ModulinoColor.YELLOW, 15) 176 pixels.show() 177 178 179def map_value(value, from_low, from_high, to_low, to_high): 180 return int( 181 (value - from_low) * (to_high - to_low) / (from_high - from_low) + to_low 182 ) 183 184 185def countdown_color(color, ledoff_every_tick=2): 186 for i in range(7, 0, -ledoff_every_tick): 187 if not pixels.connected: 188 a.left_led.set_color(red=True, green=True, blue=True) 189 a.right_led.set_color(red=True, green=True, blue=True) 190 else: 191 pixels.set_range_color(0, i, color) 192 pixels.show() 193 sleep_ms(500) 194 if not pixels.connected: 195 a.left_led.set_color(red=False, green=False, blue=False) 196 a.right_led.set_color(red=False, green=False, blue=False) 197 else: 198 pixels.clear_all() 199 pixels.show() 200 sleep_ms(500) 201 202 203def calibrate_color(): 204 print("Reading white color") 205 for i in range(7, 0, -2): 206 if not pixels.connected: 207 a.left_led.set_color(red=True, green=True, blue=True) 208 a.right_led.set_color(red=True, green=True, blue=True) 209 else: 210 pixels.set_range_color(0, i, ModulinoColor.WHITE) 211 pixels.show() 212 sleep_ms(500) 213 if not pixels.connected: 214 a.left_led.set_color(red=False, green=False, blue=False) 215 a.right_led.set_color(red=False, green=False, blue=False) 216 else: 217 pixels.clear_all() 218 pixels.show() 219 sleep_ms(500) 220 221 a.color_calibration("white") 222 223 print("Reading black color") 224 for i in range(7, 0, -2): 225 if not pixels.connected: 226 a.left_led.set_color(red=False, green=False, blue=True) 227 a.right_led.set_color(red=False, green=False, blue=True) 228 else: 229 pixels.set_range_color(0, i, ModulinoColor.BLUE) 230 pixels.show() 231 sleep_ms(500) 232 if not pixels.connected: 233 a.left_led.set_color(red=False, green=False, blue=False) 234 a.right_led.set_color(red=False, green=False, blue=False) 235 else: 236 pixels.clear_all() 237 pixels.show() 238 sleep_ms(500) 239 a.color_calibration("black") 240 241 if pixels.connected: 242 pixels.set_all_color(ModulinoColor.GREEN, 15) 243 pixels.show() 244 else: 245 a.left_led.set_color(red=False, green=True, blue=False) 246 a.right_led.set_color(red=False, green=True, blue=False) 247 sleep_ms(2000) 248 249 # hard-reset the board to refresh the calibration (read again the color from the file) 250 machine.reset() 251 252 253STATE_SETUP = -1 254STATE_INIT = 0 255STATE_PLAY = 1 256 257state = STATE_INIT 258 259deadline = 0 260while True: 261 try: 262 if state == STATE_SETUP: 263 calibrate_color() 264 265 if state == STATE_INIT: 266 a.drive(0, 0) 267 showEndAnimation() 268 if a.get_touch_ok(): 269 state = STATE_SETUP 270 if a.get_color_label() is not "BLACK": 271 showReadyToPlayLeds() 272 state = STATE_PLAY 273 274 elif state == STATE_PLAY: 275 receiveAndExecuteFromEspNow() 276 277 if a.get_touch_ok(): 278 state = STATE_SETUP 279 280 color = a.get_color_label() 281 if color == "BLACK": 282 state = STATE_INIT 283 elif color == "YELLOW": 284 showSlipAnimation() 285 deg = random.choice( 286 [30.0, 45.0, 90.0, 130.0, 150.0, 180.0, 275.0, 360.0] 287 ) 288 a.rotate(deg, "deg") 289 showReadyToPlayLeds() 290 elif color == "BLUE" or color == "LIGHT BLUE": 291 a.drive(0, 0) 292 showFreezeAnimation() 293 showReadyToPlayLeds() 294 while a.get_color_label() == "BLUE" or a.get_color_label() == "LIGHT BLUE": 295 receiveAndExecuteFromEspNow() 296 elif color == "GREEN" or color == "LIGHT GREEN": 297 if not isPlayingReverted: 298 deadline = ticks_add( 299 ticks_ms(), REVERT_CONTROLLER_FOR_SECONDS * 1000 300 ) 301 isPlayingReverted = True 302 303 if isPlayingReverted: 304 elapsed = ticks_diff(deadline, ticks_ms()) 305 mapped = map_value( 306 elapsed, 0, REVERT_CONTROLLER_FOR_SECONDS * 1000, 0, 7 307 ) 308 showRevertedAnimation(mapped) 309 if elapsed < 0: 310 showReadyToPlayLeds() 311 isPlayingReverted = False 312 except AssertionError: 313 print("AssertionError") 314 # If calibration is not done correctly, the _limit() function can raise an AssertError 315 # See https://github.com/arduino/arduino-alvik-mpy/blob/80e66561a2ae06c69adddb3adc21ca88f91a57dd/arduino_alvik/arduino_alvik.py#L724 316 state = STATE_SETUP 317 continue 318 sleep_ms(50)
MAC Checker
python
Checks the MAC address of your device.
1import network 2 3# Initialize the WLAN interface 4wlan = network.WLAN(network.STA_IF) 5 6# Get and print the MAC address 7mac = wlan.config('mac') 8print("MAC Address:", ':'.join(['%02x' % b for b in mac]))
Fighter Sketch
python
The sketch for the Alvik Robot
1import network 2import espnow 3import struct 4import sys 5from time import sleep 6 7from modulino import ModulinoKnob, ModulinoButtons 8 9 10ALVIK_MAC = "74:4d:bd:a2:08:74" 11 12sta = network.WLAN(network.STA_IF) # Or network.AP_IF 13sta.active(True) 14e = espnow.ESPNow() 15e.active(True) 16 17 18def mac_str_to_bytes(mac_str): 19 mac_str = mac_str.replace(":", "") 20 return bytes.fromhex(mac_str) 21 22 23_mac_peer = mac_str_to_bytes(ALVIK_MAC) 24 25try: 26 e.add_peer(_mac_peer) 27except OSError as exp: 28 print(f"Skip to connect to network: {exp}") 29 30buttons = ModulinoButtons() 31if not buttons.connected: 32 print("🤷 No button modulino found") 33 sys.exit() 34 35knob = ModulinoKnob() 36if not knob.connected: 37 print("🤷 No knob modulino found") 38 sys.exit() 39knob.range = (-15, 15) # (Optional) Set a value range 40 41STOP = 0 42GO_FORWARD = 1 43GO_BACKWARD = 2 44TURN_LEFT = 3 45TURN_RIGHT = 4 46LIFT = 5 47 48 49def stop(): 50 e.send(_mac_peer, struct.pack("B", STOP), True) 51 52 53def go_forward(): 54 e.send(_mac_peer, struct.pack("B", GO_FORWARD), True) 55 56 57def go_backward(): 58 e.send(_mac_peer, struct.pack("B", GO_BACKWARD), True) 59 60 61def turn_left(): 62 e.send(_mac_peer, struct.pack("B", TURN_LEFT), True) 63 64 65def turn_right(): 66 e.send(_mac_peer, struct.pack("B", TURN_RIGHT), True) 67 68 69def lift(): 70 e.send(_mac_peer, struct.pack("B", LIFT), True) 71 72 73buttons.on_button_a_press = lambda: go_forward() 74buttons.on_button_b_press = lambda: stop() 75buttons.on_button_c_press = lambda: go_backward() 76 77knob.on_press = lambda: lift() 78knob.on_rotate_clockwise = lambda _, __: turn_right() 79knob.on_rotate_counter_clockwise = lambda _, __: turn_left() 80 81while True: 82 knob.update() 83 buttons.update() 84 85 sleep(0.1)
Downloadable files
PowerPack Holder (Controller)
power-pack-holder.stl
Body (Controller)
file.None
Back Plate (Alvik)
file.None
Scoop
lift-arm-scoop.stl
Top Plate (Alvik)
top-plate.stl
Top Plate Brackets (Alvik)
top-plate-holder.stl
Arms (Alvik)
You need 2 sets and one should be mirrored
lift-arm-servo.stl
Comments
Only logged in users can leave comments