Darren Herbst
Created June 23, 2017

Smart Pickleball Paddle

A Smart Pickleball Paddle that will help you improve your game and promote healthy and fun excercise!

69
Smart Pickleball Paddle

Things used in this project

Hardware components

PickleBall Paddle
×1
Android device
Android device
×1
Electrical Tape
×1
Infineon Sensor Hub Nano
Infineon Sensor Hub Nano
×1

Software apps and online services

Android Studio
Android Studio
My app is in the code section of the project.

Story

Read more

Custom parts and enclosures

Custom Enclosure For Sensor

Using the packaging that the sensor came in, cut it down and create a little box that holds the sensor hub.

Code

Main Activity Code in Android Studio

Java
This is the code for the main activity. It handles the Bluetooth connection, data collection, and graphs. You may want to be sure your package is updated to reflect the package you are using.
package pickleballsmarts.smartpaddle;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.graphics.Color;
import android.graphics.EmbossMaskFilter;
import android.graphics.Paint;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.androidplot.pie.PieChart;
import com.androidplot.pie.PieRenderer;
import com.androidplot.pie.Segment;
import com.androidplot.pie.SegmentFormatter;
import com.androidplot.util.PixelUtils;
import com.infineon.sen.comm.Model.Mode;
import com.infineon.sen.comm.Model.Sensor;
import com.infineon.sen.comm.SensorEvent;
import com.infineon.sen.comm.SensorHub;
import com.infineon.sen.comm.SensorHubListener;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.ValueDependentColor;
import com.jjoe64.graphview.series.BarGraphSeries;
import com.jjoe64.graphview.series.DataPoint;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;

public class MainActivity extends AppCompatActivity {


    BluetoothAdapter mBtAdapter;
    List<BluetoothDevice> pairedDevices;
    SensorHub mSensorHub;
    String TAG = "SENSORHUB";
    GraphView graph;

    Button btnStart;
    Button btnStop;
    Button btnPauseResume;

    boolean collectData = false;
    boolean drawGraph = false;
    boolean graphed = false;
    boolean useDebugData = false;

    TreeMap tree = new TreeMap();

    // Pie Chart
    public PieChart pie;
    private Segment upper;
    private Segment middle;
    private Segment lower;
    int numberOfSegments = 5;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        btnStart = (Button) findViewById(R.id.btnStart);
        btnStop = (Button) findViewById(R.id.btnStop);
        btnPauseResume = (Button) findViewById(R.id.btnPauseResume);
        pie = (PieChart) findViewById(R.id.pieChart);

        pie.getLegend().setVisible(false);
        pie.getBorderPaint().setColor(Color.TRANSPARENT);
        pie.getBackgroundPaint().setColor(Color.TRANSPARENT);


        final float padding = PixelUtils.dpToPix(30);



        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "Starting to Collect Data");
                collectData = true;
                tree.clear();
                pie.clear();
            }
        });
        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "Collect Data Stopped");
                collectData = false;
                drawGraph = true;
            }
        });
        btnPauseResume.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "Pause/Resume");
                if(collectData) {
                    collectData = false;
                    btnPauseResume.setText("Resume");
                }
                else if (!collectData) {
                    collectData = true;
                    btnPauseResume.setText("Pause");
                }
            }
        });



