1.15pm Make your own cloud-based app: simple feedback for players

Make your own cloud-based app: simple remote monitoring of
athletes
Adam Kerr & Iain Spears
Middlesbrough FC
Teesside University
Chairs:
Greg Atkinson
Jonathan Madden
Make your own cloud-based app: simple feedback for athletes
Adam Kerr & Iain Spears
Middlesbrough FC
Teesside University
Chairs:
Greg Atkinson
Jonathan Madden
Our Backgrounds
• Adam
• 9 years experience in Elite Sport Physical Preparation
• Responsible for 1st Team fitness at Middlesbrough FC
• Iain Spears.
• Specialism in computational biomechanics.
• Programming in Fortran, C++ and then C#.
• Last 5-6 years spent much time working with gaming technology.
Rationale : Practitioner’s perspective
• Routine collection of GPS data during
training sessions
• 20 hrs missed recovery time
• Some scientific evidence for
recommendations
• How to get immediate feedback to
the players
• Excel or Progamming
• Email, Facebook, Web site, Apps
Making apps the easy way (Unity3D)
• Apple’s App Store (and later Google Play etc) have revolutionised the
gaming industry
• Led to the increased availability of easy-to-use tools for creating
mobile technology.
• Basic programming in C#
• Floats, arrays, bools, ints
• Unity3D
• Free !
Data flow using cloud-based technology (local storage approach)
Data
Uploading the .csv files
Step 1
App
Server (£25 per annum)
Domainname: www.sportsdata.org.uk
FTP Address: ftp.sportsdata.org.uk
Password: EDP6gx*****
Step 3
Feeding Back
Step 2
Downloading, parsing
and merging the .csv files
Step 1: Uploading the .csv files (AdamsUploader.exe)
void aaUploadCurrentFTPFile(string fName)
{
string Password
= "EDP6gx****";
string Username
= "sportsdavz";
string LocalFileName
= fName;
string ServerFileName
= "ftp://ftp.cluster007.ovh.net/www/data/footballConference/" + fName;
FileInfo toUpload
= new FileInfo(LocalFileName);
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ServerFileName);
request.Method
= WebRequestMethods.Ftp.UploadFile;
request.Credentials
= new NetworkCredential(Username, Password);
Stream ftpStream
= request.GetRequestStream();
FileStream file = File.OpenRead(LocalFileName);
int length
= 2056;
byte[] buffer = new byte[length];
int bytesRead = 0;
do
{
bytesRead = file.Read(buffer, 0, length);
ftpStream.Write(buffer, 0, bytesRead);
}
while (bytesRead != 0);
file.Close();
ftpStream.Close();
}
Step 1: Uploading the .csv files
static void Main(string[] args)
{
aaUploadCurrentFTPFile("gpsMaster.csv");
Console.WriteLine("Uploaded gpsMaster.csv");
Console.ReadLine();
aaUploadCurrentFTPFile("matchplay.csv");
Console.WriteLine("Uploaded matchplay.csv");
Console.ReadLine();
aaUploadCurrentFTPFile("anthrometrics.csv");
Console.WriteLine("Uploaded anthrometrics.csv");
Console.ReadLine();
}
Step 2: Downloading and parsing the .csv files
void aaParseFileGPS()
{
Global.stackCountGPS = 1;
for (int i = 0; i < Global.wLineCount; i++)
{
int p = 0;
parts = Global.lineString[i].Split(',');
Global.sessionCode[Global.stackCountGPS] = parts[p++];
Global.date[Global.stackCountGPS]
= parts[p++];
Global.week[Global.stackCountGPS]
= parts[p++];
etc,etc , etc
Global.pl[Global.stackCountGPS]
= parts[p++];
Global.plpermin[Global.stackCountGPS]
= parts[p++];
Global.plperslow[Global.stackCountGPS]
= parts[p++];
Global.stackCountGPS++;
}
}
Step 2: Merging the 3 .csv files
void aaReadInNewPlayer()
{
for (int i = 2; i < Global.stackCountAnthro; i++ )
{
if (Global.playerName[stackCurrent] == Global.playerNameAnthro[i])
{
currentBF = Global.currentBodyFatAnthro_p1[i];
currentBFTarget = Global.targetBodyFatAnthro_p1[i];
currentBFError = Global.currentBodyFatAnthroError_p1[i];
currentDist = Global.gpsVar[0, stackCurrent];
}
}
for (int i = 2; i < Global.stackCountMatch; i++)
{
if (Global.playerName[stackCurrent] == Global.playerNameMatch[i])
{
currentPlayer = Global.playerNameMatch[i];
currentPlayed = Global.played_p1[i];
currentWillPlay= Global.willPlay_p1[i];
currentDaySinceLastGame = (int)Global.dateSinceLastGame_p1[i].TotalDays;
}
}
}
Step 3: Feeding Back
bool carb = protein = compression = false;
if (currentBFError < 0 && currentDist > 3500)
{
carb = true;
protein = false;
}
if (currentBFError > 10 && currentDist > 3500 && currentDist < 5000)
{
carb = false;
protein = true;
}
if (currentDist > 5000)
{
carb = true;
protein = false;
}
if (currentDaySinceLastGame == 1 && currentPlayed > 15 && currentWillPlay == 1)
{
compression = true;
}
Step 3: Feeding Back (compression garment)
float dy = 1f*Mathf.Sin(Time.realtimeSinceStartup*10f);
currentFeedback = "Hi " + currentPlayer + "," ;
if (compression)
{
currentFeedback += "\r\n" + "Please wear your compression garment to aid recovery";
planes[0].position = new Vector3(vComp.x, vComp.y + dy, vComp.z);
planes[1].position = new Vector3(vComp.x, vComp.y, vComp.z);
planes[0].localScale = new Vector3(Global.rfactor * bigr, Global.rfactor * bigr, Global.rfactor * bigr);
planes[1].localScale = new Vector3(Global.rfactor * littler, Global.rfactor * littler, Global.rfactor * littler);
}
else
{
planes[1].localScale = new Vector3(Global.rfactor * bigr, Global.rfactor * bigr, Global.rfactor * bigr);
planes[0].localScale = new Vector3(Global.rfactor * littler, Global.rfactor * littler, Global.rfactor * littler);
}
currentFeedback += "\r\n" + "Thanks" + "\r\n" + "Adam";
textMessage.text = currentFeedback;
Player Feedback (for discussion)
 What information should we feed back to players?
 What evidence can we find to justify the specific details
of feedback ?
 What should we do if the evidence is not there ?
 How best to deliver the feedback ?