Aller au contenu


Photo

Glenn Robot Humanoide


  • Veuillez vous connecter pour répondre
989 réponses à ce sujet

#41 Oliver17

Oliver17

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 2 676 messages
  • Gender:Male
  • Interests:Glenn

Posté 21 juillet 2016 - 03:39

Oui mais tu veux le quel exactement, j'en ai fais plusieurs, et il faut que je peaufine j'ai un peu honte de lâcher ça comme ça lol :)

Dis moi et je post ça.

 

Edit : là je revois le code pour jouer sur l'accélération et la vitesse et non pas sur les degrés en incrémentation.

Pour degrés il faut juste que je récupérer ça valeur et savoir la position, c'est tout.

 

Donc je refais tout ^^

 

Pour Abdelkrim qui comme moi aime voir les photos et vidéos du travail des maker's :)

 

Bon j'ai juste revu ma structure de test hein, y a rien de folichon ^^

 

mini_259367IMAG1454.jpg

 

 

Merci


signature_01.png -->

 

Mon Tipeee
 


#42 Path

Path

    Made By Humans

  • Modérateur
  • PipPipPipPipPip
  • 2 409 messages
  • Gender:Male
  • Location:Paris

Posté 21 juillet 2016 - 04:04

 

 

j'ai un peu honte de lâcher ça comme ça

... Faut pas !! On (moi aussi) est là pour apprendre. :)

 

Je parlais du code joué pendant que tu filmais.

 


Podcast Made By Humans

Je cherche des volontaires de tous niveaux pour nos petites conversations entre hobbyistes.

Accès aux salles secrètes

 


#43 Oliver17

Oliver17

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 2 676 messages
  • Gender:Male
  • Interests:Glenn

Posté 21 juillet 2016 - 04:16

Bon je crois que c'est ça, mais comme je bidouille des que je veux jouer avec un servo ^^

 

 

 
from Adafruit_PWM_Servo_Driver import PWM
import time

pwm = PWM(0x40,  debug = False)
pwm.setPWMFreq(50)

servomin = 150 
servomax = 510  
anglemin = 0
anglemaxi = 180
anglemoins = -90
anglecentre = 0
angleplus = 90
degres = 0

#def fservo018 ():
#    """Ici on transforme la valeur du servo en degré"""
 #   result = int((degres - anglemin) * (servomax - servomin) / (anglemaxi - anglemin) + servomin) 
 #   return result

def fservo909 ():
    """Ici on transforme la valeur du servo en degré"""
    result = int((degres - anglemoins) * (servomax - servomin) / (angleplus - anglemoins) + servomin)
    return result

accel = 0.5
decel = 0
vitesse = 2

def fcalc ():
    cal0 = (infodegres/100)*10 #durée de l'accélération
    cal1 = infodegres-cal1 #durée de la vitesse constante
    cal2 = infodegres/100 #valeur pour l'accélération
    return cal0, cal1, cal2

def faccel():
    """Ici on gére l'accélération"""
    #calc = round(accel + (degres/100)*vitesse, 2)
    calc = round(accel + (degres/100)*vitesse, 2)
    print (calc)
    return calc

degres = 0  #les trois lignes suivante sont juste pour tester rapidement, sinon elles ne me servent pas.
pwm.setPWM(0, 0, fservo()) #ici on joue sur le servo en degrés
pwm.setPWM(0, 0, 150) #ici on joue directement avec les valeurs du servo

#time.sleep(3)
print ("servo : ",int(fservo()),"- Degres : ",degres, "- Acceleration : ",faccel(), "- Vitesse donnée : ", vitesse)

while True :
   
    #break
    #ici mes tests sur l'accélération, mais ça fonctionne moins bien :'(
    if degres >= 30:
        pwm.setPWM(3, 0, fservo())
        degres += faccel()
        print ("servo : ",int(fservo()),"- Degres : ",degres, "- Acceleration : ",faccel(), "- Vitesse donnée : ", vitesse)
        
    elif degres == degres:
        degres = 0
        pwm.setPWM(3, 0, fservo())
        degres += faccel()
        print (fservo(), " : ",degres)
        print("Retour au début")
        
        break

