Quantcast

Position2DInterface.getYaw() I always get the same value

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Position2DInterface.getYaw() I always get the same value

apm75
This post was updated on .
Hi people,

I'm programming BUG2 algorithm with player/stage. I'm using Player-3.0.2 and Stage-3.2.2. First I get the slope:
 slope = (goalY - startY) / (goalX - startX);
and the angle with trigonometry:
 angle = (float) Math.toDegrees(Math.atan(Math.abs(slope)));

later I try to do that the robot look at the GOAL point. In this point, I try this code:

static void apuntar(Position2DInterface posi) {
                while (!posi.isDataReady())
                        ;

                boolean salir = false;

                while (!salir) {
                        // giramos
                        posi.setSpeed(0, 0.15f);

                        float min = (float) (angulo - 1.5f);
                        float max = (float) (angulo + 1.5f);

                        try {
                                Thread.sleep(1000);
                        } catch (Exception e) {
                        }

                        float posAngulo = posi.getYaw();
                        System.out.println("min = " + min);
                        System.out.println("max = " + max);
                        System.out.println("pos = " + posAngulo);
                        if (posAngulo > min && posAngulo < max) {
                                salir = true;
                        }
                }
                posi.setSpeed(0, 0);
        }

But I always get the same value with getYaw() so my robot turns on itself and I see how the angle change in stage window, but I get the same value with getYaw in my code, so never will work!!

thanks in advance, sorry my english ins't good!!
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Position2DInterface.getYaw() I always get the same value

Fred Labrosse
Hello,

You need to call read() on your robot, to get new values.

Fred


On Thursday 08 May 2014 07:31:05 apm75 wrote:

> Hi people,
>
> I'm programming BUG2 algorithm with player/stage. I'm using Player-3.0.2
> and Stage-3.2.2. First I get the slope:
>  slope = (goalY - startY) / (goalX - startX);
> and the angle with trigonometry:
>  angle = (float) Math.toDegrees(Math.atan(Math.abs(slope)));
>
> later I try to do that the robot look at the GOAL point. In this point, I
> try this code:
> static void apuntar(Position2DInterface posi) {
>
> while (!posi.isDataReady())
> ;
>
> boolean salir = false;
>
> while (!salir) {
> // giramos
> posi.setSpeed(0, 0.15f);
>
> float min = (float) (angulo - 1.5f);
> float max = (float) (angulo + 1.5f);
>
> try {
> Thread.sleep(1000);
> } catch (Exception e) {
> }
>
> float posAngulo = posi.getYaw();
> System.out.println("min = " + min);
> System.out.println("max = " + max);
> System.out.println("pos = " + posAngulo);
> if (posAngulo > min && posAngulo < max) {
> salir = true;
> }
> }
> posi.setSpeed(0, 0);
> }
>
> But I always get the same value with getYaw() so my robot turns on itself
> and I see how the angle change in stage window, but I get the same value
> with getYaw in my code, so never will work!!
>
> thanks in advance, sorry my english ins't good!!
>
>
>
>
> --
> View this message in context:
> http://player-stage-gazebo.10965.n7.nabble.com/Position2DInterface-getYa
> w-I-always-get-the-same-value-tp19226.html Sent from the
> playerstage-users mailing list archive at Nabble.com.
>
> -------------------------------------------------------------------------
> ----- Is your legacy SCM system holding you back? Join Perforce May 7 to
> find out: &#149; 3 signs your SCM is hindering your productivity
> &#149; Requirements for releasing software faster
> &#149; Expert tips and advice for migrating your SCM now
> http://p.sf.net/sfu/perforce
> _______________________________________________
> Playerstage-users mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/playerstage-users

------------------------------------------------------------------------------
Is your legacy SCM system holding you back? Join Perforce May 7 to find out:
&#149; 3 signs your SCM is hindering your productivity
&#149; Requirements for releasing software faster
&#149; Expert tips and advice for migrating your SCM now
http://p.sf.net/sfu/perforce
_______________________________________________
Playerstage-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/playerstage-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Position2DInterface.getYaw() I always get the same value

aaldaihan
In reply to this post by apm75
U probably need the "Read()" call in the second loop.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Position2DInterface.getYaw() I always get the same value

