Skip to content
This repository has been archived by the owner on Jan 29, 2021. It is now read-only.

Commit

Permalink
Merge pull request #22 from yconst/dev
Browse files Browse the repository at this point in the history
Model improvements and image related efficiency improvements
  • Loading branch information
yconst authored Sep 9, 2017
2 parents 1afc484 + 3ed7daa commit 3b19778
Show file tree
Hide file tree
Showing 13 changed files with 120 additions and 74 deletions.
34 changes: 21 additions & 13 deletions burro/composers/composers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
from config import config

from rover import Rover
from sensors import PiVideoStream
from sensors.cameras import PiVideoStream
from models import list_models
from pilots import (KerasCategorical,
from pilots import (KerasRegression, KerasCategorical,
RC, F710, MixedRC, MixedF710)
from mixers import AckermannSteeringMixer, DifferentialSteeringMixer
from drivers import NAVIO2PWM, Adafruit_MotorHAT
Expand All @@ -18,12 +18,12 @@

class Composer(object):

def new_vehicle(self):
def new_vehicle(self, type=config.car.type):
rover = Rover()
self.board_type = methods.board_type()
self.setup_pilots(rover)
self.setup_recorders(rover)
self.setup_mixers(rover)
self.setup_mixers(rover, type)
self.setup_remote(rover)
self.setup_indicators(rover)
self.setup_sensors(rover)
Expand Down Expand Up @@ -57,18 +57,26 @@ def setup_pilots(self, rover):
def setup_recorders(self, rover):
rover.recorder = FileRecorder()

def setup_mixers(self, rover):
def setup_mixers(self, rover, type):
if self.board_type is 'navio':
logging.info("Found NAVIO2 HAT - Setting up Ackermann car")
throttle_driver = NAVIO2PWM(2)
steering_driver = NAVIO2PWM(0)
rover.mixer = AckermannSteeringMixer(
steering_driver=steering_driver,
throttle_driver=throttle_driver)
if type == 'differential':
logging.info("Found NAVIO2 HAT - Setting up differential car")
left_driver = NAVIO2PWM(config.differential_car.left_channel)
right_driver = NAVIO2PWM(config.differential_car.right_channel)
rover.mixer = DifferentialSteeringMixer(
left_driver=left_driver,
right_driver=right_driver)
else:
logging.info("Found NAVIO2 HAT - Setting up Ackermann car")
throttle_driver = NAVIO2PWM(config.ackermann_car.throttle_channel)
steering_driver = NAVIO2PWM(config.ackermann_car.steering_channel)
rover.mixer = AckermannSteeringMixer(
steering_driver=steering_driver,
throttle_driver=throttle_driver)
elif self.board_type is 'adafruit':
logging.info("Found Adafruit Motor HAT - Setting up differential car")
left_driver = Adafruit_MotorHAT(config.differential.left_terminal)
right_driver = Adafruit_MotorHAT(config.differential.right_terminal)
left_driver = Adafruit_MotorHAT(config.differential_car.left_channel+1)
right_driver = Adafruit_MotorHAT(config.differential_car.right_channel+1)
rover.mixer = DifferentialSteeringMixer(
left_driver=left_driver,
right_driver=right_driver)
Expand Down
12 changes: 9 additions & 3 deletions burro/config/defaults.ini
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,20 @@ rotation = 0
crop_top = 0
crop_bottom = 0

[ackermann_car]
[car]
type="ackermann"
reverse_steering = False
max_steering_angle = 30.

[ackermann_car]
throttle_channel = 2
steering_channel = 0
drift_gain = 0.15

[differential_car]
left_terminal = 1
right_terminal = 2
# For Adafruit HAT nth channel is n+1th terminal
left_channel = 0
right_channel = 1
left_mult = 1.0
right_mult = 1.0
left_reverse = False
Expand Down
16 changes: 14 additions & 2 deletions burro/methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os
import subprocess
import re
import time

import numpy as np

Expand Down Expand Up @@ -40,14 +41,14 @@ def from_one_hot(y):
functions to help converting between angles and yaw input values.
'''

def angle_to_yaw(angle, limit=config.ackermann_car.max_steering_angle):
def angle_to_yaw(angle, limit=config.car.max_steering_angle):
'''
Convert from angle to yaw
'''
return angle / float(limit)


def yaw_to_angle(yaw, limit=config.ackermann_car.max_steering_angle):
def yaw_to_angle(yaw, limit=config.car.max_steering_angle):
'''
Convert from yaw to angle
'''
Expand Down Expand Up @@ -89,3 +90,14 @@ def board_type():
return 'navio'
elif '0x60' in addresses:
return 'adafruit'


'''
TIME TOOLS
'''

def current_milis():
'''
Return the current time in miliseconds
'''
return int(round(time.time() * 1000))
6 changes: 5 additions & 1 deletion burro/mixers/mixers.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def __init__(self,
def update(self, throttle, angle):
throttle = min(1, max(-1, -throttle))
yaw = min(1, max(-1, methods.angle_to_yaw(angle)))
if not config.ackermann_car.reverse_steering:
if not config.car.reverse_steering:
yaw = -yaw
self.throttle_driver.update(throttle)
self.steering_driver.update(yaw)
Expand All @@ -53,6 +53,10 @@ def update(self, throttle, angle):
r_speed = (throttle + angle * throttle / 90.) * config.differential_car.right_mult
l_speed = min(max(l_speed, -1), 1)
r_speed = min(max(r_speed, -1), 1)
if config.car.reverse_steering:
t_speed = l_speed
l_speed = r_speed
r_speed = t_speed
if config.differential_car.left_reverse:
l_speed = -l_speed
if config.differential_car.right_reverse:
Expand Down
3 changes: 2 additions & 1 deletion burro/pilots/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from pilots import BasePilot, KerasCategorical
from pilots import (BasePilot,
KerasCategorical, KerasRegression)
from rc import RC
from mixed import MixedRC, MixedF710
from f710 import F710
6 changes: 3 additions & 3 deletions burro/pilots/pilots.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,10 @@ def decide(self, img_arr):
img_arr = np.expand_dims(img_arr, axis=0)
prediction = self.model.predict(img_arr)
if len(prediction) == 2:
yaw = prediction[0]
throttle = prediction[1]
yaw = methods.angle_to_yaw(prediction[0][0])
throttle = prediction[1][0]
else:
yaw = prediction
yaw = methods.angle_to_yaw(prediction[0][0])
throttle = 0

avf = config.model.average_factor
Expand Down
22 changes: 13 additions & 9 deletions burro/recorders/filerecorder.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@

import time
import os
import shutil

from PIL import Image

import methods
from config import config

def current_milli_time(): return int(round(time.time() * 1000))

class BaseRecorder(object):

Expand All @@ -16,6 +15,9 @@ def __init__(self):
self.is_recording = False

def record_frame(self, image_array, angle, throttle):
'''
Record a single image frame
'''
pass


Expand All @@ -39,9 +41,9 @@ def make_instance_dir(self, sessions_path):
os.makedirs(instance_path)
return instance_path

def record_frame(self, image_array, angle, throttle):
def record_frame(self, image_buffer, angle, throttle):
'''
Record a single frame, with frame index, angle and throttle values
Record a single image buffer, with frame index, angle and throttle values
as its filename
'''
# throttle is inversed, i.e. forward is negative, backwards positive
Expand All @@ -60,11 +62,13 @@ def record_frame(self, image_array, angle, throttle):
self.frame_count,
file_angle,
file_throttle)
im = Image.fromarray(image_array)
im.save(filepath)
with open (filepath, 'w') as fd:
image_buffer.seek(0)
shutil.copyfileobj(image_buffer, fd, -1)
self.frame_count += 1

def create_img_filepath(self, directory, frame_count, angle, throttle):
def create_img_filepath(self, directory, frame_count,
angle, throttle, file_type='png'):
'''
Generate the complete filepath for saving an image
'''
Expand All @@ -77,6 +81,6 @@ def create_img_filepath(self, directory, frame_count, angle, throttle):
"_agl_" +
str(angle) +
"_mil_" +
str(current_milli_time()) +
'.jpg')
str(methods.current_milis()) +
'.' + file_type)
return filepath
2 changes: 1 addition & 1 deletion burro/remotes/frontend/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ ws.onmessage = function (event) {

const ImageView = {
view: function() {
return m("img", {class:"viewport", src:"data:image/jpeg;base64," + Store.data.image})
return m("img", {class:"viewport", src:"data:image/png;base64," + Store.data.image})
}
}

Expand Down
10 changes: 4 additions & 6 deletions burro/remotes/remotes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import json
Expand All @@ -18,11 +17,13 @@


class MainHandler(web.RequestHandler):

def get(self):
self.render('index.html')


class SocketHandler(websocket.WebSocketHandler):

def check_origin(self, origin):
return True

Expand Down Expand Up @@ -53,7 +54,7 @@ def on_close(self):

def send_status(self):
v = self.application.vehicle
img64 = v.vision_sensor.capture_base64()
img64 = v.vision_sensor.base64()
status = {
"image": img64,
"controls": {
Expand All @@ -80,6 +81,7 @@ def send_settings(self):


class WebRemote(web.Application):

def __init__(self, vehicle):
self.vehicle = vehicle
base_dir = os.path.dirname(__file__)
Expand All @@ -100,7 +102,3 @@ def start(self):
self.thread = threading.Thread(target=self.loop.start)
self.thread.daemon = True
self.thread.start()


if __name__ == "__main__":
main()
16 changes: 9 additions & 7 deletions burro/rover.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,29 @@ def run(self):
self.step()
stop_time = time.time()
self.f_time = stop_time - start_time
time.sleep(max(0.01, 0.05 - self.f_time))
time.sleep(max(0.005, 0.05 - self.f_time))

def step(self):
pilot_angle, pilot_throttle = self.pilot.decide(
self.vision_sensor.frame)

self.mixer.update(pilot_throttle, pilot_angle)

self.pilot_angle = pilot_angle
self.pilot_throttle = pilot_throttle

if self.record:
self.recorder.record_frame(
self.vision_sensor.frame, pilot_angle, pilot_throttle)
self.vision_sensor.image_buffer(),
pilot_angle, pilot_throttle)

if self.recorder.is_recording:
self.indicator.set_state('recording')
elif self.record:
self.indicator.set_state('standby')
else:
self.indicator.set_state('ready')

self.pilot_angle = pilot_angle
self.pilot_throttle = pilot_throttle

self.mixer.update(pilot_throttle, pilot_angle)


def selected_pilot_index(self):
return self.pilots.index(self.pilot)
Expand Down
1 change: 0 additions & 1 deletion burro/sensors/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
from sensors import *
Loading

0 comments on commit 3b19778

Please sign in to comment.