samedi 9 avril 2016

Services dans le logiciel (Saas) dans le domaine de la réservation sportive

Les deux boites suivantes proposent à des organisateurs d'évènement (sportif ou non) de créer une page pour communiquer sur un évènement, et surtout de gérer les inscriptions et le paiement des participants. Le concept est facile à vendre, n'importe quel organisateur d'évènement dont le web n'est pas le métier sera intéressé par la délégation du paiement à un tier. En plus le business model d'un tel service est facile à imaginer puisqu'il suffit de percevoir un pourcentage sur les achats.

Je cite ces deux sites car je les ai utilisé personnellement pour participer à des courses d'obstacle.


https://www.weezevent.com
Basé à Dijon



https://www.sportintown.com/
Basé à Nantes

jeudi 24 mars 2016

Krak Skateboard


Je profite de la mise à jour de l’application Krak (excellent nom cela dit en passant) pour prendre des notes à son sujet. Déjà première remarque, elle est mise à jour ce qui indique que le projet est toujours en cours.

Par Krak Skateboarding Inc. Créé par des Français Kevin Straszburger et Maxime Cattet (ancien de l’ EPITA). Basée à Log Angeles. Quelques investisseurs probablement type business angel.

Plusieurs services proposés, entièrement centrés sur le skateboard.

-        une application
-        un magazine en ligne
-        un abonnement à un sac cadeau et à un magazine papier
-        un capteur à venir ?


L’application est disponible sur iOS et Android. Partage de photos, vidéos, spots, réseau social. Design et interface soignée. Une des applications de skate les plus abouties. C’est propre et sérieux.
On ne sait pas toujours où l’on peut cliquer par contre. Malheureusement boguée et serveurs complètement indisponibles parfois.
Elle soufre du manque de médiatisation et donc du peu de trafic et d’utilisateurs. Seulement deux spots dans la région de Nantes.  

Un magazine en ligne et en papier ! Le magazine en ligne est plus une présentation web du contenu déjà disponible dans l’app. S’ajoute à ça quelques articles et interviews assez complets. J’imagine qu’on les retrouve dans le magazine papier. Je suppose que le magazine est destiné à générer du trafic et à maintenir un intérêt pour la marque. Au moins on sent qu’il y a quelqu’un derrière et que la société est en activité. Pas sûr que le retour sur investissement en terme de trafic récolté soit très élevé pour autant.

Un abonnement à un sac cadeau ?! C’à a le mérite d’être une offre très différente des concurrents. Peut présenter un intérêt pour un public d’ados et pré ados. Ça rappelle les clubs de Musclor et autres clubs de Barbie. Pas sûr que ce jeune public se retrouve encore dans le concept du magazine physique cela dit. Peut-être une bonne idée comme achat ponctuel pour faire un cadeau à un skateur.

La société travaillerait sur un traqueur connecté, du moins c’est que le profil d’entreprise annonce. Cet article de2014 confirme l’objectif. J’avais cru voir un communiqué indiquant qu’ils faisaient alliance avec une autre boîte californienne pour le développement hardware (Trace il me semble ?) mais je ne retrouve plus rien à ce sujet. Pour autant ; étant donné les compétences évidentes de l’équipe en développement mobile, en marketing et en communication, je ne crois pas du tout à l’arrivée d’un traqueur. C’est trop différent de se qu’ils font actuellement et qui doit déjà les occuper grandement. Avec un partenariat peut-être …

Pour conclure les trois services déjà proposés sont tous de bonne facture et réalisés sérieusement. Je m’interroge cependant sur tant de diversification pour une société qui j’imagine n’a pas encore rencontré le succès. Ils ont l’avantage d’avoir une source de revenue potentielle par le sac cadeau. Comme pour toutes les applications du même genre ils se heurtent à la difficulté d’amorcer un effet de masse et une communauté.


jeudi 18 février 2016

Le podcast des entrepreneurs par Antonella Viland