Bon ben j'ai essayer de nettoyer un peu ^^

Dans ce code je joue avec les degrés, mais je me demande si je devrais pas jouer directement sur l'accélération et la vitesse que sur le degrés en lui même (euh je me répète là ou je deviens fou ?) et le degrés garder cette valeur pour la position...

 

Quand pensez vous ?

 

Edit : 18h45 : ppfffiiiuuuuu tout s'embrouille, je ne sais même plus par ou chercher quelle direction prendre, sur quelle valeur jouer...

 

Edit : 20h08 : quelqu'un aurait un lien sur (je ne sais pas comment on dit) le lexique mathématique, vous savez tout ces signes que l'on voit dans les formules mathématique, petit n, le signe pi etc etc, j'avais trouvé un truc comme ça sur wikipedia et je n'arrive pas à retrouver le lien, si quelqu'un à mieux je suis preneur :)

 

 

Merci


signature_01.png -->

 

Mon Tipeee
 


#44 abdelkrim

abdelkrim

    Membre occasionnel

  • Membres
  • Pip
  • 143 messages
  • Gender:Male
  • Location:France/Picardie/Oise/ Creil
  • Interests:Infographie 3D, Programation, Robotique, Sport

Posté 22 juillet 2016 - 03:01

Voilà, j'ai fais une pitite vidéo, montez le son je fais mon timide, et en plus bonjour la voix que j'ai on dirait que j'ai bouffer un paquet de clope lol

Je pense que tous le monde trouve sa voix bizarre sur un enregistrement alors qu'elle est entièrement normal^^ (enfin moi c'est mon cas)

 

Pour Abdelkrim qui comme moi aime voir les photos et vidéos du travail des maker's  :)

Je ne peux pas trop toucher a la robotique là ou je suis donc je peux simplement regardé le travaille des autres, et étant un débutant ne comprenant pas très bien les écrits, j'aime beaucoup voirs vos création en image/vidéo :P

 

 

Sinon j'essaye de donner une solution mais je ne sais pas si ça marche, en faite ça marche en 3D donc... :Alex_03:

En gros (je e comprend pas trop le code mais bon) essaye de trouver la valeur qui place les servomoteur à la position 0 (par exemple 250)

Une fois cette valeurs trouvé, tu mes dans le code que (par exemple) 250 = 0 , normalement l'ordinateur comprendra que 340 = 90 aussi ect...

En gros, on change la position des valeur 250 comme la valeur initial (donc 0)

 

Mais comme j'ai dit il ne faut pas m'écouter à 100%, je donne simplement une idée si c'est fesable

 

oui j'aurai peut-etre dû me taire^^

 

Pour Abdelkrim qui comme moi aime voir les photos et vidéos du travail des maker's  :)

Je ne peux pas trop toucher a la robotique là ou je suis donc je peux simplement regardé le travaille des autres, et étant un débutant ne comprenant pas très bien les écrits, j'aime beaucoup voirs vos création en image/vidéo :P


pour mieux me connaitre : Abdelkrim et sa révolution

mes animation 3D (pas toute mais ça arrive ;) ) : youtube


#45 Oliver17

Oliver17

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 2 676 messages
  • Gender:Male
  • Interests:Glenn

Posté 22 juillet 2016 - 05:10

Lol, ben le truc c'est que les valeurs sont transformés via les extrêmes genre comme le map() sous arduino.

 

Ce qui fait que en théorie tu retrouves toujours le centre, de toutes façons j'ai bidouillé les valeurs pour que ça tombe au centre comme me l'a conseillé Cocothebo.


signature_01.png -->

 

Mon Tipeee
 


#46 Path

Path

    Made By Humans

  • Modérateur
  • PipPipPipPipPip
  • 2 409 messages
  • Gender:Male
  • Location:Paris

Posté 23 juillet 2016 - 10:32

Merci pour le source. T'as pas le while dans la video, si j'ai bien compris.

Du coup je vois pas d'où vient le pb du milieu pas au milieu :)

En fait, je vois que ça : le servo irait au delà de 650 ou en deçà de 100. Il serait donc capable de plus de 180°.

Désolé, je deviens monomaniac quand je comprends pas :)


