Poner un entrenador elíptico y pygame

Hola, amigos! Sucedió así que para recuperarse de una lesión, me compré un dispositivo de este tipo.



Con sus funciones, se las arregló bastante bien, pero no había un "pero", y consistía en el hecho de que el velocímetro estaba confundido en el testimonio, y por lo tanto muestran resultados diferentes en la distancia recorrida. Si usted va bastante lento, el indicador de velocidad en todo quedó en silencio. Y se decidió hacer su velocímetro con ... bueno, se entiende.


Cómo conectar un simulador de computadora y h4>
En primer lugar, en el que se decidió comenzar - encontrar una forma de obtener los datos en el ordenador. Intermediario, se decidió utilizar la tarjeta de Arduino ¿Por qué Arduino ? Porque usted no tiene ni nada adecuado.
En el examen se encontró que desde el simulador para el sensor tiene dos salidas.


Lo cual sería suficiente para conectarlo a las clavijas de Arduino dicho régimen

En contacto A0 , dependiendo de la posición de los pedales, la señal vendrá varios tamaños.
Durante los experimentos se han intentado muchas opciones de alarma desde el microcontrolador a la computadora, y finalmente se estableció en esta versión:
un equipo de colada continua de caracteres «0» y, a continuación, cuando un paso en el simulador, sirvió «1» «0» y así el círculo
. Aquí está boceto

 & lt; code class = & quot; cpp & quot; & gt; int pin = A0; int ledPin = 13; int minSignal = 600; bool stateUp = false; bool LastState = false; bool oneStep = false; void setup () {pinMode (pin, INPUT); pinMode (ledPin, OUTPUT); Serial.begin (9600); } Lazo vacío () {int = señal analogRead (pin); si (señal & gt; minSignal) {stateUp = true; } Else {stateUp = false; } Si (LastState = StateUp & amp;! & Amp; LastState == false) {oneStep = no oneStep; } Else {} LastState = stateUp; Serial.println (oneStep); digitalWrite (ledPin, oneStep); // LED} & lt; / Código & gt;  pre> 
  

Juego h4>
¿Qué más para escribir en la pygame si no juegas? I>

Idea h5>
El entrenador elíptico es una simulación de caminar sobre esquíes, por lo que será un esquiadores de carrera. Cada paso que se da en el simulador hace que el personaje en el juego. Primero quería hacer un carácter suave movimiento \ aceleración, pero al final decidió dar preferencia a la precisión.

Asentamientos h5>
Empíricamente, se ha encontrado que las circunstancias "óptimas", una vuelta completa equivale cuarta metros. Esto probablemente no es lo que una persona atraviesa, y cuánto se desplaza el disco central. Basta con aceptar este valor como un axioma.
En la pista virtual 1 metro es igual a 1 pixel. Es decir, cada paso del movimiento persnazha 4 píxeles por delante.
Velocidad calculará cada movimiento.
v = s / t
s = 4 m.
t - el tiempo de un solo paso.
* un paso - una vuelta completa de los pedales I>
.
Passion h5>
Sí, hay gráficos y un velocímetro con un temporizador, pero quiero que el espíritu de la competencia.
Pero lo que si no va a competir con alguien y con uno mismo, ayer ? Said - hecho.


Carácter superior hoy, inferior - ayer. Para ser más precisos - el carácter de la última carrera, pero hay que admitir que la primera opción suena más fresco
.

Detalles Técnicos h4>

base de datos h5>
Naturalmente, sólo tiene que mantener la información de las carreras, se necesita una base de datos. Decidí usar mysql python uso de la biblioteca MySQLdb DataManger Se aplica el esquema.


Código de ejemplo
 & lt; code class = & quot; python & quot; & gt; slass DataManager: def __init __ (self): self.time = tiempo self.currentTimeForLastRace = DateTime.Now () self.currentTime = self.time.time () self.speed = 0 self.db = MySQLdb.connect (host = & quot; localhost & quot;, user = & quot; raíz & quot;, passwd = & quot; raíz & quot;, db = & quot; skirunner & quot;, charset = 'utf8') self.cursor = self.db.cursor () self.isGetLastRaceSpeeds = False self.dataLastRace = [] = self.lastRaceMinDate DateTime.Now () self.value = 0 = 0 self.lastValue self.impulse = 0 self.isRaceStart = False self.currentRaceId = -1 self.currentDistanceId = -1 self.currentProfileId = -1 def getImpulse (auto, valor): self.impulse = 0 si self.time.time () - self.currentTime & gt; RESET_SPEED_TIME: self.speed = 0 self.value = valor si self.value = Self.lastValue: tiempo = self.time.time () - self.currentTime self.impulse = POWER_IMPULSE self.isRaceStart = True self.speed = PASO / hora # metros por segundo self.currentTime = self.time.time () self.lastValue = self.value volver self.impulse def getLastRaceDistanceAtCurrentTime (self, raceId, horaActual): lastRaceDistance = 0 dateFormat = & quot;% Y-% m -% d% H:% M:% S% f & quot; si no self.isGetLastRaceSpeeds: sql = & quot; & quot; & quot; min SELECT (fecha) DESDE DONDE runLog race_id =% s & quot; & quot; & quot; % RaceId self.cursor.execute (sql) datos = self.cursor.fetchall () para rec en datos: self.lastRaceMinDate = datetime.strptime (rec [0], dateFormat) sql = & quot; & quot; & quot; distancia SELECT, Fecha a partir de runLog DONDE ORDER BY fecha DESC & quot race_id =% s; & quot; & quot; Self.cursor.execute% RaceId (sql) self.dataLastRace = self.cursor.fetchall () self.isGetLastRaceSpeeds = True si self.isRaceStart: tiempo = DateTime.Now () - datetime.fromtimestamp (horaActual) para rec en el yo. dataLastRace: distancia, date = rec si el tiempo & lt; = (datetime.strptime (fecha, dateFormat) - self.lastRaceMinDate): lastRaceDistance = retorno distancia lastRaceDistance & lt; / código de & gt;  pre> 
  

Gráficos h5>
Como se puede ver en la imagen anterior, los gráficos primitivos, pero no nyashnost es lo principal. Su aplicación se ha utilizado la biblioteca pygame escribió.

Form h5>


Formularios utilizados para la biblioteca PyQt Código de ejemplo
 & lt; code class = & quot; python & quot; & gt; clase FormProfile (QMainWindow): def __init __ (self): super (QMainWindow, auto) .__ init __ () uic.loadUi (' % s / ui /% DIR frm_profile.ui, auto) self.cb_profile_load () self.te_newProfile.hide () self.bt_addProfile.hide () self.bt_cancel.hide () self.lb_add.hide () self.move (... QDesktopWidget () availableGeometry () Centro () - self.frameGeometry () Centro ()) self.connect (self.bt_ok, SEÑAL (& quot; se hace clic () & quot;), self.bt_ok_clicked) self.connect ( self.bt_new, SEÑAL (& quot; hace clic () & quot;), self.bt_new_clicked) self.connect (self.bt_addProfile, SEÑAL (& quot; hace clic en () & quot;), self.bt_addProfile_clicked) self.connect (self.bt_cancel, SEÑAL (& quot; hace clic en () & quot;), self.bt_cancel_clicked) self.connect (self.bt_graph, SEÑAL (& quot; se hace clic () & quot;), self.bt_graph_clicked) def bt_ok_clicked (self): self.profileId = auto. . cb_profile.itemData (self.cb_profile.currentIndex ()) toString () self.formDistance = FormDistance (self.profileId) self.formDistance.show () self.hide () & lt; / código de & gt;  pre> 
  
Me gustó mucho las ventanas del proceso de desarrollo. No más difícil que en el estudio MS Los formularios creados en el Qt 4 Creador Importarlos en código
 & lt; code class = & quot; python & quot; & gt; uic.loadUi ('/ ui / frm_profile.ui% s'% DIR, auto) & lt; / código de & gt;  pre> 
Eventos y métodos para
 & lt relacionados; code class = & quot; python & quot; & gt; self.connect (self.bt_ok, SEÑAL (& quot; se hace clic () & quot;), self.bt_ok_clicked) self.connect (self.bt_new, SEÑAL (& quot; hace clic () & quot;), self.bt_new_clicked) self.connect ( self.bt_addProfile, SEÑAL (& quot; hace clic () & quot;), self.bt_addProfile_clicked) self.connect (self.bt_cancel, SEÑAL (& quot; hace clic () & quot;), self.bt_cancel_clicked) self.connect (self.bt_graph, SEÑAL (& quot; hace clic () & quot;), self.bt_graph_clicked) & lt; / código de & gt;  pre> 
Y mostrar
 & lt; code class = & quot; python & quot; & gt; self.formProfile = FormProfile () self.formProfile.show () & lt; / código de & gt;  pre> 

Gráficos h5>


Trazando biblioteca se utiliza matplotlib.
Aquí, también, código de ejemplo
 & lt; code class = & quot; python & quot; & gt; matplotlib.pyplot importación como plt def bt_averageSpeed_clicked (self): ... plt.plot_date (fechas, valores, 'b ') plt.plot_date (fechas, los valores,' bo ') averageSpeed ​​= len (valores) & gt; 0 y (lambda: sum (valores) / len (valores)) o (lambda: 0) plt.xlabel (u & quot; de alta velocidad promedio =% .2f m / s o% .2f km / h & quot;% (float ( averageSpeed ​​()), float (averageSpeed ​​()) / 1000 * 3600)) plt.ylabel (u & quot; velocidad media (m / s) & quot;) plt.title (u & quot; El perfil de velocidad% s & quot;% dm.getProfileNameById ( self.profileId)) plt.gca (). xaxis.set_major_formatter (mdates.DateFormatter ('% d /% m /% y')) plt.gcf (). autofmt_xdate () plt.grid (True) plt.show ( ) & lt; / código de & gt;  pre> 
Me gustaría destacar que para mostrar fuentes cirílicas apoyan la necesidad de conectar.
 & lt; code class = & quot; python & quot; & gt; de matplotlib rc importación font = {'familia': 'Droid Sans', 'peso':, 'tamaño' 'normal': 14} rc ('fuente', ** fuente) & lt; / código de & gt;  pre> 
  

Lectura de datos desde arduino h5>
Con este fin, utilizar la biblioteca serial El siguiente código se ejecuta en un hilo separado.
 & lt; code class = & quot; python & quot; & gt; def getDataFromSimulator (): mundial valueFromSimulator, ser isRunnig = serial.Serial ('/ dev / ttyACM0', 9600), mientras que isRunnig: valor = ser.readline () Proveedores: valueFromSimulator = int (valor), excepto: pasar & lt; / código de & gt;  pre> 
La variable valueFromSimulator en el otro hilo se utiliza sólo para la lectura.
El lanzamiento de dos corrientes.
 & lt; code class = & quot; python & quot; & gt; t1 = threading.Thread (target =, args = (self.profileId, self.distanceId) principal) t2 = threading.Thread (target = getDataFromSimulator) t2.start ( ) t1.start () & lt; / código de & gt;  pre> 

Video demostración de mala calidad h4>
Según lo ordenado.


Voy a estar alegres comentarios, críticas y sugerencias. I>
Todo el código fuente

Fuente: habrahabr.ru/post/217891/

Tags

Vea también

Nueva y Notable