apm75
This post was updated on .
In reply to this post by Fred Labrosse
Thanks Fred!!

I don't know if you said that...
Here is all code it's help to understand better

package bug2;

import javaclient2.PlayerClient;
import javaclient2.PlayerException;
import javaclient2.Position2DInterface;
import javaclient2.SonarInterface;
import javaclient2.structures.PlayerConstants;

public class Bug2 {
        // define minimum/maximum allowed values for the SONAR sensors
        static float SONAR_MIN_VALUE = 0.2f;
        static float SONAR_MAX_VALUE = 5.0f;

        // define the wall threshold
        static float MIN_WALL_THRESHOLD = 0.3f;
        static float MAX_WALL_THRESHOLD = 0.4f;

        // define the default translational and rotational speeds
        static float xSpeed, yawSpeed;
        static float DEF_X_SPEED = 0.2f;
        // static float DEF_X_SPEED = 1f;
        static float DEF_YAW_SPEED = 0.25f;
        // static float DEF_YAW_SPEED = 0.75f;

        // array to hold the SONAR sensor values
        static float[] sonarValues;
        static float frontSide, leftSide;

        // Punto inicial START
        static float startX = -7;
        static float startY = -7;

        // Punto final GOAL medio 2 obstaculos
        static float goalX = -5;
        static float goalY = -5;

        static float angulo = 0;
        static float pendiente = 0;

        static int estado = 0;

        static float posChoqueX = startX;
        static float posChoqueY = startY;

        public static void main(String[] args) {
                PlayerClient robot       = null;
                Position2DInterface posi = null;
                SonarInterface soni     = null;

                try {
                        robot = new PlayerClient("localhost", 6665);
                        posi = robot.requestInterfacePosition2D(0,
                                        PlayerConstants.PLAYER_OPEN_MODE);
                        soni = robot.requestInterfaceSonar(0,
                                        PlayerConstants.PLAYER_OPEN_MODE);
                } catch (PlayerException e) {
                        System.err.println(" > Error connecting to Player: ");
                        System.err.println("    [ " + e.toString() + " ]");
                        System.exit(1);
                }
       
                robot.runThreaded(0, 0);

                // Calculo de la pendiente entre el START y el GOAL - m=(y-y0)/(x-xo)
                pendiente = (goalY - startY) / (goalX - startX);
                System.out.println("Pendiente = " + pendiente);

                // Para el calculo del angulo usamos trigonometria (arco-tangente)
                angulo = (float) Math.toDegrees(Math.atan(Math.abs(pendiente)));
                System.out.println("Angulo2 = " + angulo);

                // Enfocamos al robot hacia el objetivo
                apuntar(robot,posi);
                // Cuando estamos enfocados iniciamos el proceso
                boolean rodear = false;
                boolean fin = false;
                estado = 0;
                while (!fin) {

                        // obtenemos los datos de los sonar
                        getSonars(soni);

                        // salvo algo lo impida nos moveremos de frente
                        xSpeed = DEF_X_SPEED;
                        yawSpeed = 0;

                        while (!posi.isDataReady())
                                ;
                        // si estoy en la recta y no estoy rodeando... pa lante
                        float posRealx = posi.getX() + startX;
                        while (!posi.isDataReady())
                                ;
                        float posRealy = posi.getY() + startY;

                        // si detecto un obstaculo -> rodear igual a true
                        if (frontSide < MAX_WALL_THRESHOLD) {
                                System.out.println("DETECTA");
                                rodear = true;
                        }

                        System.out.println("En linea?");
                        boolean enLinea = enLaLinea(posRealx, posRealy);
                        if (enLinea && !rodear) {
                                // Pa lante
                                System.out.println("Adelante!");
                                posi.setSpeed(xSpeed, yawSpeed);

                                if (posRealx > (goalX - 0.5) && posRealx < (goalX + 0.5)
                                                && posRealy > (goalY - 0.5) && posRealy < (goalY + 0.5)) {
                                        posi.setSpeed(0, 0);
                                        fin = true;
                                }

                        } else {

                                if (rodear) {
                                        System.out.println("Rodeando...");
                                        rodear(soni, posi);

                                }
                                System.out.println("ESTADO: " + estado);
                                if (estado == 5) {
                                        posi.setSpeed(0, 0);
                                        apuntar(robot,posi);

                                        rodear = false;
                                        estado = 0;
                                        posChoqueX = posRealx;
                                        posChoqueY = posRealy;
                                }

                        }

                        try {
                                Thread.sleep(100);
                        } catch (Exception e) {
                        }
                }
                return;
        }

