PS4 controller not working in GoPigo3

The reason I sent you that information is because the simple left() and right() methods don’t allow you to control the degree of turn - it simply goes right or left.

By using the set_speed methods, (and some simple calculations), you can make both speed and the sharpness of the turn directly related to the amount of joystick deflection.

2 Likes

The issue is the robot can only do one thing at a time using the forward/backward/right/left commands, but the joystick can command two things at the same time - a little forward AND a little left or right. The robot doesn’t know which to do - forward OR left/right.

You have two choices, simple or complex:

  • SIMPLE: create a class variable - fwd_bwd=False

    • set fwd_bwd=True in on_L3_down and on_L3_up
    • set fwd_bwd=False in on_L3_y_at_rest
    • add if (fwd_bwd == False): to on_L3_right and on_L3_left
      which will only tell the bot to turn left or right when not being commanded to go forward or backward. Meaning the robot will only be able to do one command OR another, and never is asked to do one command AND another.
    • P.S. If it is still touchy trying to get left/right to work, you may need to only set fwd_bwd True if the value is greater than some minimal value.
  • COMPLEX:

    • separate the driving from the commanding
      • on_L3_up/down commands set a class variable fwd_bwd by the y value
      • on_L3_left/right commands set a class variable left_right by the x value
      • on_L3_x_at_rest sets left_right to 0, on_L3_y_at_rest sets fwd_bwd to 0
      • every on_L3 command ends with a call to a class method do_drive_command()
      • do_drive_command(self) merges:
        • fwd_bwd and left_right into a steer(left_motor_percent, right_motor_percent)
        • probably can get hints how to do this from @jimrh’s code which I think uses set_motor_dps() instead

BTW, it appears when you changed the drive_cm(5) and -5 to forward() backward(), you forgot to change the print statements; made the code harder to grasp at first glance.

2 Likes

This is because the basic forward, backward, left, and right commands don’t allow for precision in turning or motion - these commands are intended to be used in simple “teach me about the robot” cases - like bloxter - where precision is not a requirement.

To move and turn with precision, you need to use the set_motor_dps commands like this:

  1. Measure/capture the actual value - with the sign - of the y_axis, (forward and back) and the x_axis, (left and right).
  2. Decide on what maximum speed you want the robot to travel at - 100 dps, 500 dps, whatever - and set max_speed to that value.
    • 300 is a good starting point.  Use a smaller number if you want the robot to move more slowly.
  3. For forward and backward motion, you need to generate a speed value for the motors that is proportional to the degree of deflection of the y_axis.
    • Since a normalized gamepad’s joystick returns values between 0 and 1, you can use these as percentages directly and calculate the speed by doing this: desired_speed = int((max_speed * y_axis) * -1)
      • The “-1” flips the sign so that the robot moves in the correct direction and the int makes sure the value is a whole number without a fractional part.)
    • For straight travel, you do this:
my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_LEFT, desired_speed)
my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_RIGHT, desired_speed)
  1. In order to turn, the inside wheel - the wheel you are turning toward - has to be moving more slowly than the outside wheel.  To do that, you need to calculate a “differential_speed” which is a speed value that is some fraction of the desired_speed - such that the greater the x_axis deflection, the slower the inside wheel goes.  This way, a small movement of the joystick to the left or right makes a small turn and a large movement of the x_axis makes a correspondingly sharper turn.
    • You do that calculation like this:
differential_speed = int(desired_speed - abs(desired_speed * x_axis))