Excellent podcast sur la création d'entreprise que je viens de découvrir. Il est rattaché au site http://macreationdentreprise.fr/. Je n'ai écouté que les premiers épisodes pour le moment, mais on sent tout de suite qu'Antonella sait de quoi elle parle. On est loin des discours théoriques et poussiéreux de professeurs et autres conseillers qui ne survivraient pas 15 jours s'ils tentaient l'aventure. La création d'entreprise c'est avant tout une question de mentalité, d'esprit de liberté, de pragmatisme et de confiance en soi. Il y a les gens qui réfléchissent, planifient, se documentent ... et il a y ceux qui produisent vraiment quelque chose de concret.


jeudi 24 décembre 2015

Notes sur la Sensor Fusion Demo d'Alexander Pacha

Cette très intéressante démo présente les différences de stabilité obtenues selon la source utilisé pour déterminer la position d'un téléphone.

Tous les capteurs du SDK d'android renvoient leurs données dans le système de coordonnées mondial dit main droite:

Axis globe
Dans ce système de coordonnées une rotation positive:

- selon l'axe X fait pointer le haut du téléphone vers le bas.
- selon l'axe Y fait pencher le téléphone à droite(sens inverse des aiguilles d'une montre)
- selon l'axe Z fait tourner le téléphone vers la droite.

Le code montre l'utilisation de getRotationMatrixFromVector et getQuaternionFromVector
SensorManager.getRotationMatrixFromVector(currentOrientationRotationMatrix.matrix, event.values);
// Calculate angle. Starting with API_18, Android will provide this value as event.values[3], but if not, we have to calculate it manually.
SensorManager.getQuaternionFromVector(q, event.values);
currentOrientationQuaternion.setXYZW(q[1], q[2], q[3], -q[0]);
Déjà comme le commentaire l'indique si l'on code pour une API supérieure à 18 on peut oublier l'appel à getQuaternionFromVector puisque event.values contiendra déjà les quatre réels (x,y,z,w) nécessaires à l'initialisation d'un quaternion.

De plus la matrice de rotation n'est pas utilisée plus tard donc on peut supprimer cet appel également et n'avoir que:
currentOrientationQuaternion.setXYZW(event.values[0], event.values[1], event.values[2], -event.values[3]); PS: je ne comprends pas la nécessité d'utiliser le négatif de event.values[3]
Dans la fonction getEulerAngles qui renvoient la position du téléphone sous la forme de trois angles d'Euler, on peut également supprimer la matrice de rotation et passer directement via le quaternion:
SensorManager.getOrientation(currentOrientationQuaternion.getMatrix4x4().matrix, angles); Lorsque l'on veut réaliser l'affichage du cube en OpenGL on va presque directement passer ces valeurs à la fonction glRotatef que l'on applique sur la matrice MODELVIEW. Quaternion q = orientationProvider.getQuaternion();
gl.glRotatef((float) (2.0f * Math.acos(q.getW()) * 180.0f / Math.PI), q.getX(), q.getY(), q.getZ());
Ceci est possible car glRotatef appliquée à MODELVIEW interprète les rotations à l'inverse du système de coordonnées de l'orientation du téléphone. Ainsi dans ce système:

gl.glRotatef(15, 1, 0, 0) fait pointer le téléphone vers le haut
gl.glRotatef(15, 0, 1, 0) fait pencher le télépone vers la droite (rotation dans le sens des aiguilles)
gl.glRotatef(15, 0, 0, 1) fait tourner le téléphone vers la gauche

La seule adaptation nécessaire au système de coordonnées opengl est la transformation du demi angle de rotation (en radian) stocké par le quaternion en un angle complet en degré: theta_deg = ((2 *half_theta_rad) * 180 / M_PI)
https://play.google.com/store/apps/details?id=org.hitlabnz.sensor_fusion_demo

vendredi 18 décembre 2015

Utiliser le Gesture Recognition Toolkit (GRT) sur Android via JNI