Podcast Made By Humans

Je cherche des volontaires de tous niveaux pour nos petites conversations entre hobbyistes.

Accès aux salles secrètes

 


#47 Oliver17

Oliver17

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 2 676 messages
  • Gender:Male
  • Interests:Glenn

Posté 23 juillet 2016 - 10:37

Bon je patauge un peu, je reprend quasi tout, on est d'accord que les servomoteurs on gère la position et donc de ce fait pour une accélération il est normal que j'ai des accoups car je suis obligé de faire mon accélération via la position du servo, hein, ok ? :)

 

genre : accélération + (degres/100)*vitesse  #
Ce sont des valeurs que j'entre pour gérer tout le bignou niveau calcul...

 

De ce fait, existe t'il un moyen pour avoir une transition plus douce, sans accoups ?

 

Et le truc pour finir connaissez vous les formules pour une accélération linéaire ou (je ne suis pas sur du terme) rampe d'accélération ?

J'ai un peu de mal à trouver tout ça sur le net, ou lorsque je trouve te bien je pige pas la formule car il y a tout ces "sigles" mathématique que je ne comprend pas (pas tous).

 

Car ce que j'ai pu faire me convient moyen.

 

Merci


signature_01.png -->

 

Mon Tipeee
 


#48 Oliver17

Oliver17

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 2 676 messages
  • Gender:Male
  • Interests:Glenn

Posté 23 juillet 2016 - 10:39

Merci pour le source. T'as pas le while dans la video, si j'ai bien compris.

Du coup je vois pas d'où vient le pb du milieu pas au milieu :)

En fait, je vois que ça : le servo irait au delà de 650 ou en deçà de 100. Il serait donc capable de plus de 180°.

Désolé, je deviens monomaniac quand je comprends pas :)

 

Coucou, bah pour que ça tombe au milieu me suis pas pris la tête, j'ai changé les valeurs et j'ai moins de 180°, tant pis :) et je retrouve donc un bon milieu si je puis dire :)


signature_01.png -->

 

Mon Tipeee
 


#49 Path

Path

    Made By Humans

  • Modérateur
  • PipPipPipPipPip
  • 2 409 messages
  • Gender:Male
  • Location:Paris

Posté 23 juillet 2016 - 11:37

Rhaa :) S'pas logique ça :) lol

 

Pour ta vitesse,

 

Imagine que tu veuilles parcourir 100°. De la position 0° à la position finale 100°. Par exemple.

Tu veux que ce parcours soit fait en 10s.

Soit 10°/s.

 

Pour faire ça, 

Tu place ton servo à 0° et tu initialise une variable t (temps) à 0.

Tu boucle comme ceci : 

- La position de ton servo en degrés à l'instant est map(<temps depuis t=0>, 0s, 10s, 0°, 100°)

- Tu sors de la boucle quand la position est (supérieur ou) égale à ta position d'arrivée (pour gérer le pb des pouillèmes après la virgule)

 

Regardes comment j'ai fait pour bob ;) http://www.robot-maker.com/forum/topic/10644-le-ptit-bob-de-path-complet/?p=72156

 

Pour ton accélération,

 

Imagine que tu veuilles ce même parcours de 100° en allant plus lentement au début et à la fin du parcours.

Tu utilise la même méthode et tu lui demande ceci :

- De 0 à 10° tu lui demande de le faire en 2s (soit 5°/s)

- De 10° à 90° en 6s (soit 13,3°/s)

- De 90 à 100° en 2s (soit 5°/s)

 

C'est pas les rampes dont parlait Mike. C'est pas une une accélération linéaire mais je trouve ça simple.


Podcast Made By Humans

Je cherche des volontaires de tous niveaux pour nos petites conversations entre hobbyistes.

Accès aux salles secrètes

 


#50 Oliver17

Oliver17

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 2 676 messages
  • Gender:Male
  • Interests:Glenn

Posté 23 juillet 2016 - 12:35

Ok, je viens de lire rapide, et je comprend dans les grandes lignes, donc avec ce que tu me décris ici je dois pouvoir arriver à faire quelque chose :)

 