        static void rodear(SonarInterface soni, Position2DInterface posi) {
                xSpeed = DEF_X_SPEED;
                yawSpeed = 0;

                // Detecion de choque de frente
                if (frontSide < MAX_WALL_THRESHOLD) {
                        xSpeed = -0.10f;
                        yawSpeed = -DEF_YAW_SPEED * 4;
                } else
                // No nos acercarnos al objeto
                if (leftSide < MIN_WALL_THRESHOLD) {
                        xSpeed = DEF_X_SPEED / 2;
                        yawSpeed = -DEF_YAW_SPEED;
                } else
                // Ni nos alejamos mucho
                if (leftSide > MAX_WALL_THRESHOLD) {
                        xSpeed = DEF_X_SPEED / 2;
                        yawSpeed = DEF_YAW_SPEED;
                }
                posi.setSpeed(xSpeed, yawSpeed);
        }

        static void getSonars(SonarInterface soni) {
                while (!soni.isDataReady())
                        ;
                sonarValues = soni.getData().getRanges();

                // ignore erroneous readings/keep interval [SONAR_MIN_VALUE;
                // SONAR_MAX_VALUE]
                for (int i = 0; i < soni.getData().getRanges_count(); i++)
                        if (sonarValues[i] < SONAR_MIN_VALUE)
                                sonarValues[i] = SONAR_MIN_VALUE;
                        else if (sonarValues[i] > SONAR_MAX_VALUE)
                                sonarValues[i] = SONAR_MAX_VALUE;

                leftSide = Math.min(Math.min(sonarValues[0], sonarValues[1]),
                                sonarValues[2]);
                frontSide = Math.min(sonarValues[3], sonarValues[4]);
        }

        static boolean enLaLinea(float x, float y) {

                float deno1 = 0;
                float deno2 = 0;
                float coeficiente = 0;
                if (goalX - startX != 0) {
                        deno1 = goalX - startX;
                }
                if (goalY - startY != 0) {
                        deno2 = goalY - startY;
                }
                if (deno1 == 0) {
                        coeficiente = 0 - (y - startY) / deno2;
                } else {
                        if (deno2 == 0) {
                                coeficiente = (x - startX) / deno1 - 0;
                        } else {
                                coeficiente = (x - startX) / deno1 - (y - startY) / deno2;
                        }
                }

                System.out.println("Coeficiente ="+coeficiente);

                if (-0.05f < coeficiente && coeficiente < 0.05f) {
                        if (Math.abs(posChoqueX - x) < 0.5
                                        && Math.abs(posChoqueY - y) < 0.5) {
                                posChoqueX = x;
                                posChoqueY = y;
                        } else {
                                estado = 5;

                        }
                        return true;
                }

                return false;
        }

        static void apuntar(PlayerClient robot, Position2DInterface posi) {

                while (!posi.isDataReady());
               

                boolean salir = false;

                while (!salir) {
                        // giramos
                        posi.setSpeed(0, 0.15f);

                        float min = (float) (angulo - 1.5f);
                        float max = (float) (angulo + 1.5f);

                        try {
                                Thread.sleep(1000);
                        } catch (Exception e) {
                        }
                       
                        robot.readAll();
                        float posAngulo = posi.getYaw();
                        System.out.println("min = " + min);
                        System.out.println("max = " + max);
                        System.out.println("pos = " + posAngulo);
                        if (posAngulo > min && posAngulo < max) {
                                salir = true;
                        }
                }
                posi.setSpeed(0, 0);
        }

}
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Position2DInterface.getYaw() I always get the same value

Fred Labrosse
I'm not sure what your code does (no time to look in great detail and my
Spanish is a bit rusty ;-) but you do seem to call readAll() (not sure what
it does, I use Read()).

