Electric Skate Board


electric skateboard

 

Describing my electric skateboard build. I have only driven this board seven miles so I cant say how far it will go. But I can say that its scary fast and very fun!

Electrical was a cinch!

Below you can see the layout of the parts that are needed for the electronics. I screwed and glued a waterproof case to contain all this to the bottom of the board.

electric skateboard parts

My big mistake

This board is fast I wish it was higher off the ground with larger inflatable tires. Secondly because electric motor low rpm torque is terrible I wish I had a kit that reduced the gear ratio even more than my current kit which was purchased off amazon. See below and notice how this wheel had a bunch of small holes. Making sure your gear fits your wheel is probably the most difficult part of the build if you order the wrong stuff. Also my belt was at maximum tension and I ended up adding bearings on each side that tension the belt.

electric skateboard wheel

 

electric skateboard pulley idler

 

Controlling software

So I had to code the arduino to accept blue tooth commands. Here the code below loops on the bluetooth signal and the gradually increases or reduces an int value that the esc is programmed to recognize.

 

 


#include <Servo.h>
#include <SoftwareSerial.h>
#include <Arduino.h>


SoftwareSerial mySerial(5,6);
Servo myServo;
int input = 0;
int inChar = 90;
int current = 90;
int waiter = 0;

void setup() {

Serial.begin(9600);
mySerial.begin(9600);
myServo.attach(9);

Serial.println("Arduino Ready!!");
}

void loop() {

waiter ++;

if (mySerial.available() > 0){

input = mySerial.read();

if (input != 0)
{
inChar = input;
}

//Serial.println(inChar);


}

delay(15);
//Serial.println("Set motor");
//Serial.println(inChar);
if (current < inChar)
{
if (waiter > 10){
current ++;
waiter = 0;
Serial.println(current);
}
}else if (current > inChar){

current--;
}
myServo.write(current);

Serial.println(current);

}

 

The android code was lengthy. Below is a view of inside android studio and youll see my constraint layout.

skateboard control android app

 

 

Following that is my two classes composing the skateboard controller.

 