//series.setValuesOnTopSize(50);

        mBtAdapter = BluetoothAdapter.getDefaultAdapter();

        Set<BluetoothDevice> allPairedDevices = mBtAdapter.getBondedDevices();

        pairedDevices = new ArrayList<BluetoothDevice>();
        for (BluetoothDevice d : allPairedDevices) {
            if(isIfxDevice (d))
                pairedDevices.add(d);
        }

        mSensorHub = new SensorHub(this, pairedDevices.get(0).getAddress());
        mSensorHub.addSensorHubListener(new SensorHubListener() {
            @Override
            public void onConnected(SensorHub sensorHub) {
                Log.d(TAG, "Connected");
                setMode(null, null);
                mSensorHub.start();
            }

            @Override
            public void onDisconnected(SensorHub sensorHub) {
                Log.d(TAG, "Disconnected");
            }

            @Override
            public void onConnectionError(SensorHub sensorHub) {
                Log.d(TAG, "Connection Error");
            }

            @Override
            public void onSensorDataReceived(SensorHub sensorHub, SensorEvent sensorEvent) {
                // Log.d(TAG, sensorEvent.getTimestamp() + ":" + sensorEvent.getDataId() + ":" + sensorEvent.getSensorValue());
                if((sensorEvent.getDataId().equalsIgnoreCase("a")) && collectData) {
                    Log.d(TAG, sensorEvent.getTimestamp() + ":" + sensorEvent.getDataId() + ":" + sensorEvent.getSensorValue());
                    double sensorValue = sensorEvent.getSensorValue();
                    String key = String.format("%.4f", sensorValue);
//                    String key = Double.toString((int) sensorValue);
                    if (tree.containsKey(key)) {
                        tree.put(key, (int)tree.get(key) + 1);
                    }
                    else {
                        tree.put(key, 1);

                    }
                }

                else if (drawGraph) {
                    Log.d(TAG, "Tree size = " + tree.size());
//                    iterateOverMap(tree);
                    if (tree.size() > 0) {

                    }
                    else {
                        Toast.makeText(getApplicationContext(), "No Data Available", Toast.LENGTH_LONG).show();
                    }
                        generateDataForGraph(tree);
                    graphed = true;
                    drawGraph = false;
                }

//                Log.d(TAG, "" + collectData + graphed);
            }

            @Override
            public void onModeChanged(SensorHub sensorHub, Mode mode) {
                Log.d(TAG, mode.getSensorId() + ":" + mode.getModeId() + ":" + mode.getValue());
            }
        });
        mSensorHub.connect();
    }

    private boolean isIfxDevice(BluetoothDevice device) {

        String deviceName = device.getName().toLowerCase();
        if(deviceName.equals("ifx_nanohub"))
            return true;
        return false;
    }

    public void setMode(String sid, Mode mode) {
        if(mSensorHub.getSensorList().size() == 0) {
            Log.d(TAG, "Error: no sensor detecte");
            return;
        }

        Sensor sensor = mSensorHub.getSensorList().get(0);
        Log.d(TAG, "Setting Mode " + sensor.getId());
        // need to set the mode here - study what modes and descriptions are first
        mSensorHub.setMode(sensor.getId(), new Mode("mode", "bg"));
        mSensorHub.setMode(sensor.getId(), new Mode("prs_mr", "32"));
        mSensorHub.setMode(sensor.getId(), new Mode("prs_osr", "128"));
        mSensorHub.setMode(sensor.getId(), new Mode("temp_mr", "32"));
        mSensorHub.setMode(sensor.getId(), new Mode("temp_osr", "128"));

    }
    private void iterateOverMap(Map<String, Integer> map) {
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            Log.d(TAG, entry.getKey() + ":" + entry.getValue());
        }
    }
    private void generateDataForGraph(Map<String, Integer> map) {

        double keys[] = new double[numberOfSegments];


        double lowestKey = 0;
        double highestKey = 0;

        double increment = (highestKey - lowestKey)/numberOfSegments;
        Log.d(TAG, "Increment = " + increment);
        int mind = 25;
        int maxd = 100;

        Random r = new Random();

        if (useDebugData) {
            keys[0] = r.nextInt(maxd - mind + 1) + mind;
            keys[1] = r.nextInt(maxd - mind + 1) + mind;
            keys[2] = r.nextInt(maxd - mind + 1) + mind;
            keys[3] = r.nextInt(maxd - mind + 1) + mind;
            keys[4] = r.nextInt(maxd - mind + 1) + mind;
        }
        else {
            lowestKey = Double.valueOf((String)tree.firstKey());
            highestKey = Double.valueOf((String)tree.lastKey());
            increment = (highestKey - lowestKey)/numberOfSegments;
        }
        while (tree.size() > 0 && !useDebugData) {
            Map.Entry e = tree.pollFirstEntry();
            Log.d(TAG, "Polled Entry " + (tree.size() + 1) + " times.");

            for (int j = 0; j < numberOfSegments; j++) {
                if(((lowestKey + increment * j) <=  Double.valueOf((String)e.getKey())) && (Double.valueOf((String)e.getKey()) <= (lowestKey + increment * (j+1)))) {
                    keys[j] += 1;
                }
            }
        }

        Log.d(TAG, "Length of Keys[] " + keys.length);

        int max = 0;
        for(int i = 0; i < keys.length; i++) {
            Log.d(TAG, "Keys[] : " + keys[i]);
            max = Math.max(max, (int)keys[i]);
        }

        EmbossMaskFilter emf = new EmbossMaskFilter(
                new float[]{1, 1, 1}, 0.4f, 10, 8.2f);
        SegmentFormatter sf = new SegmentFormatter(Color.RED);




        for (int i = keys.length - 1; i>=0; i--) {
            if (i == 4 || i == 0) {
                sf = new SegmentFormatter(getResources().getColor(R.color.edge));
            }
            else if (i == 3 || i == 1) {
                sf = new SegmentFormatter(getResources().getColor(R.color.middle));
            }
            else if (i == 2) {
                sf = new SegmentFormatter(getResources().getColor(R.color.center));
            }


            sf.getLabelMarkerPaint().setShadowLayer(3, 0, 0, Color.BLACK);
            sf.getFillPaint().setMaskFilter(emf);
//            sf.setOuterInset((float)(max * 50/keys[i]));
            sf.setOuterInset((float)(300-keys[i]/max*300));
            sf.setRadialInset(1);
            //sf.setInnerInset((float)(keys[i] * 5));
            Segment seg = new Segment("", 1);
            pie.addSegment(seg, sf);


        }



        pie.getRenderer(PieRenderer.class).setStartDegs(75);
        pie.getRenderer(PieRenderer.class).setExtentDegs(150);

        pie.redraw();
        Log.d(TAG, "Drew Pie");


    }
    private Integer getSegmentFormatterColor(double[] d, double value) {
        double color = Color.BLUE;
        int j = 0;
        for(int i = 0; i < d.length; i++) {
            if(value <= d[i]) {
                j++;
            }
        }
        switch (j) {
            case 0:
                return Color.BLUE;
            case 1:
                return Color.GREEN;
            case 2:
                return Color.CYAN;
            case 3:
                return Color.YELLOW;
            case 4:
                return Color.RED;
        }
        return (int)color;
    }
}