This requires a bit more explanation:

  • The (desired_speed * x_axis) gives the fractional part of the desired speed represented by the x_axis movement.
    • (i.e. If the x_axis is moved a small amount, (0.1), the product becomes a very tiny number.  If it is moved more, (0.5), that number becomes larger.)
  • What we want is the amount of the desired speed left over after the tiny number is removed - so we subtract it from the desired speed.
    • As you move the x_axis further, the number gets larger and the subtracted speed becomes smaller - which is what you want since that will make the turn sharper the further the x_axis is moved.
    • You then apply the differential_speed to the inside wheel.
    • Moving backward is exactly the same, except the sign is negative.
  • You also have to test the sign of the x_axis value so you know which wheel needs to move more slowly.
    • If the x_axis is negative, you apply the desired_speed to the right wheel and differential_speed to the left wheel.
    • If the x_axis is positive, you apply the desired_speed to the left wheel and the differential_speed to the right wheel.  This will make the robot turn in the correct direction regardless of if it is moving backwards or forward.

Try it and tell me how it works.

=======================

Update
I tried adjusting my calculations as shown above and there were difficulties.

My original logic works.

############################
##    Motion Selection    ##
############################
#  Depending on the position of the x and y axes
#  and the state of trigger_1, we determine
#  **IF** the robot should be moving,
#  and **WHAT DIRECTION** it should be moving in.
#
    if force == 0 or trigger_1 == 0:
        my_gopigo3.stop()
        print("Robot Stopped. . .\n")

    elif trigger_1 == 1 and y_axis < 0:
        # We're moving forward - either straight, left, or right.
        print("The robot is moving forward and is ", end="")
        
        # if we're not moving directly forward, the inside wheel must be slower
        # than the outside wheel by some percentage.

        # When moving to the left, the left wheel must be moving slower than
        # the right wheel by some percentage, depending on the sharpness of the turn.
        # "set_motor_dps" allows the wheels to be set to individual speeds.
        if x_axis < 0:  #  Moving fowrard to the left
            desired_speed = int(calc_desired_speed(speed, force))
            differential_speed = int(calculate_differential_speed(desired_speed, x_axis))
            my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_RIGHT, desired_speed)
            my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_LEFT, differential_speed)
            print("moving forward to the left\n")

            # Moving to the right, we apply the same logic as before, but swap wheels.
        elif x_axis > 0:  #  Moving fowrard to the right
            desired_speed = int(calc_desired_speed(speed, force))
            differential_speed = int(calculate_differential_speed(desired_speed, x_axis))
            my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_LEFT, desired_speed)
            my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_RIGHT, differential_speed)
            print("moving forward to the right\n")

        else:  # Moving directly forward
            desired_speed = int(calc_desired_speed(speed, force))
            my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_LEFT, desired_speed)
            my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_RIGHT, desired_speed)
            print("moving forward straight ahead\n")

    elif trigger_1 == 1 and y_axis > 0:
        # We're moving backward
        #  This is the exact same logic and calculation as moving forward
        #  Except that it's "backwards" (bad pun!)
        #  We do this by changing the sign of the speed requested.

        # if we're not moving directly backward, the inside wheel must be slower
        # than the outside wheel by some percentage.
        print("The robot is moving backward and is ", end="")

        #  reduce maximum reverse speed to 1/2 forward speed
        speed = speed * 0.5

        if x_axis < 0:  #  Moving backward to the left
            # Moving to the left, the left wheel must be moving slower than
            # the right wheel by some percentage.
            desired_speed = int(calc_desired_speed(speed, force))
            differential_speed = int(calculate_differential_speed(desired_speed, x_axis))
            my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_RIGHT, -desired_speed)
            my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_LEFT, -differential_speed)
            print("moving backward to the left\n")

        elif x_axis > 0:  #  Moving backward to the right
            # Moving to the right, we apply the same logic, but swap wheels.
            desired_speed = int(calc_desired_speed(speed, force))
            differential_speed = int(calculate_differential_speed(desired_speed, x_axis))
            my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_LEFT, -desired_speed)
            my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_RIGHT, -differential_speed)
            print("moving backward to the right\n")

        else:  #  Moving directly backward.
            desired_speed = int(calc_desired_speed(speed, force))
            my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_LEFT, -desired_speed)
            my_gopigo3.set_motor_dps(my_gopigo3.MOTOR_RIGHT, -desired_speed)
            print("moving straight backward\n")