<pre>public class MainActivity extends AppCompatActivity {

    String TAG = "MainActivity";
    TextView textViewSkateBoardInfo, textViewFeedback;
    EditText editTextInputToBoard;
    Button buttonSubmit, buttonBrake, buttonCoast, buttonCruise, buttonMinus, buttonPlus;
    Spinner spinnerDevices;
    SeekBar seekBarSpeed;

    int desiredSpeed = 0;


    String[] deviceNames;
    BluetoothAdapter bluetoothAdapter;
    ArrayAdapter<String> spinnerAdapter;
    int chosenDevice = 0;
    UUID MY_UUID;
    boolean threadControl = false;
    boolean bluetoothConnectionActive = false;
    Set<BluetoothDevice> pairedDevices;
    MyBlueToothService myBlueToothService;
     Handler mHandler;

    ConnectThread connectThread;

    //region----------------------------------------    Overrides & Permissions




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);


            setUpUI();

            checkPermissions();







    }



    private void checkPermissions()
    {
        String[] permissions = new String[] {

                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.BLUETOOTH,
                Manifest.permission.BLUETOOTH_ADMIN
        };


        ActivityCompat.requestPermissions(MainActivity.this, permissions, 10);


    }



    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);


        setupBlueTooth();

    }


    //endregion


    //region----------------------------------------    UI



    private void setUpUI()
    {
        MY_UUID = UUID.fromString("ca805ff2-39d8-47ca-a9a4-ca6227358943");
        textViewFeedback = findViewById(R.id.textview_FeedBack);
        textViewSkateBoardInfo = findViewById(R.id.textView_SkateBoard);
        editTextInputToBoard = findViewById(R.id.editText_InputToSkateBoard);
        buttonSubmit = findViewById(R.id.button_Submit);
        spinnerDevices = findViewById(R.id.spinner_Devices);
        buttonBrake = findViewById(R.id.button_Brake);
        seekBarSpeed = findViewById(R.id.seekBar_speed);
        buttonCoast = findViewById(R.id.button_Coast);
        buttonCruise = findViewById(R.id.button_Push);
        buttonMinus = findViewById(R.id.button_minusFive);
        buttonPlus = findViewById(R.id.button_plusFive);

        seekBarSpeed.setProgress(90);

        buttonSubmit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                buttonClick();
            }
        });

        buttonCoast.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                desiredSpeed = 98;
                seekBarSpeed.setProgress(98);
                sendSpeed(desiredSpeed);
                String s = "Speed set at " + String.valueOf(desiredSpeed);
                writeToInternal(s);

            }
        });

        buttonCruise.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                desiredSpeed = 105;
                seekBarSpeed.setProgress(105);
                sendSpeed(desiredSpeed);
                String s = "Speed set at " + String.valueOf(desiredSpeed);
                writeToInternal(s);

            }
        });

        buttonMinus.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                desiredSpeed = desiredSpeed -5;
                seekBarSpeed.setProgress(desiredSpeed);
                sendSpeed(desiredSpeed);
                String s = "Speed set at " + String.valueOf(desiredSpeed);
                writeToInternal(s);

            }
        });

        buttonPlus.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                desiredSpeed = desiredSpeed +5;
                seekBarSpeed.setProgress(desiredSpeed);
                sendSpeed(desiredSpeed);
                String s = "Speed set at " + String.valueOf(desiredSpeed);
                writeToInternal(s);

            }
        });




        seekBarSpeed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                desiredSpeed = i;

            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                sendSpeed(desiredSpeed);
                String s = "Speed set at " + String.valueOf(desiredSpeed);
                writeToInternal(s);
            }
        });


        buttonBrake.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                desiredSpeed = 90;
                seekBarSpeed.setProgress(90);
                sendSpeed(desiredSpeed);
                String s = "Speed set at " + String.valueOf(desiredSpeed);
                writeToInternal(s);

            }
        });



        mHandler = new  Handler(){

            @Override
            public void handleMessage(Message msg) {

                if (msg.what == 0){

                byte[] b = (byte[]) msg.obj;
                    // TODO: 5/12/2018 heres the response
                    String s = new String(b);

                    textViewFeedback.setText(s);

                }



            }
        };

    }




    private void buttonClick()
    {
        String s = editTextInputToBoard.getText().toString();

        if (!bluetoothConnectionActive ){
            runConnectThread();
            Log.d(TAG, "buttonClick: connecting");
        }else if(s.equals(""))
        {
            connectThread.cancel();
            myBlueToothService.cancel();
            Log.d(TAG, "buttonClick: dissconnecting");
            setupBlueTooth();
        }


            if (!s.equals(""))
            {
            sendString(s);
                Log.i(TAG, "buttonClick: sending ext input");
            }




    }

    public void writeToInternal(String input)
    {
        final String s = input;

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                textViewSkateBoardInfo.setText(s);

            }
        });



    }

    public void writeToBlueToothResponse(String input)
    {
        final String s = input;
        Log.d(TAG, "writeToBlueToothResponse: " + input);

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                textViewFeedback.setText(s);
            }
        });


    }


    public void sendString(String s)
    {
        try {
            byte[] bytes = s.getBytes("UTF-8");
            myBlueToothService.writeToDevice(bytes);
            writeToInternal(s);
        }catch (UnsupportedEncodingException e){
            Log.e(TAG, "sendString: ", e);
            writeToInternal("Failed to send");
        }

    }


    public void sendSpeed(int toSend)
    {


        byte[] b = ByteBuffer.allocate(4).putInt(toSend).array();

        if (bluetoothConnectionActive) {

            myBlueToothService.writeToDevice(b);

            Log.i(TAG, "sendSpeed: sending...");
        }
    }


    //endregion


    //region----------------------------------------    Bluetooth

    private void setupBlueTooth()
    {


        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter == null){
            Toast.makeText(this, "device doesnt support bluetooth", Toast.LENGTH_SHORT).show();
        }

        if (!bluetoothAdapter.isEnabled()){
            Intent enableBTIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBTIntent, 20);
        }

        pairedDevices = bluetoothAdapter.getBondedDevices();


        if (pairedDevices.size() > 0){
            deviceNames = new String[pairedDevices.size()];


            int tick = 0;
            for (BluetoothDevice device :
                    pairedDevices) {

                deviceNames[tick] = device.getName();



                tick++;
            }

            spinnerAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, deviceNames);

            spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

            spinnerDevices.setAdapter(spinnerAdapter);

            spinnerDevices.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {

                    chosenDevice = i;

                }

                @Override
                public void onNothingSelected(AdapterView<?> adapterView) {

                }
            });

        }



    }



    public void runConnectThread()
    {
    BluetoothDevice deviceToInsert = null;

    for (BluetoothDevice d :
            pairedDevices) {
        if (d.getName().equals(deviceNames[chosenDevice])){
            deviceToInsert = d;
        }
    }
    Log.i(TAG, "runConnectThread: try to connect");

   connectThread = new ConnectThread(deviceToInsert);
    connectThread.begin();

}


    private class ConnectThread implements Runnable
    {
    private  BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;
    Thread thread;


    public ConnectThread(BluetoothDevice device)
    {
        if (device == null){
            Toast.makeText(MainActivity.this, "BT Device Null", Toast.LENGTH_SHORT).show();
        }

        BluetoothSocket tmp = null;

        mmDevice = device;


        try{

            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        }catch (Exception e){
            Log.e(TAG, "ConnectThread: ",e );
        }


        mmSocket = tmp;

    }




    @Override
    public void run() {

        bluetoothAdapter.cancelDiscovery();

        try {
            mmSocket = (BluetoothSocket) mmDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(mmDevice, 1);
            mmSocket.connect();

        }catch (Exception e){
            Log.e(TAG, "run: ", e);
            writeToInternal( "failed connection to " + deviceNames[chosenDevice]);

                try {

                    mmSocket.close();
                }catch (Exception e2){
                    Log.e(TAG, "run: ", e2);
                }
                return;



        }

            writeToInternal( "connected to " + deviceNames[chosenDevice]);
            //do something with mmSOcket here
            myBlueToothService = new MyBlueToothService(mmSocket);
            Log.i(TAG, "Connection Success");
            bluetoothConnectionActive = true;
            passSTart();


    }




    public void begin()
    {
        thread = new Thread(this);
        threadControl = true;
        thread.start();
    }


    public void cancel()
    {
        bluetoothConnectionActive = false;
        threadControl = false;
        try {
            mmSocket.close();
        }catch (Exception e){
            Log.e(TAG, "cancel: ", e);
        }

    }


}

    public void passSTart()
    {
        myBlueToothService.passMain(this);
    }




    //endregion



    //region----------------------------------------    lifecycle

    @Override
    protected void onDestroy() {
        super.onDestroy();
        myBlueToothService.cancel();

    }


    //endregion


}</pre>

 

