Ryan Fogle
Published

UIUC ME 461 Final Project --Ryan Fogle

As a part of my ME 461 class, I used a TI board and an Orange PI Zero to wirelessly control the bot on two wheels through a website.

AdvancedShowcase (no instructions)210
UIUC ME 461 Final Project --Ryan Fogle

Things used in this project

Hardware components

Orange PI Zero
×1
Texas Instruments TMS320F28379D
×1

Story

Read more

Code

Final Project Zip

C/C++
Compressed file of the workspace
No preview (download only).

Orange PI Zero Code

Python
No preview (download only).

Flask app.py

Python
The web server code
from flask import Flask
from flask import render_template
from flask import jsonify
from flask import request
from serial import Serial
import redis
import pickle

# connect to ttyS2
app = Flask(__name__)
ser = Serial('/dev/ttyS2', 115200)
r = redis.StrictRedis('0.0.0.0')


@app.route('/')
def bot():
    return render_template('bot.html')


@app.route('/data/', methods=['GET', 'POST'])
def recieve_data():
    bot_data = request.json
    p_data = pickle.dumps(bot_data)
    r.set('data', p_data)

    return jsonify({'status': 'success'})


@app.route('/get_data/')
def get_data():
    # for testing purposes

    p_data = r.get('data')
    if p_data is not None:
        bot_data = pickle.loads(p_data)
        return jsonify(bot_data)
    else:
        return jsonify({'status': 'failed'})


@app.route('/control/', methods=['GET', 'POST'])
def control():
    try:
        res = request.get_json()
        print(res)
        ser.write(res['turn'].encode())
        ser.write(res['speed'].encode())
    except Exception as e:
        print(e)
        return jsonify({'status': 'failed'})

    return jsonify({'status': 'success'})


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Data Collection gather.py

Python
This is how I collected the data
import serial
import requests

# data dictionary
data = {}

# open connect to UART
with serial.Serial('/dev/ttyS2', baudrate=115200) as ser:
    print("reading first line")
    # read first msg
    msg = ser.readline().decode()
    print('Finished reading first line')

    # create a continous loop to read messages
    while msg:

        # split values based on comma
        tokens = msg.split(',')

        # loop over value strings
        for token in tokens:
            # split name and value
            if ":" in token:
                name, val = token.split(':', 1)

                # trim whitespace
                name = name.strip()
                val = val.strip()

                # add to data dictionary
                data[name] = val
            else:
                print(token)

        # send data to web server
        url = 'http://0.0.0.0:5000/data/'

        headers = {}
        try:
            x = requests.post(url, json=data)
            print(data)
        except Exception as e:
            print(e)

        msg = ser.readline().decode()

HMTL JoyStick Page

HTML
Webpage that was delievered
<!doctype html>
<html lang='en'>

<head>
    <meta charset="utf-8">
</head>

<body class="noselect" onload="init();">
    <div class="container space-top">
        <h1 class="center blue-text thin">Robot Joystick</h1>
        <div class="center-align">
            <canvas id="joystick" height="300" width="300"></canvas>
        </div>
        <p class="light">X: <span id="xVal" >0</span></p>
        <pclass="light">Y: <span id="yVal" >0</span></p>
    </div>
    <div class="slidecontainer">
        <p>Speed: <span id='speed'>0</span> %</p>
        <input type="range" min="0" max="100" value="0" class="slider" id="myRange">
    </div>
    <div>
        <p>Right Distance <span id='rightdist'>0</span> rads</p>
        <p>Left Distance: <span id='leftdist'>0</span> rads</p>
        <p>Right Speed: <span id='rightspeed'>0</span> ft/s</p>
        <p>Left Speed: <span id='leftspeed'>0</span> ft/s</p>
    </div>
    <script src="https://code.createjs.com/1.0.0/createjs.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.5.1.js"
        integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"
        integrity="sha512-UXumZrZNiOwnTcZSHLOfcTs0aos2MzBWHXOHOuB0J/R44QB0dwY5JgfbvljXcklVf65Gc4El6RjZ+lnwd2az2g=="
        crossorigin="anonymous"></script>