Merci, je vais me pencher sur ce problème via tes données, au moins maintenant je sais vers ou allez car franchement je commençais à pédaler dans la s'moule et je ne savais plus vers quoi chercher.

 

Si je me réfère aux données du servomoteur qui sont 0.14sec/60° cela peut aider, non ?

Et si je pige bien, il faut jouer avec map() régulièrement ?

J'y ai pensé mais j'étais pas du tout sur cette même longueur d'onde ^^

 

Je poserai le code des que j'aurai "un truc valable" :)

 

Edit 14:19 : j'ai vu les mouvements de Bob, c'est super fluide je trouve .

 

 

Merci


signature_01.png -->

 

Mon Tipeee
 


#51 Path

Path

    Made By Humans

  • Modérateur
  • PipPipPipPipPip
  • 2 409 messages
  • Gender:Male
  • Location:Paris

Posté 23 juillet 2016 - 01:38

La donnée du constructeur de 0,14s pour faire 60 deg doit te donner la vitesse max. Soit 428,5 deg/s.

Map oui en boucle pour faire ça.

Regarde les code aussi :)

Prends le temps.

Podcast Made By Humans

Je cherche des volontaires de tous niveaux pour nos petites conversations entre hobbyistes.

Accès aux salles secrètes

 


#52 Oliver17

Oliver17

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 2 676 messages
  • Gender:Male
  • Interests:Glenn

Posté 23 juillet 2016 - 04:13

J'ai regardé ton code, mais j'ai pas tout pigé vu que c'est du C, mais je vais bien trouvé, en fait, tu gruges tu fais de l'incrémentation et en changeant les valeurs par exemple pour le vitesse seconde et degrés tu obtiens un certaines vitesse, c'est bien ça ? :)

 

Par contre pour l'accélération suis curieux de voir ce que ça va donner.

 

En tous cas merci bien pour ce coup de main, j'essaye déjà un code pour la vitesse et je posterai ça ^^

 

Merci


signature_01.png -->

 

Mon Tipeee
 


#53 Oliver17

Oliver17

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 2 676 messages
  • Gender:Male
  • Interests:Glenn

Posté 23 juillet 2016 - 05:02

Bon, j'ai essayé comme ça pour tester, et je ne vois pas vraiment de changement de vitesse lorsque je change les valeurs, j'ai du me planter quelque part.

 

 

from Adafruit_PWM_Servo_Driver import PWM
import time


pwm = PWM(0x40,  debug = False)
pwm.setPWMFreq(50)


t = 0
tsmin = 0
tsmax = 10
degmin = 0
degmax = 100


def fvitesse():
    result = int((t - tsmin) * (degmax - degmin) / (tsmax - tsmin) + degmin)
    #result = int((t - degmin) * (tsmax - tsmin) / (degmax - degmin) + tsmin)
    print (result)
    return result


pwm.setPWM(0, 0, 150)  #ici j'initialise juste le servo à 0

time.sleep(1)


while True :


    if t < 100 :
        
        pwm.setPWM(0, 0, fvitesse())
        t +=1
        print ("Temps : ", t, "- Degres : ",degres, "- vit foc : ",fvitesse())


    elif t == 100 :
        break

Merci


signature_01.png -->

 

Mon Tipeee
 


#54 Oliver17

Oliver17

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 2 676 messages
  • Gender:Male
  • Interests:Glenn

Posté 23 juillet 2016 - 05:39

J'ai retrouvé ce code pour la vitesse que j'avais réussi à faire :) (content rosco)

 

 

 
from Adafruit_PWM_Servo_Driver import PWM
import time


pwm = PWM(0x40,  debug = False)
pwm.setPWMFreq(50)


servomin = 100  
servomax = 600  
sourcemin = 0
sourcemaxi = 180


degres = 0


def degress ():
    #degres += 1 + 10 * 0.1
    result = int((degres - sourcemin) * (servomax - servomin) / (sourcemaxi - sourcemin) + servomin)
    
    return result


pwm.setPWM(0, 0, degres) #ici on initialise le servo à 0°
time.sleep(2)    
while True :
    
    if degres < 180:
        pwm.setPWM(0, 0, degress())
        degres += 1  #ici on change la valeur pour gérer la vitesse
        print (degress(), " : ",degres)


    elif degres == degres:
        time.sleep(1)
        degres = 0
        pwm.setPWM(0, 0, degress())
        print (degress(), " : ",degres)
        print("Retour au début")
        
        break

