mbedKart
Overview
By Derek Watson and Silvan Li
mbedKart uses the mbed Shadow Robot to bring Nintendo's ingenious game, Mario Kart, to life. The mbedKart is controlled through Bluetooth, and interacts with its environment to gain various powerups and determine its progress through the map.
Import programmbedKart_sp
single player mbedKart

Controls
The controller function in the Adafruit Bluefruit app is used to control the mbedKart. Key bindings are shown as follows:
| Key | Action |
|---|---|
| Left | Steer Left |
| Right | Steer Right |
| 1 | Pause |
| 2 | Accelerate |
| 4 | Reverse |
Gameplay
Under normal circumstances, the mbedKart has a limited max speed, and reaching this maximum speed is not an instantaneous process. Holding down the accelerate button (2) will gradually increase the speed of the kart until it reaches its max speed. Upon release of the accelerate button, the kart will slowly coast to a steady stop. Holding the reverse button (4) will cause the kart to gradually speed up in reverse up to the negative of its max speed. Pausing the game (1) will immediately stop the kart and will allow the kart to instantaneously return to its velocity prior to pausing.
Driving over an area that the RGB sensor detects as blue will give the mbedKart a temporary boost in speed. This boost increases the kart's max speed for 5 seconds. The race is won when the kart drives over an area the RGB sensor detects as red. Upon victory, the kart will immediately stop and perform a victory celebration with its RGB Led.
Hardware
Components
- Shadow Robot Kit
- mbed LPC1768
- RGB Led
- 3x 180-330 Ohm Resistors
- TCS34725 RGB Sensor
- Mini USB Breakout
- TB6612FNG Motor Driver
- UART Bluetooth Module
RGB Sensor
| RGB Sensor | mbed |
|---|---|
| LED | p30 |
| SDA | p28 |
| SCL | p27 |
| GND | gnd |
| VIN | 3.3v |
Since there is no publicly available library for the TCS34725 RGB sensor, mbedKart uses a custom class, rgbSensor. The rgbSensor class is instantiated with rgbSensor(sda, scl, led). Values return by each color's corresponding get_x() is an int that ranges from 0-32767.
rgbSensor.h
//Class to interface with the RGB color sensor over I2C
class rgbSensor
{
protected:
I2C _i2c;
DigitalOut _led;
int sensor_addr;
int value_C;
int value_R;
int value_G;
int value_B;
public:
rgbSensor(PinName,PinName,PinName);
void update();
int get_C();
int get_R();
int get_G();
int get_B();
};
rgbSensor::rgbSensor(PinName sda, PinName scl, PinName led) :
_i2c(sda, scl), _led(led){
value_R = 0;
value_G = 0;
value_B = 0;
sensor_addr = 41 << 1;
_i2c.frequency(200000);
char id_regval[1] = {146};
char data[1] = {0};
_i2c.write(sensor_addr,id_regval,1, true);
_i2c.read(sensor_addr,data,1,false);
char timing_register[2] = {129,0};
_i2c.write(sensor_addr,timing_register,2,false);
char control_register[2] = {143,0};
_i2c.write(sensor_addr,control_register,2,false);
char enable_register[2] = {128,3};
_i2c.write(sensor_addr,enable_register,2,false);
_led = 1;
}
void rgbSensor::update()
{
char clear_reg[1] = {148};
char clear_data[2] = {0,0};
_i2c.write(sensor_addr,clear_reg,1, true);
_i2c.read(sensor_addr,clear_data,2, false);
value_C = ((int)clear_data[1] << 8) | clear_data[0];
char red_reg[1] = {150};
char red_data[2] = {0,0};
_i2c.write(sensor_addr,red_reg,1, true);
_i2c.read(sensor_addr,red_data,2, false);
value_R = ((int)red_data[1] << 8) | red_data[0];
char green_reg[1] = {152};
char green_data[2] = {0,0};
_i2c.write(sensor_addr,green_reg,1, true);
_i2c.read(sensor_addr,green_data,2, false);
value_G = ((int)green_data[1] << 8) | green_data[0];
char blue_reg[1] = {154};
char blue_data[2] = {0,0};
_i2c.write(sensor_addr,blue_reg,1, true);
_i2c.read(sensor_addr,blue_data,2, false);
value_B = ((int)blue_data[1] << 8) | blue_data[0];
}
int rgbSensor::get_C()
{
return value_C;
}
int rgbSensor::get_R()
{
return value_R;
}
int rgbSensor::get_G()
{
return value_G;
}
int rgbSensor::get_B()
{
return value_B;
}
Motors
| Motor Driver | mbed |
|---|---|
| PWMA | p22 |
| AIN2 | p16 |
| AIN1 | p17 |
| STBY | 3.3v |
| BIN1 | p19 |
| BIN2 | p20 |
| PWMB | p23 |
| GND | gnd |
| VM | 5v |
| VCC | 3.3v |
Import libraryMotor
Control an H-Bridge using a PwmOut (enable) and two DigitalOuts (direction select)
In order to achieve precise and bidirectional control of the wheels, the mbedKart uses a motor H-bridge driver with the Motor library.
Bluetooth
| Module | mbed |
|---|---|
| CTS | gnd |
| TXO | p14 |
| RXI | p13 |
| VIN | 5v |
| GND | gnd |
The Bluetooth module uses serial TX/RX ports to communicate with the mbed. In order to read the messages, a series of getc() functions are called with their contents read individually.
Potential Multiplayer Options
Although this version of mbedKart is single player only, code for this cart can be modified to support Wi-Fi communication with a central server. The example Python script below runs on an EC2 instance running Ubuntu and can be used as a simple server for multiplayer mbedKart. Karts connect to the server and periodically sends updates while the server keeps track of position within the race and can send hazards occasionally.
mbedKartServer.py
from socket import *
import json
import time
kartList = []
kartID = 0
maxKarts = 2
checkpoints = 5
end = False
def createServer():
global kartID
serversocket = socket(AF_INET, SOCK_STREAM)
serversocket.bind(('localhost',9003))
serversocket.listen(5)
while(kartID < maxKarts):
print('listening')
(clientsocket, address) = serversocket.accept()
clientsocket.settimeout(0.1)
kart = {
"client": clientsocket,
"id": kartID,
"place": 0,
"progress": 0
}
kartList.append(kart)
kartID = kartID + 1
print clientsocket.recv(4096)
clientsocket.send("Hello")
clientsocket.send(str(kart['id']))
print(str(len(kartList)) + ' player(s) have joined. Waiting on ' + str(maxKarts - len(kartList)))
serversocket.close()
def startGame():
global end, checkpoints
print('starting game')
time.sleep(1)
for k in kartList:
k['client'].send('S')
time.sleep(.5)
while not end:
for k in kartList:
try:
data = k['client'].recv(8)
if data:
print(data + str(k['id']))
if data[0] == 'U':
k['progress'] = k['progress'] + 1
if k['progress'] == checkpoints:
end = True
if data[0] == 'F':
pass #put game logic here
if end:
k['client'].send('E')
else:
k['client'].send('N')
except:
pass
def closeServer():
for k in kartList:
k['client'].shutdown(SHUT_WR)
k['client'].close()
if __name__ == "__main__":
createServer()
startGame()
closeServer()
Please log in to post comments.