However this is on a copy of the robot, not on the robot itself.  I have
not looked at that, but it is unlikely that this is going to work, and
passing instances like the PlayerClient and Position2DInterface by value is
anyway a bad idea).  Use pointers (or references if you don't want to use
pointers).

Fred


On Thursday 08 May 2014 10:49:17 apm75 wrote:

> Thanks Fred!!
>
> I don't know if you said that...
> Here is all code it's help to understand better
>
> package bug2;
>
> import javaclient2.PlayerClient;
> import javaclient2.PlayerException;
> import javaclient2.Position2DInterface;
> import javaclient2.SonarInterface;
> import javaclient2.structures.PlayerConstants;
>
> public class Bug2 {
> // define minimum/maximum allowed values for the SONAR sensors
> static float SONAR_MIN_VALUE = 0.2f;
> static float SONAR_MAX_VALUE = 5.0f;
>
> // define the wall threshold
> static float MIN_WALL_THRESHOLD = 0.3f;
> static float MAX_WALL_THRESHOLD = 0.4f;
>
> // define the default translational and rotational speeds
> static float xSpeed, yawSpeed;
> static float DEF_X_SPEED = 0.2f;
> // static float DEF_X_SPEED = 1f;
> static float DEF_YAW_SPEED = 0.25f;
> // static float DEF_YAW_SPEED = 0.75f;
>
> // array to hold the SONAR sensor values
> static float[] sonarValues;
> static float frontSide, leftSide;
>
> // Punto inicial START
> static float startX = -7;
> static float startY = -7;
>
> // Punto final GOAL medio 2 obstaculos
> static float goalX = -5;
> static float goalY = -5;
>
> static float angulo = 0;
> static float pendiente = 0;
>
> static int estado = 0;
>
> static float posChoqueX = startX;
> static float posChoqueY = startY;
>
> public static void main(String[] args) {
> PlayerClient robot       = null;
> Position2DInterface posi = null;
> SonarInterface soni     = null;
>
> try {
> robot = new PlayerClient("localhost", 6665);
> posi = robot.requestInterfacePosition2D(0,
> PlayerConstants.PLAYER_OPEN_MODE);
> soni = robot.requestInterfaceSonar(0,
> PlayerConstants.PLAYER_OPEN_MODE);
> } catch (PlayerException e) {
> System.err.println(" > Error connecting to Player: ");
> System.err.println("    [ " + e.toString() + " ]");
> System.exit(1);
> }
>
> robot.runThreaded(0, 0);
>
> // Calculo de la pendiente entre el START y el GOAL - m=(y-
y0)/(x-xo)
> pendiente = (goalY - startY) / (goalX - startX);
> System.out.println("Pendiente = " + pendiente);
>
> // Para el calculo del angulo usamos trigonometria (arco-
tangente)