En fait ça il a l'air pas si mal, quand pense tu Path, le seul truc c'est que je gére l'incrémentation sur les degrés, et ça ne me plait pas trop, pourtant c'est bien sur les degrés que l'on a besoin de jouer.......

En fait en voyant de nouveau ce code je me rend compte que je vais bloquer à nouveau, vais peut être le reprendre comme base. ?!!


signature_01.png -->

 

Mon Tipeee
 


#55 Path

Path

    Made By Humans

  • Modérateur
  • PipPipPipPipPip
  • 2 409 messages
  • Gender:Male
  • Location:Paris

Posté 23 juillet 2016 - 06:06

Tu es sur la bonne voie avec ton premier.

 

fvitesse() retourne une valeur qui correspond à un angle. Elle porte mal son nom. (je chipote mais j'ai cru que tu mettais une vitesse dans setPWM)

 

A un moment, il faut bien appeler time.time() pour savoir combien de temps s'est écoulé entre 2 tours de la boucle.

Et j'ai du t'induire en erreur avec mon t=0. Dans ce cas, il faut mémoriser time.time() au démarrage du mouvement. On va appeler cette variable "timeDebut" pour lever l'ambiguïté.

 

degres = 0

timeDebut = time.time()

 

Fais-toi une fonction map générique def map(...) :

 

En entrée de map tu y mets du temps et en sortie un angle. map te donne une valeur proportionnelle de ton angle fonction du temps qui s'est écoulé.

Dans ta boucle, tu reprends la valeur de time.time() et tu la compare à timeDebut pour savoir à combien de temps on est du début.

delai = time.time() - timeDebut

Et tu donne ce delai à map (pas un angle).

 

Je corrige ce que je dis au dessus :

 

 

Pour faire ça, 

Tu place ton servo à 0° et tu initialise une variable t =.time.time()

Tu boucle comme ceci : 

- La position de ton servo en degrés à l'instant est map(<temps depuis t0>, 0s, 10s, 0°, 100°)

- Tu sors de la boucle quand la position est (supérieur ou) égale à ta position d'arrivée (pour gérer le pb des pouillèmes après la virgule)

 

 

Dernière remarque, tu es sur raspberry, pas un microcontroleur. Mets toujours des petits time.sleep() dans ta boucle pour laisser ton processeur respirer un peu. Il n'a pas que ton programme à exécuter ;) Même si il a 4 coeurs, c'est mal.


Podcast Made By Humans

Je cherche des volontaires de tous niveaux pour nos petites conversations entre hobbyistes.

Accès aux salles secrètes

 


#56 Oliver17

Oliver17

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 2 676 messages
  • Gender:Male
  • Interests:Glenn

Posté 23 juillet 2016 - 06:21

Hum, c'est là que je m’aperçois que je n'ai pas les bons réflexes et encore moins, loin d'avoir toutes les connaissances qu'il faudrait en python, je me sers de time pour les pauses, mais à aucun moment j'ai pensé à m'en servir dans le cas que tu me cite :'( (mais quel mauvais je fais).

 

Bon je vais essayer de décortiquer et de comprendre ce que tu m'a expliqué :)

 

Encore heureux que vous êtes là les gars (Path surtout en ce moment) sinon je serais encore à me péter les neurones sur le pourquoi du comment ^^

 

PS : mon autre code donc, je le met de coté, on est d'accord ce n'est pas un bon exemple...

 

Si je met un time.sleep(0.01) dans la boucle.... ah ben si c'est bon, j'ai pas d'accoups :) 

 

Encore merci :)


signature_01.png -->

 

Mon Tipeee
 


#57 cocothebo

cocothebo

    Membre passionné

  • Membres
  • PipPipPip
  • 341 messages
  • Gender:Male

Posté 23 juillet 2016 - 08:41

Juste une remarque en passant...

 

