top of page
Forum Posts
Berndt Hamboeck
May 26, 2021
In Software
I connected a ESP32Cam module to the serial port of my Bittle. First I flashed a BIOS, which includes Micropython and the CAM drive on the ESP32 cam module. The ESP32Cam module is connected to my PC using a FTDI module to send the commands through VSCode to my Bittle through the ESP32Cam module (this connection is required for flashing the BIOS anyway). ESP32Cam FTDI U0TXD RX U0RXD TX GND GND 5V 5V Finally, I connected the Bittle with the ESP32Cam module: Bittle ESP32Cam GND GND RX GPIO14 TX GPIO12 I powered the Bittle through another cable, which delivers the 5V for the board. Now, it's time to send commands to the Bittle: from machine import UART
uart = UART(1, baudrate=115200, bits=8, parity=None, stop=1, tx=12, rx=14, rts=-1, cts=-1, txbuf=256, rxbuf=256, timeout=5, timeout_char=2)
uart.init()
# uart.write("krest".encode())
uart.write("ksit".encode())
# uart.write("kbalance".encode()) The next step is to deploy a simple web server, power the ESP32CAM module from the nyboard and position the camera to get usable images.........
2
0
223
Berndt Hamboeck
May 23, 2021
In Software
I extended the code available and described here to also be able to use the Bittle connected to the serial port (as in my bittle box was no bluetooth/wifi adapter). I added some messages on the screen, I thought this might come in handy... You need to: pip install pyBittle pygame bittle_xbox_controller.py: """This program allow to control Bittle using Xbox controller.
"""
import math
import pyBittle
import pygame
import sys
import time
__initialauthor__ = "EnriqueMoran"
# Define some colors.
BLACK = pygame.Color('black')
WHITE = pygame.Color('white')
BUTTONS_MAP = {
0: pyBittle.Command.BALANCE, # A
1: pyBittle.Command.REST, # B
2: pyBittle.Command.GREETING, # X
3: pyBittle.Command.SIT, # Y
4: pyBittle.Command.STEP, # LB
5: pyBittle.Command.GYRO # RB
}
class TextPrint(object):
def __init__(self):
self.reset()
self.font = pygame.font.Font(None, 20)
def tprint(self, window, textString):
textBitmap = self.font.render(textString, True, BLACK)
window.blit(textBitmap, (self.x, self.y))
self.y += self.line_height
def reset(self):
self.x = 10
self.y = 10
self.line_height = 15
def indent(self):
self.x += 10
def unindent(self):
self.x -= 10
class Controller():
def __init__(self, window_size=(1, 1),
connect_wifi=False, connect_bluetooth=False,
connect_com=False,
ip_addr=None, device_name=None, bt_port=None):
self.window_size = window_size
self.window = None
self.joystick = None
self.n_axes = 0
self.n_buttons = 0
self.n_hats = 0
self.bittle = None
self.connect_wifi = connect_wifi
self.connect_bluetooth = connect_bluetooth
self.connect_com = connect_com
self.ip_addr = ip_addr
self.device_name = device_name
self.bt_port = bt_port
self.direction = pyBittle.Command.BALANCE
def initialize(self):
# os.environ["DISPLAY"] = ":0"
# os.environ["SDL_VIDEODRIVER"] = "dummy" # Hide window
pygame.init()
controller_found = False
self.window = pygame.display.set_mode(self.window_size)
pygame.display.set_caption("Bittle controller")
self.clock = pygame.time.Clock()
pygame.joystick.init()
self.textPrint = TextPrint()
self.bittle = pyBittle.Bittle()
if self.connect_wifi:
self.bittle.wifiManager.ip = self.ip_addr
elif self.connect_bluetooth:
self.isconnected = self.bittle.connect_bluetooth()
elif self.connect_com:
self.isconnected = self.bittle.connect_serial(True)
try:
self.joystick = pygame.joystick.Joystick(0)
self.joystick.init()
self.n_axes = self.joystick.get_numaxes()
self.n_buttons = self.joystick.get_numbuttons()
self.n_hats = self.joystick.get_numhats()
print(f"Joystick found: {self.joystick.get_name()}")
controller_found = True
except:
print("No controller found!")
return controller_found
def read_inputs(self):
new_direction = self.direction
x_axis_value = 0
y_axis_value = 0
for i in range(self.n_axes):
axis_value = self.joystick.get_axis(i)
if i == 0: # Horizontal
x_axis_value = axis_value
elif i == 1: # Vertical
y_axis_value = -axis_value # Set FORWARD as positive value
if abs(x_axis_value) > 0.8 or abs(y_axis_value) > 0.8:
angle = self.get_angle(x_axis_value, y_axis_value)
if angle >= 337.5 or angle < 22.5:
new_direction = pyBittle.Direction.FORWARD
elif angle >= 22.5 and angle < 67.5:
new_direction = pyBittle.Direction.FORWARDRIGHT
elif angle >= 67.5 and angle < 112.5:
new_direction = pyBittle.Direction.FORWARDRIGHT
elif angle >= 112.5 and angle < 157.5:
new_direction = pyBittle.Direction.BACKWARDRIGHT
elif angle >= 157.5 and angle < 202.5:
new_direction = pyBittle.Direction.BACKWARD
elif angle >= 202.5 and angle < 247.5:
new_direction = pyBittle.Direction.BACKWARDLEFT
elif angle >= 247.5 and angle < 292.5:
new_direction = pyBittle.Direction.FORWARDLEFT
elif angle >= 292.5 and angle < 337.5:
new_direction = pyBittle.Direction.FORWARDLEFT
elif abs(x_axis_value) < 0.2 or abs(y_axis_value) < 0.2:
new_direction = pyBittle.Command.BALANCE # Stop
if self.direction != new_direction:
self.direction = new_direction
self.send_direction(self.direction)
self.textPrint.tprint(self.window, "Direction: {}".format(self.direction))
for i in range(self.n_buttons):
button = self.joystick.get_button(i)
if button == 1:
try:
command = BUTTONS_MAP[i]
self.send_command(command)
self.textPrint.tprint(self.window, "Command: {}".format(command))
except Exception as e:
print(e)
for i in range(self.n_hats):
gait = None
hat = self.joystick.get_hat(i)
if hat == (-1, 0): # Left pad
gait = pyBittle.Gait.CRAWL
elif hat == (1, 0): # Right pad
gait = pyBittle.Gait.TROT
elif hat == (0, -1): # Down pad
gait = pyBittle.Gait.WALK
elif hat == (0, 1): # Up pad
gait = pyBittle.Gait.RUN
if gait:
self.bittle.gait = gait
print(f"New gait selected: {gait}")
time.sleep(0.2)
self.textPrint.tprint(self.window, "Gait: {}".format(self.bittle.gait))
def run(self):
initialized = self.initialize()
if initialized:
running = True
clock = pygame.time.Clock()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.JOYBUTTONDOWN:
print("Joystick button pressed.")
elif event.type == pygame.JOYBUTTONUP:
print("Joystick button released.")
self.window.fill(WHITE)
self.textPrint.reset()
if self.connect_wifi:
self.textPrint.tprint(self.window, "WIFI Connnection")
elif self.connect_bluetooth:
self.textPrint.tprint(self.window, "Bluetooth Connnection")
else:
self.textPrint.tprint(self.window, "COM Connnection")
if not self.connect_wifi:
self.textPrint.tprint(self.window, "Connnected: {}".format(self.isconnected))
# Get count of joysticks.
joystick_count = pygame.joystick.get_count()
self.textPrint.tprint(self.window, "Number of joysticks: {}".format(joystick_count))
self.textPrint.indent()
# For each joystick:
for i in range(joystick_count):
joystick = pygame.joystick.Joystick(i)
joystick.init()
try:
jid = joystick.get_instance_id()
except AttributeError:
# get_instance_id() is an SDL2 method
jid = joystick.get_id()
self.textPrint.tprint(self.window, "Joystick {}".format(jid))
self.textPrint.indent()
# Get the name from the OS for the controller/joystick.
name = joystick.get_name()
self.textPrint.tprint(self.window, "Joystick name: {}".format(name))
try:
guid = joystick.get_guid()
except AttributeError:
# get_guid() is an SDL2 method
pass
else:
self.textPrint.tprint(self.window, "GUID: {}".format(guid))
# Usually axis run in pairs, up/down for one, and left/right for
# the other.
axes = joystick.get_numaxes()
self.textPrint.tprint(self.window, "Number of axes: {}".format(axes))
self.textPrint.indent()
for i in range(axes):
axis = joystick.get_axis(i)
self.textPrint.tprint(self.window, "Axis {} value: {:>6.3f}".format(i, axis))
self.textPrint.unindent()
buttons = joystick.get_numbuttons()
self.textPrint.tprint(self.window, "Number of buttons: {}".format(buttons))
self.textPrint.indent()
for i in range(buttons):
button = joystick.get_button(i)
if(button == 1):
self.textPrint.tprint(self.window,
"Button {:>2} value: {}".format(i, button))
self.textPrint.unindent()
hats = joystick.get_numhats()
self.textPrint.tprint(self.window, "Number of hats: {}".format(hats))
self.textPrint.indent()
# Hat position. All or nothing for direction, not a float like
# get_axis(). Position is a tuple of int values (x, y).
for i in range(hats):
hat = joystick.get_hat(i)
self.textPrint.tprint(self.window, "Hat {} value: {}".format(i, str(hat)))
self.textPrint.unindent()
self.textPrint.unindent()
self.read_inputs()
pygame.display.flip()
self.clock.tick(20)
pygame.quit()
def send_command(self, command):
if self.connect_wifi:
if self.bittle.has_wifi_connection():
self.bittle.send_command_wifi(command)
elif self.connect_bluetooth:
self.bittle.send_command_bluetooth(command)
elif self.connect_com:
self.bittle.send_command_serial(command)
print(f"Action: {command} sent")
time.sleep(0.5) # Let Bittle rest to prevent damage
return True
def send_direction(self, direction):
if self.connect_wifi:
if self.bittle.has_wifi_connection():
if direction == pyBittle.Command.BALANCE:
self.bittle.send_command_wifi(direction)
else:
self.bittle.send_movement_wifi(direction)
elif self.connect_bluetooth:
if direction == pyBittle.Command.BALANCE:
self.bittle.send_command_bluetooth(direction)
else:
self.bittle.send_movement_bluetooth(direction)
elif self.connect_com:
if direction == pyBittle.Command.BALANCE:
self.bittle.send_command_serial(direction)
else:
self.bittle.send_movement_serial(direction)
print(f"Direction: {direction} sent")
# Let Bittle rest to prevent damage, modify this under your own risk
time.sleep(0.5)
return True
def get_angle(self, xPercent, yPercent):
"""Returns joystick angle.
"""
angle_deg = 0
if xPercent > 0.9 and yPercent == 0:
angle_deg = 90
elif xPercent < -0.9 and yPercent == 0:
angle_deg = 270
elif xPercent == 0 and yPercent > 0.9:
angle_deg = 1
elif xPercent == 0 and yPercent < -0.9:
angle_deg = 180
elif (xPercent > 0 and yPercent > 0 and (xPercent > 0.2 or
yPercent > 0.2)):
angle_rad = math.atan2(xPercent, yPercent)
angle_deg = angle_rad * 180 / math.pi
elif (xPercent > 0 and yPercent < 0 and (xPercent > 0.2 or
yPercent < -0.2)):
angle_rad = math.atan2(xPercent, yPercent)
angle_deg = angle_rad * 180 / math.pi
elif (xPercent < 0 and yPercent < 0 and (xPercent < -0.2 or
yPercent < -0.2)):
angle_rad = math.atan2(xPercent, yPercent)
angle_deg = angle_rad * 180 / math.pi
angle_deg += 360
elif (xPercent < 0 and yPercent > 0 and (xPercent < -0.2 or
yPercent > 0.2)):
angle_rad = math.atan2(xPercent, yPercent)
angle_deg = angle_rad * 180 / math.pi
angle_deg += 360
return angle_deg
if __name__ == '__main__':
connect_wifi = False # Set to True to connect through WiFi
connect_bluetooth = False # Set to True to connect through Bluetooth
connect_com = True # Set to True to connect through COM port
ip_addr = '192.168.1.138' # Here goes your Bittle's IP address
controller = Controller(connect_wifi=connect_wifi,
connect_bluetooth=connect_bluetooth,
connect_com=connect_com,
window_size=(500, 400),
ip_addr=ip_addr)
if not connect_wifi and not connect_bluetooth and not connect_com:
print("No connection method selected.")
input("Press any key to exit.")
sys.exit()
try:
controller.run()
except KeyboardInterrupt:
if controller.connect_bluetooth:
print("Closing Bluetooth connection with Bittle")
try:
controller.bittle.send_command_bluetooth(pyBittle.Command.REST)
controller.bittle.disconnect_bluetooth()
print("Connection Closed")
except:
pass
input("Press any key to exit.")
sys.exit()
2
1
318
Berndt Hamboeck
More actions
bottom of page