You will have to adjust variable names and such to match your code.

3 Likes

This is what I have done so far I have created in a class MotorModule which determines the speed, turning and timing and then have my PlayStationController class aswell I have tested this and it doesn’t work. I think I may need to change the buttons because the d-pad doesn’t seem to be recognised at all when I press the buttons.




1 Like

@jimrh I’m going to change the buttons to how I had them previously and try again! Because the joystick seems to be recognised by the PyPS4 library. I’ve just tried the ‘on_L3_up’ and it went forward so I’m hoping right and left may run smoother with the added logic that I’ve done in the MotorModule.py

1 Like

Get rid of the gpg= instantiation and the gopigo3.GoPiGo3 import

Change all gpg to GPG
(Then change all GPG to egpg)

Reason: EasyGoPiGo class is derived from the GoPiGo3 class, so all GoPiGo3 class methods are available.

Python conventions:

  • Constants are all caps
  • variables and class instances are lowercase or start with lowercase

If you want a shorter constant name than egpg.MOTOR_RIGHT, I suggest RMOTOR=EasyGoPiGo3.MOTOR_RIGHT

That Motor=MotorModule statement makes me want to lock up your robot in my closet until you complete a Python course. Sorry to have to say it, but that scrambled my brain so much I cannot help you further.

2 Likes

@cyclicalobsessive Ok I didn’t know this I will make these changes to my code now thank you! And I will also check I have the correct Python conventions and make changes to these aswell.

Haha I do apologise for that :sweat_smile:, to be honest this is my first time working with Python I may need to look over some of the basics again. My background is more in Java.

3 Likes

There is a complete Java API library for the GoPiGo3

Perhaps there is a Java lib for the joystick somewhere.

Not too many folks doing GoPiGo3 in Java though. I was forced by employment to endure Java and JavaScript, and was fortunate to be able to say goodbye to all that many years ago.

Wishing you fun and success with your GoPiGo3!

3 Likes

I will have a look at that just to see what it is like. Thank you!

But to be honest I will stick with Python it is a lot more appealing to me and I’ve always wanted to work with it. Java was the first programming language I learned in my Software Engineering degree. Oh really? Yeah Java isn’t my favourite language I’ve worked with :sweat_smile:

Thank you very much!

3 Likes

Re: Programming/naming conventions.

  • Do what makes things easier for you, regardless of what PEP-8 may say.
  • Comments are Your Friend!

With all due apologies to @cyclicalobsessive, my opinion about “naming conventions” is more Calvin and Hobbs than Guido and Python.

If I think it’s a good idea, if I think it’s visually appealing, and if it makes sense to me, I do it.  Otherwise, I do what makes sense to me, regardless of what the “naming conventions” say.  :wink:

The bottom line is that YOU have to read the code, and YOU have to maintain it.

It also depends on who is going to be grading your project.  If this guy is really strict about PEP compliance, then be strict. If he likes Java naming conventions, do it the way he’ll like best.  :wink:
 