Une fois GRT compilé pour Android la partie la plus complexe consiste à utiliser SWIG afin de générer automatiquement l'interface JNI pour appeler le C++ via Java. Cette page est une traduction et adaptation de ce billet qui m'a fait découvrir SWIG. La procédure à suivre est la suivante:
Commencer par créer le répertoire qui accueillera les fichiers JNI générés par SWIG.
mkdir -p ./GRTApp/app/src/main/java/org/swig/grt/ Ensuite on va avoir besoin du fichier grt.i ci dessous qui définit comment SWIG doit écrire les interfaces C++. C'est la première fois que j'utilise SWIG et trouver la syntaxe pour les opérateurs C++ surchargés n'a pas été simple.
%module grt

%{
#include "GRT.h"
using namespace GRT;
%}

%inline %{
typedef unsigned int UINT;
%}

%rename(assign) GRT::IndexDist::operator=;
%rename(assign) GRT::DTW::operator=;

%include
%include "my_vector.i"
%template(VectorDouble) std::vector;
%include "grt/Util/GRTTypedefs.h"

%include "grt/Util/Matrix.h"
%rename(assign) GRT::MatrixDouble::operator=;
%include "grt/Util/MatrixDouble.h"

%rename(assign) GRT::TimeSeriesClassificationSample::operator=;
%rename(get) GRT::TimeSeriesClassificationSample::operator[];
%include "grt/DataStructures/TimeSeriesClassificationSample.h"

%rename(assign) GRT::TimeSeriesClassificationData::operator=;
%rename(get) GRT::TimeSeriesClassificationData::operator[];
%include "grt/DataStructures/TimeSeriesClassificationData.h"

%rename(assign) GRT::TimeSeriesClassificationDataStream::operator=;
%rename(get) GRT::TimeSeriesClassificationDataStream::operator[];
%include "grt/DataStructures/TimeSeriesClassificationDataStream.h"

%include "grt/CoreModules/Classifier.h"
%include "grt/ClassificationModules/DTW/DTW.h"
Ensuite on lance la commande qui va générer jni/grt_wrap.cpp et tout un tas de fichiers d'interfaces dans org/swig/grt
swig -c++ -java -package org.swig.grt -outdir ../java/org/swig/grt/ -o grt_wrap.cpp grt.i Reste à compiler le tout avec:
Compiler avec ndk-build NDK_LIBS_OUT=../jniLibs On peut ensuite réaliser en java un clone du code d'example de l'algorithme DTW de la page suivante: Voici le code java équivalent.
DTW dtw = new DTW();

TimeSeriesClassificationData trainingData = new TimeSeriesClassificationData();

if(!trainingData.loadDatasetFromFile("/data/data/com.codeflakes.grtapp/files/dtwtrainingdata_grt")) {
    Log.e(TAG, "Failed to load training data!");
}

Log.d(TAG, trainingData.getStatsAsString());

TimeSeriesClassificationData testData = trainingData.partition(80);
dtw.enableTrimTrainingData(true, 0.1, 90);

//Train the classifier
if( !dtw.train_( trainingData ) ){
     Log.e(TAG, "Failed to train classifier!");
}

//Use the test dataset to test the DTW model
double accuracy = 0;
for(int i=0; i<testData.getNumSamples(); i++){
    //Get the i'th test sample - this is a timeseries
    long classLabel = testData.get(i).getClassLabel();
    MatrixDouble timeseries = testData.get(i).getData();
    //Log.d(TAG, "" + classLabel + " " + testData.get(i).getLength() + " " + testData.get(i).getNumDimensions());

    //Perform a prediction using the classifier
    if (!dtw.predict_( timeseries ) ){
        Log.e(TAG, "Failed to perform prediction for test sample: " + i);
    }

    //Get the predicted class label
    long predictedClassLabel = dtw.getPredictedClassLabel();
    double maximumLikelihood = dtw.getMaximumLikelihood();
    VectorDouble classLikelihoods = dtw.getClassLikelihoods();
    VectorDouble classDistances = dtw.getClassDistances();

    //Update the accuracy
    if( classLabel == predictedClassLabel ) accuracy++;

    Log.d(TAG, "TestSample: " + i + "\tClassLabel: " + classLabel + "\tPredictedClassLabel: " + predictedClassLabel + "\tMaximumLikelihood: " + maximumLikelihood);
}