</pre>
<pre>    private interface MessageConstants {
        public static final int MESSAGE_READ = 0;
        public static final int MESSAGE_WRITE = 1;
        public static final int MESSAGE_TOAST = 2;


    }


    public  MyBlueToothService(BluetoothSocket socket)
    {
        connectedThread = new ConnectedThread(socket);
        connectedThread.startListeneing();


    }


    public void writeToDevice(byte[] b)
    {
        connectedThread.write(b);
    }


    public void cancel()
    {
        connectedThread.cancel();
    }

    public void passMain(MainActivity a)
    {
        connectedThread.setMainActivity(a);
    }



    private class ConnectedThread implements Runnable
    {
        Thread thread;
        MainActivity mainActivity;

        private final BluetoothSocket mmSocket;
        private  DataInputStream mmInputStream;
        private DataOutputStream mmOutputStream;
        private byte[] mmBuffer;

        public ConnectedThread(BluetoothSocket socket){

            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;


            try
            {
              tmpIn = socket.getInputStream();
                Log.i(TAG, "ConnectedThread: input stream success");
            }catch (Exception e){
                Log.e(TAG, "ConnectedThread: failed", e);
            }
            try
            {
              tmpOut = socket.getOutputStream();
                Log.i(TAG, "ConnectedThread: output stream success");
            }catch (Exception e){
                Log.e(TAG, "ConnectedThread: failed", e);
            }

            mmInputStream = new DataInputStream(tmpIn);

            mmOutputStream = new DataOutputStream(tmpOut);





        }


        public void run()
        {
            mmBuffer = new byte[1024];
            int numbytes = 0;


            while (threadBool)
            {
                try
                {
                  numbytes = mmInputStream.read(mmBuffer);
                    //Log.i(TAG, "mybluetooth read bufer bypassed");

                    if (numbytes > 0){
                        //Log.d(TAG, "read numbytes > 0");

                        String s = new String(mmBuffer, "UTF-8");
                        mainActivity.writeToBlueToothResponse(s);

                    }

                }catch (Exception e){
                    Log.e(TAG, "run: ", e);
                    break;
                }



            }




        }





        public void write(byte[] bytes)
        {
            byteHolder = bytes;

            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {

                            WriteToBT();

                }
            });
            t.start();

        }





        private void WriteToBT()
        {
            //Log.d(TAG, "WriteToBT: " + String.valueOf(byteHolder.length));


            try{
                mmOutputStream.write(byteHolder);
                //Log.i(TAG, "WriteToBT: passed");
                int i = new BigInteger(byteHolder).intValue();
                //Log.d(TAG, "WriteToBT: " + String.valueOf(i));

            }catch (Exception e){
                Log.e(TAG, "write: ", e);

            }
        }



        public void startListeneing()
        {threadBool = true;
        thread = new Thread(this);

        thread.start();

        }



        public void cancel()
        {
            threadBool = false;
            try{
                mmSocket.close();
            }catch (Exception e){
                Log.e(TAG, "cancel: ", e);
            }


        }



        public void setMainActivity(MainActivity a)
        {
            mainActivity = a;
        }



    }



}</pre>
<pre>

and that’s it!
 

Leave a comment

Your email address will not be published. Required fields are marked *