Dernière remarque, tu es sur raspberry, pas un microcontroleur. Mets toujours des petits time.sleep() dans ta boucle pour laisser ton processeur respirer un peu. Il n'a pas que ton programme à exécuter ;) Même si il a 4 coeurs, c'est mal.

Alors là j'ai des gros gros doutes.

Que pour une raison quelconque ajouter des time.sleep() améliore qqc pourquoi pas, mais pas pour la raison donnée.

D'une comme tu le dis, si c'est un pi 3 ya 4 coeurs donc 4 threads matériels en parallèle. De deux, on est sur un linux, qui gère le multi tache comme un grand, ya un ordonnanceur qui donne du temps à chaque process qui tourne en fonction de bcp de chose dont sa priorité.

Bref heureusement que l'on doit pas "penser" aux autres process sur un système d'exploitation, ça serait de toute façon complètement impossible à gérer.

 

En fait dans tous les cas, même si quand on exécute un script python c'est peu visible, celui ci est interrompu de multiples fois pour que d'autres processus s'exécute dans un semblant de multi tâche, quoi avec 4 coeurs on a un vrai 4 tâches en // mais sur un seul coeur même si on a l'impression de multi tavhe sur un linux/windows, en vrai il n'y a qu'un seul process qui s'exécute pour un petit moment puis un autre puis un autre etc.

 

 

Désolé pour le hors sujet, mais ça me semblait important!



#58 Path

Path

    Made By Humans

  • Modérateur
  • PipPipPipPipPip
  • 2 409 messages
  • Gender:Male
  • Location:Paris

Posté 23 juillet 2016 - 11:37

Tu as raison sur le fonctionnement de l'OS. C'est juste une bonne pratique voire un réflexe à prendre (surtout quand on débute) qui vient de mes profs et après de mon expérience du monde du web et des fortes charges sur les machines en front. Mais je t'accorde que ce n'est pas forcement applicable sur un robot où tu maitrise la charge et ton code. Cependant, je maintiens fermement ce que je dis : c'est mal de ne pas en mettre dans une boucle infinie ! Et je ne te dirais pas tout ce que je pense des boucles infinies. C'est mal aussi. Même dans un robot quand ça tourne sous linux, tu peux facilement arriver à du 400% CPU avec ça ! Désolé, je ne suis pas d'accord. Tu verras toujours une pause dans une boucle infinie. Et désolé aussi, Oliver, pour cette réponse. La bonne pratique consiste à laisser autres processus autant de temps CPU que possible. Même des micro secondes. Sisi, il faut se soucier de ce qui tourne à coté ; c'est un monde fermé.

 

PS. mon avis est applicable aux CPU avec un OS, pas aux micro-contrôleurs.


Podcast Made By Humans

Je cherche des volontaires de tous niveaux pour nos petites conversations entre hobbyistes.

Accès aux salles secrètes

 


#59 Oliver17

Oliver17

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 2 676 messages
  • Gender:Male
  • Interests:Glenn

Posté 24 juillet 2016 - 07:24

Y a pas de soucis les gars, exprimez vous :)

 

perso je fais du Hard Code (ce qui veut dire, que je code un truc chelou lol) :)

 

Edit 10:17 : le t = time.time() c'est bien ce que tu places dans ton map() on est bien d'accord.

d'ailleurs je croyais que le time.time donnée des valeurs en second, mais en fait j'ai une succession de chiffres de fou.

 

Merci


signature_01.png -->

 

Mon Tipeee
 


#60 Path

Path

    Made By Humans

  • Modérateur
  • PipPipPipPipPip
  • 2 409 messages
  • Gender:Male
  • Location:Paris

Posté 24 juillet 2016 - 09:32

Oui tu as raison :) en python, on obtient un double en secondes. Dans notre cas, il vaut mieux avoir des milli secondes.

Pour avoir des milli secondes : t= int(time.time() * 1000) et idem pout t0, hein, fois 1000  :)

Et non, à map, tu donne le temps depuis le début donc tu lui donne t-timeDebut


Podcast Made By Humans

Je cherche des volontaires de tous niveaux pour nos petites conversations entre hobbyistes.

Accès aux salles secrètes

 





0 utilisateur(s) li(sen)t ce sujet

0 members, 0 guests, 0 anonymous users