With regard to your gamepad:
I found this little gem on-line, (https://gamepadtest.com/), that allows you to use a browser to check and verify that all the analog axes and buttons are doing what you expect them to do.  You can also use it to verify what the joystick and button indexes are.

In my case, I bought a cheap “Ritmix” gamepad. Before I started coding with it, I tried it with the gamepad tester - and boy was it a revelation!

It turned out that:

  • The buttons worked if, and when, they decided they wanted to work - and when they did work, sometimes they stuck “active” and sometimes they didn’t.
  • The joystick axes acted more like buttons than axes - the entire analog effect was within the first 1/3 of the travel of the stick.
  • The button numbering had nothing to do with the “W3C Standard Gamepad” layout.

So, I went out and spent about 4-5 times the money and bought a Logitech gamepad, and the difference was like night-and-day!

  • Button action was smooth and precise.  There was also a nice mechanical “snick!” that you could feel when the button activated.
  • The joystick action was smooth over the entire range of motion.
  • The button and joystick axes were consistent with what you would expect them to be.

Translation:  The difference between a 400₽ gamepad and a gamepad that was more than 2000₽ was massive - being like $5 vs $25 USD - and the quality difference was immense.

I am going to recommend you take a peek at your gamepad online, just to make sure the joystick and button action is smooth and correct.  This way you don’t waste time trying to make your program compensate for a poor quality joystick - or conversely, you can concentrate on your code when you have confidence that your gamepad is working properly.

Here is an illustration I shamelessly stole from the W3C’s “Standard Gamepad” site.  I also changed the colors around, (made it black-and-white), changed the font size and moved a few things around to make them easier to see.

Here’s my “Standard Gamepad” reference diagram that I use primarily to remind me which direction the values of the joystick axes go.


 

As far as classes and stuff is concerned, @cyclicalobsessive is your man.  He probably knows more about that than any five other people here, including - ESPECIALLY including - me.

As far as getting a joystick and a robot talking to each other - that’s something I’m working on and I will be glad to give you whatever help I can.

Keep on Truckin’!

(Don’t loose your faith in yourself!)

3 Likes

Oooh!  I did that too. . .

I had this brilliant brainstorm, (probably helped by a bit of (ahem!) “rocket fuel”, or if you’re in Russia, “anti-freeze”), of changing all the class references from “gopigo3_robot” to “gopigo3” throughout my code - to make it easier to read.  :man_facepalming:

The results were, well, “interesting” and I couldn’t figure out why my beautifully working piece of software had suddenly gone all pear-shaped on me.  What was especially interesting was that there were no exceptions or errors or conflicts or whatever thrown at all - things were just as peachy and calm as the weather in the eye of a hurricane.

When I RE-re-named everything to “my_gopigo3”, things were happy again - and it took me a few moments to figure it out.  (Actually more than a “few” moments if I’m going to be perfectly honest.)

What happened is that my “gopigo3” instance was derived from the EasyGoPiGo3 class, which was, (surprise!), derived from the original “gopigo3” base-class.

I don’t know what the computer was thinking I was telling it to do, but it was interesting!

3 Likes

Haha that is fair enough :sweat_smile: I think I could definitely brush up on Python conventions though. Yes that’s true it is me that will be reading my code I will also add comments aswell.

For my project, my supervisor and an assessor will be grading it. From what I’ve gathered, the implementation is worth 20% and my dissertation is worth 70% and presentation 10%. I don’t think they are really strict with the compliance. I’ll be graded on lots of different things like background research, design documentation, and proving that I have created the Autonomous Car. Whereas one of my modules Embedded Systems will mainly be assessing my C++ implementation. I think my coding is still very important of course but I’ll be assessed on other things aswell.

Oh okay that’s great thank you very much! To be honest the library I used PyPS4 in the github page: https://github.com/ArturSpirin/pyPS4Controller it outlines flaws of the package like ‘not all buttons are recognised’ which I did notice that the d-pad wasn’t working at all so I had to use other buttons that were recognised on the PS4 Controller. There is no harm in double checking though definitely! My supervisor also gave me a PS2 Controller to try :laughing:

That is really annoying though about your gamepad. I feel like with mine it has been very temperamental so I definitely will check out that website! I do have 2 PS4 Controllers so if it is to do with one of them at least I have a backup.

Yes exactly, to be honest i have tested it now and it is working fine but I can always double check my controller and ensure some of the buttons that aren’t registering actually work.

Haha thank you!!!

2 Likes

Remind me what “Autonomous Car” means with respect to this project.

  • Drive from one side of the room to another without catching fire?
  • Drive to the refrigerator and bring back a cold beer?
    https://spectrum.ieee.org/gamma-two-robot-fetches-you-a-beer
  • Drive outside and walk the dog?
  • Drive downtown and buy groceries?
  • Drive itself to your professor’s office and drop off your dissertation?
    (and bring him a beer too? :wink:)

Also remind me, what connection interface are you using?  I don’t know what “ds4drv” is, (Sony PlayStation Dual-Shock 4 - whatever that is), but it sound like poison to me - at least with regard to this gamepad.

Is a wireless gamepad connection required?  In my case, I have my gamepad/joystick connected to my computer via USB so I avoid all the wireless issues.

The way my robot works is that the core functionality is on the robot itself, which connects to my household network via WiFi, and I connect to the robot via a web browser, (a whole different set of problems!), and use my “big” Saitek X52 joystick to drive it around.  Theoretically, (:smirk:), any computer with access to my network, (and another Saitek joystick!) could connect to my robot and drive it around.

I did not implement any kind of Bluetooth control just to avoid the issues that using a wireless gamepad would produce.

Another question:
What is the definition of “success”?  Does it have to drive across the room?  Drive across the room and avoid obstacles like the Professor’s cat?  Or maybe drive across the room, avoid the cat, and bring back fresh cat-treats?

3 Likes

Haha if my car could drop my dissertation off at my supervisors office and then fetch me a gin after that would be great :joy:

The connection interface I am using is ds4drv and is via Bluetooth I watched a YouTube video on the PyPS4 library and the guy who created this library shown how he used it by connecting the controller via Bluetooth using this interface so I assumed I needed to do that. It isn’t always reliable sometimes the controller connects better the closer it is to my car but it always says on the terminal that the ‘signal is very low’.

A wireless controller isn’t required I can use any. My supervisor gave me a wired ps2 pad but he said I can use any. It is only so that I can control the car to drive around a track and collect data from the track.

The main objective for the project is for the Autonomous Car to follow a track. For the track I am just using white A4 paper. I have implemented the rpi camera using OpenCV for image processing and colour detection.

Another feature I need to implement is obstacle detection so when there are objects near the car in front or behind the car will stop. I will implement this part after lane detection. My supervisor told me that a student last year implemented these 2 and got 85%/100.

Optionally and if I have time, I want to implement traffic light detection. So when the light is green the car will go and if the light is red the car will stop. I will have to see though because I’m not too sure if I will have time to do this and it isn’t required for the project but it is something I’d like to do!

Definition of success:

  • Car can drive around a track and identify curves and patterns

  • Car can detect objects, obstacles/avoid collisions

  • Car can detect traffic lights

3 Likes

I’m going to invite @superbam to join us as he’s already done this.

You may want to go check out his thread, he was doing the exact same thing except that he was doing lane detection.

Viz.:

There’s a lot of good information there that may well be useful to you.

3 Likes

I’m doing lane detection in my project aswell. Thank you I will have a look at the thread! :grin:

3 Likes

I don’t know how much of “his work” you can use without getting in trouble for plagiarism, but hopefully this will give you ideas.

Maybe you can/should cite his efforts as a research source?

Side Note:

My how times have changed!  I remember during my freshman year at Virginia Tech, my big (independent) project was wiring up a boot loader circuit that took the place of a stack of punched cards and was used to make a GE-4020 mainframe self-booting.

Today’s projects?
Self driving cars that can avoid obstacles, find the liquor store, know the best sources for weed, and find you a hot date!

Sheesh!

3 Likes

Well, if you use A4 paper as your track, I would recommend you this youtube series:

To track obstacles, you could use a haar cascade, but it’s not very reliable… But I am pretty sure, there are a lot of projects on github that let you detect the state of traffic lights

3 Likes

I’ll have a look at the thread but I wouldn’t copy anything. Yes definitely it will give me ideas for how I’d like to approach mine.

Wow that sounds interesting! I’m only just working with circuits this semester I do enjoy it. For mine I have to make an environmental home monitoring system that monitors temperature, humidity and other things in C++.

Haha yes there is quite a difference :joy:

2 Likes

Oh okay I’ll have a look at that YouTube series thank you!

3 Likes