</body>
<style>
    body {
        height: 100%;
        width: 100%;
        background-color: #dedede;
        margin-left: 200px;
    }

    .space-top {
        padding-top: 10px;
    }

    #joystick {
        height: 400px;
        width: 400px;
        border-radius: 400px;
        -moz-border-radius: 400px;
        -webkit-border-radius: 400px;
        text-align: center;
        background-color: #80d5ff;
        font: 24px/400px Helvetica, Arial, sans-serif;
        cursor: all-scroll;
        user-select: none;
        z-index: -100;
    }

    .noselect {
        -webkit-touch-callout: none;
        -webkit-user-select: none;
        -khtml-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
    }

    .slidecontainer {
        width: 100%;
    }

    .slider {
        -webkit-appearance: none;
        width: 50%;
        height: 25px;
        background: #d3d3d3;
        outline: none;
        opacity: 0.7;
        -webkit-transition: .2s;
        transition: opacity .2s;
    }

    .slider:hover {
        opacity: 1;
    }

    .slider::-webkit-slider-thumb {
        -webkit-appearance: none;
        appearance: none;
        width: 25px;
        height: 25px;
        background: #4CAF50;
        cursor: pointer;
    }

    .slider::-moz-range-thumb {
        width: 25px;
        height: 25px;
        background: #4CAF50;
        cursor: pointer;
    }
</style>
<script>
    function init() {
        // easal stuff goes hur
        var xCenter = 150;
        var yCenter = 150;
        var stage = new createjs.Stage('joystick');

        var psp = new createjs.Shape();
        psp.graphics.beginFill('#333333').drawCircle(xCenter, yCenter, 50);

        psp.alpha = 0.25;

        var vertical = new createjs.Shape();
        var horizontal = new createjs.Shape();
        vertical.graphics.beginFill('#ff4d4d').drawRect(150, 0, 2, 300);
        horizontal.graphics.beginFill('#ff4d4d').drawRect(0, 150, 300, 2);

        stage.addChild(psp);
        stage.addChild(vertical);
        stage.addChild(horizontal);
        createjs.Ticker.framerate = 60;
        createjs.Ticker.addEventListener('tick', stage);
        stage.update();

        var myElement = $('#joystick')[0];

        // create a simple instance
        // by default, it only adds horizontal recognizers
        var mc = new Hammer(myElement);

        mc.on("panstart", function (ev) {
            var pos = $('#joystick').position();
            xCenter = psp.x;
            yCenter = psp.y;
            psp.alpha = 0.5;

            stage.update();
        });

        // listen to events...
        mc.on("panmove", function (ev) {
            var pos = $('#joystick').position();

            x = (ev.center.x - pos.left - 250);
            var y = (ev.center.y - pos.top - 170);
            $('#xVal').text(x);
            $('#yVal').text(-1 * y);

            var coords = calculateCoords(ev.angle, ev.distance);

            psp.x = coords.x;
            psp.y = coords.y;

            psp.alpha = 0.5;

            stage.update();
        });

        mc.on("panend", function (ev) {
            psp.alpha = 0.25;
            createjs.Tween.get(psp).to({
                x: xCenter,
                y: yCenter
            }, 750, createjs.Ease.elasticOut);
            $('#xVal').text(0);
            $('#yVal').text(0);
        });

        $('#myRange').change(function () {
            $('#speed').text($('#myRange').val());
        });

        setInterval(sendData, 250);
        setInterval(getData, 250);
    }

    function calculateCoords(angle, distance) {
        var coords = {};
        distance = Math.min(distance, 100);
        var rads = (angle * Math.PI) / 180.0;

        coords.x = distance * Math.cos(rads);
        coords.y = distance * Math.sin(rads);

        return coords;
    }

    function getTurn(x) {
        if (x > 0) {
            return 'R';
        }
        else if (x < 0) {
            return 'L';
        }
        else if (x == 0) {
            return 'C';
        }
    }

    function getSpeed(speed) {
        if (speed == 0) {
            return '0'
        }
        else if (speed == 100) {
            return '6';
        } else if (speed > 80) {
            return '5';
        } else if (speed > 60) {
            return '4';
        } else if (speed > 40) {
            return '3';
        } else if (speed > 20) {
            return '2';
        } else if (speed > 0) {
            return '1';
        }
    }

    function sendData() {
        let percent = parseInt($('#speed').text());
        let spd = getSpeed(percent);
        var x = parseInt($('#xVal').text());
        let turn = getTurn(x);

        let data_obj = {turn: turn, speed: spd};
        // console.log(JSON.stringify(data_obj));

        $.ajax({
            url: '/control/',
            type: 'POST',
            dataType: 'json',
            data: JSON.stringify(data_obj),
            contentType: "application/json",
            success: function (data) {
                // console.log(data);
            }
        });
    }

    function getData() {
        $.ajax({
            url: '/get_data/',
            type: 'GET',
            dataType: 'json',
            contentType: "application/json",
            success: function (data) {
                $('#rightdist').text(data['RightDistance']);
                $('#leftdist').text(data['LeftDistance']);
                $('#rightspeed').text(data['rawRightVel']);
                $('#leftspeed').text(data['rawLeftVel']);
            }
        });
    }
</script>

</html>

Credits

Ryan Fogle

Ryan Fogle

1 project • 0 followers

Comments