Log.d(TAG, "Test Accuracy: " + (accuracy/(testData.getNumSamples())*100.0) + "%");

mercredi 16 décembre 2015

Compilation du Gesture Recognition Toolkit sur Android

Pour ne pas avoir à développer la partie reconnaissance de mouvement j'ai recherché des bibliothèques existantes. Mon choix s'est porté sur le GRT (Gesture Recognition Toolkit) de Nick Gillian.

Pour le faire fonctionner sur Android je me suis basé sur cet article http://hollyhook.de/wp/grt-for-android

Le but est de compiler le code C++ en une bibliothèque libgrt.so que l'on intégrera dans notre APK et que l'on utilisera via JNI.

Le processus pour compiler le GRT en NDK est le suivant:

- Créer un projet vierge sous Android Studio.
- Spécifier le répertoire dans lequel on va placer le fichier .so et désactiver la compilation du NDK en ajoutant dans gradle:
sourceSets {
     main {
         jniLibs.srcDir 'jniLibs' // spécification du répertoire de libs JNI
         jni.srcDirs = [] // désactivation compilation NDK
     }
}

Copier ensuite (un lien sympbolique marche aussi) le code source du GRT dans GRTApp/app/src/main/jni. La structure de l'application est la suivante:
GRTApp
app
     build
     libs
     src
         main
             java
                 com/codeflakes/grtapp
                 org/swig/grt
             jni
                 grt
             jniLibs
             libs
                 armeabi-v7a
             res
         test
         androidTest
build
gradle
Ajouter les Android.mk et Application.mk suivants dans ./jni pour pouvoir compiler avec ndk-build

Application.mk: NDK_TOOLCHAIN_VERSION := clang
APP_STL := gnustl_static
APP_CPPFLAGS += -frtti
APP_CPPFLAGS += -fexceptions
APP_ABI := armeabi-v7a
Android.mk:
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

$(info $(LOCAL_PATH))

HEADER_FILES_LIST := $(wildcard $(LOCAL_PATH)/grt/*.h)
HEADER_FILES_LIST += $(wildcard $(LOCAL_PATH)/grt/*/*.h)
HEADER_FILES_LIST += $(wildcard $(LOCAL_PATH)/grt/*/*/*.h)
HEADER_FILES_LIST += $(wildcard $(LOCAL_PATH)/grt/*/*/*/*.h)
HEADER_FILES_LIST += $(wildcard $(LOCAL_PATH)/grt/*/*/*/*/*.h)
#$(info $(HEADER_FILES_LIST))
LOCAL_C_INCLUDES := $(HEADER_FILES_LIST:$(LOCAL_PATH)/%=%)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/grt/

LOCAL_MODULE    := grt

SRC_FILES_LIST := $(wildcard $(LOCAL_PATH)/grt/*.cpp)
SRC_FILES_LIST += $(wildcard $(LOCAL_PATH)/grt/*/*.cpp)
SRC_FILES_LIST += $(wildcard $(LOCAL_PATH)/grt/*/*/*.cpp)
SRC_FILES_LIST += $(wildcard $(LOCAL_PATH)/grt/*/*/*/*.cpp)
SRC_FILES_LIST += $(wildcard $(LOCAL_PATH)/grt/*/*/*/*/*.cpp)
#$(info $(SRC_FILES_LIST))
LOCAL_SRC_FILES := $(SRC_FILES_LIST:$(LOCAL_PATH)/%=%)
LOCAL_SRC_FILES += $(LOCAL_PATH)/grt_wrap.cpp

LOCAL_CPPFLAGS += -std=c++11
LOCAL_LDLIBS   += -latomic
LOCAL_LDLIBS   += -llog

include $(BUILD_SHARED_LIBRARY) 
Premier post. Je vais essayer de documenter mes recherches et mon travail sur le développement d'un traqueur sportif. J'y consignerai du code et de la technique, mais aussi des infos sur les concurrents, le marché et le business model d'un tel produit.