Android App XML File

XML
This is the layout file for the main activity. Mine is named activity_main.xml
Just add this to the res>>layout folder.
In the main activity ensure setContentView is set for this view. For example setContentView(R.layout.activity_main);
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/ap_charcoal"
    android:orientation="horizontal"
    tools:context="pickleballsmarts.smartpaddle.MainActivity">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="@color/ap_transparent"
        android:orientation="vertical"
        android:paddingTop="100dp">

        <TextView
            android:id="@+id/textView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Pickle Ball Time"
            android:textColor="@color/ap_white"
            android:textSize="36dp" />

        <Button
            android:id="@+id/btnStart"
            android:layout_width="match_parent"
            android:layout_height="71dp"
            android:elevation="0dp"
            android:text="Start"
            android:textSize="24sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/btnPauseResume"
            android:layout_width="match_parent"
            android:layout_height="71dp"
            android:text="Pause"
            android:textSize="24sp"
            android:textStyle="bold" />

        <Button
            android:id="@+id/btnStop"
            android:layout_width="match_parent"
            android:layout_height="71dp"
            android:text="Stop"
            android:textSize="24sp"
            android:textStyle="bold" />
    </LinearLayout>

    <RelativeLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:orientation="horizontal">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingBottom="75dp"
            android:paddingLeft="200dp"
            android:paddingTop="100dp"
            app:srcCompat="@drawable/human" />

        <com.androidplot.pie.PieChart
            android:id="@+id/pieChart"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"

            app:renderMode="use_background_thread" />
    </RelativeLayout>

</LinearLayout>

Credits

Darren Herbst

Darren Herbst

1 project • 3 followers
Degreed electrical engineer and worked at John Deere for 3 years. I moved back to the family ranch/farm to design agriculture IoT systems.

Comments