> angulo = (float) Math.toDegrees(Math.atan(Math.abs(pendiente)));
> System.out.println("Angulo2 = " + angulo);
>
> // Enfocamos al robot hacia el objetivo
> apuntar(robot,posi);
> // Cuando estamos enfocados iniciamos el proceso
> boolean rodear = false;
> boolean fin = false;
> estado = 0;
> while (!fin) {
>
> // obtenemos los datos de los sonar
> getSonars(soni);
>
> // salvo algo lo impida nos moveremos de frente
> xSpeed = DEF_X_SPEED;
> yawSpeed = 0;
>
> while (!posi.isDataReady())
> ;
> // si estoy en la recta y no estoy rodeando... pa lante
> float posRealx = posi.getX() + startX;
> while (!posi.isDataReady())
> ;
> float posRealy = posi.getY() + startY;
>
> // si detecto un obstaculo -> rodear igual a true
> if (frontSide < MAX_WALL_THRESHOLD) {
> System.out.println("DETECTA");
> rodear = true;
> }
>
> System.out.println("En linea?");
> boolean enLinea = enLaLinea(posRealx, posRealy);
> if (enLinea && !rodear) {
> // Pa lante
> System.out.println("Adelante!");
> posi.setSpeed(xSpeed, yawSpeed);
>
> if (posRealx > (goalX - 0.5) && posRealx < (goalX +
0.5)
> && posRealy > (goalY - 0.5) && posRealy <
(goalY + 0.5)) {

> posi.setSpeed(0, 0);
> fin = true;
> }
>
> } else {
>
> if (rodear) {
> System.out.println("Rodeando...");
> rodear(soni, posi);
>
> }
> System.out.println("ESTADO: " + estado);
> if (estado == 5) {
> posi.setSpeed(0, 0);
> apuntar(robot,posi);
>
> rodear = false;
> estado = 0;
> posChoqueX = posRealx;
> posChoqueY = posRealy;
> }
>
> }
>
> try {
> Thread.sleep(100);
> } catch (Exception e) {
> }
> }
> return;
> }
>
> static void rodear(SonarInterface soni, Position2DInterface posi) {
> xSpeed = DEF_X_SPEED;
> yawSpeed = 0;
>
> // Detecion de choque de frente
> if (frontSide < MAX_WALL_THRESHOLD) {
> xSpeed = -0.10f;
> yawSpeed = -DEF_YAW_SPEED * 4;
> } else
> // No nos acercarnos al objeto
> if (leftSide < MIN_WALL_THRESHOLD) {
> xSpeed = DEF_X_SPEED / 2;
> yawSpeed = -DEF_YAW_SPEED;
> } else
> // Ni nos alejamos mucho
> if (leftSide > MAX_WALL_THRESHOLD) {
> xSpeed = DEF_X_SPEED / 2;
> yawSpeed = DEF_YAW_SPEED;
> }
> posi.setSpeed(xSpeed, yawSpeed);
> }
>
> static void getSonars(SonarInterface soni) {
> while (!soni.isDataReady())
> ;
> sonarValues = soni.getData().getRanges();
>
> // ignore erroneous readings/keep interval [SONAR_MIN_VALUE;
> // SONAR_MAX_VALUE]
> for (int i = 0; i < soni.getData().getRanges_count(); i++)
> if (sonarValues[i] < SONAR_MIN_VALUE)
> sonarValues[i] = SONAR_MIN_VALUE;
> else if (sonarValues[i] > SONAR_MAX_VALUE)
> sonarValues[i] = SONAR_MAX_VALUE;
>
> leftSide = Math.min(Math.min(sonarValues[0], sonarValues[1]),
> sonarValues[2]);
> frontSide = Math.min(sonarValues[3], sonarValues[4]);
> }
>
> static boolean enLaLinea(float x, float y) {
>
> float deno1 = 0;
> float deno2 = 0;
> float coeficiente = 0;
> if (goalX - startX != 0) {
> deno1 = goalX - startX;
> }
> if (goalY - startY != 0) {
> deno2 = goalY - startY;
> }
> if (deno1 == 0) {
> coeficiente = 0 - (y - startY) / deno2;
> } else {
> if (deno2 == 0) {
> coeficiente = (x - startX) / deno1 - 0;
> } else {
> coeficiente = (x - startX) / deno1 - (y - startY) /
deno2;
> }
> }
>
> System.out.println("Coeficiente ="+coeficiente);
>
> if (-0.05f < coeficiente && coeficiente < 0.05f) {
> System.out.println("EN LINEA: " + (x - startX) / (goalX -
startX)
> + " @@ " + (y - startY) / (goalY - startY) + " @@
TRUE");
> System.out.println("EN LINEA: "
> + (posChoqueX - x)
> + " @@ "
> + (posChoqueY - y)
> + " @@"
> + (Math.abs(posChoqueX - x) < 0.5 ||
Math.abs(posChoqueY

> - y) < 0.5));
> System.out.println("Xs: " + (posChoqueX) + "-" + x + " || "
> + "Ys: " + (posChoqueY) + "-" + y);
> if (Math.abs(posChoqueX - x) < 0.5
> && Math.abs(posChoqueY - y) < 0.5) {
> posChoqueX = x;
> posChoqueY = y;
> } else {
> estado = 5;
>
> }
> return true;
> }
> // System.out.println("EN LINEA: "+(x-startX)/(goalX-startX)+" @@
> "+(y-startY)/(goalY-startY)
> // + " @@ FALSE");
>
> return false;
> }
>
> static void apuntar(PlayerClient robot, Position2DInterface posi) {
>
> while (!posi.isDataReady());
>
>
> boolean salir = false;
>
> while (!salir) {
> // giramos
> posi.setSpeed(0, 0.15f);
>
> float min = (float) (angulo - 1.5f);
> float max = (float) (angulo + 1.5f);
>
> try {
> Thread.sleep(1000);
> } catch (Exception e) {
> }
>
> robot.readAll();
> float posAngulo = posi.getYaw();
> System.out.println("min = " + min);
> System.out.println("max = " + max);
> System.out.println("pos = " + posAngulo);
> if (posAngulo > min && posAngulo < max) {
> salir = true;
> }
> }
> posi.setSpeed(0, 0);
> }
>
> }
>
>
>
>
> --
> View this message in context:
> http://player-stage-gazebo.10965.n7.nabble.com/Position2DInterface-getYa
> w-I-always-get-the-same-value-tp19226p19229.html Sent from the
> playerstage-users mailing list archive at Nabble.com.
>
> -------------------------------------------------------------------------
> ----- Is your legacy SCM system holding you back? Join Perforce May 7 to
> find out: &#149; 3 signs your SCM is hindering your productivity
> &#149; Requirements for releasing software faster
> &#149; Expert tips and advice for migrating your SCM now
> http://p.sf.net/sfu/perforce
> _______________________________________________
> Playerstage-users mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/playerstage-users

------------------------------------------------------------------------------
Is your legacy SCM system holding you back? Join Perforce May 7 to find out:
&#149; 3 signs your SCM is hindering your productivity
&#149; Requirements for releasing software faster
&#149; Expert tips and advice for migrating your SCM now
http://p.sf.net/sfu/perforce
_______________________________________________
Playerstage-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/playerstage-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Position2DInterface.getYaw() I always get the same value

apm75
thanks Fred,

My algorithm consist in that: My robot leads straight to the goal, if the robot encounters an obstacle it around to the right side, and returns to the straight line to the goal.

I don't know which variable have to call Read(), Position2DInterface posi? SonarInterface soni?
Other thing I don't understand you it's the used of pointers in Java?

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Position2DInterface.getYaw() I always get the same value

Fred Labrosse
I did say I did not have time to look at it properly, so did not spot that
this was Java (thought it was C++).

Read(), which may well be readAll() in Java, I don't know) needs to be
called on the robot (player client) as you did.  And that needs to be
called in the control loop.  And this is what you seem to be doing.

So maybe the Java API behaves differently. Sorry, I don't use Java so I
don't know.

Fred


On Friday 09 May 2014 01:57:04 apm75 wrote:

> thanks Fred,
>
> My algorithm consist in that: My robot leads straight to the goal, if the
> robot encounters an obstacle it around to the right side, and returns to
> the straight line to the goal.
>
> I don't know which variable have to call Read(), Position2DInterface
> posi? SonarInterface soni?
> Other thing I don't understand you it's the used of pointers in Java?
>
>
>
>
>
> --
> View this message in context:
> http://player-stage-gazebo.10965.n7.nabble.com/Position2DInterface-getYa
> w-I-always-get-the-same-value-tp19226p19231.html Sent from the
> playerstage-users mailing list archive at Nabble.com.
>
> -------------------------------------------------------------------------
> ----- Is your legacy SCM system holding you back? Join Perforce May 7 to
> find out: &#149; 3 signs your SCM is hindering your productivity
> &#149; Requirements for releasing software faster
> &#149; Expert tips and advice for migrating your SCM now
> http://p.sf.net/sfu/perforce
> _______________________________________________
> Playerstage-users mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/playerstage-users

------------------------------------------------------------------------------
Is your legacy SCM system holding you back? Join Perforce May 7 to find out:
&#149; 3 signs your SCM is hindering your productivity
&#149; Requirements for releasing software faster
&#149; Expert tips and advice for migrating your SCM now
http://p.sf.net/sfu/perforce
_______________________________________________
Playerstage-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/playerstage-users
Loading...