DexterInd / GoPiGo3

The GoPiGo3 is a Raspberry Pi Robot!
https://gopigo.io
Other
98 stars 85 forks source link

GET_MOTOR_STATUS returns fictional DPS after OFFSET_MOTOR_ENCODER command #336

Open slowrunner opened 1 month ago

slowrunner commented 1 month ago

I do not expect a GoPiGo3 firmware "fix" for this issue - simply documenting the existence of the issue

While the GoPiGo3 API is open-source, available for us to understand to the level of our curiosity, the code that runs inside the “red board” has always required us to use black box testing for any insight.

The Raspberry Pi uses the GoPiGo3 API to send commands across an SPI bus to the red board, and interpret any returned result data. The GET_MOTOR_STATUS_LEFT, and GET_MOTOR_STATUS_RIGHT commands via the gopigo3.get_motor_status() API return:

Returns a list:
            flags -- 8-bits of bit-flags that indicate motor status:
                bit 0 -- LOW_VOLTAGE_FLOAT - The motors are automatically disabled because the battery voltage is too low
                bit 1 -- OVERLOADED - The motors aren't close to the target (applies to position control and dps speed control).
            power -- the raw PWM power in percent (-100 to 100)
            encoder -- The encoder position
            dps -- The current speed in Degrees Per Second

So imagine my surprise when using the gopigo3.reset_motor_encoder() API (which sends an OFFSET_MOTOR_ENCODER SPI command) to see get_motor_status() return non-zero robot speeds, and in fact speeds far exceeding possible GoPiGo3 robot motion.

This is the result when resetting the encoders without moving the robot:

*** started moving
[INFO] [1715963280.121958244] [odometer]: start heading -0.0329 rads
[INFO] [1715963280.122452707] [odometer]: last heading -0.0329 rads
[INFO] [1715963280.123078985] [odometer]: current heading -0.0329 rads
[INFO] [1715963280.123697318] [odometer]: last_point - x: -0.1734 y: 0.0196 z: 0.0000 heading: -1.9
[INFO] [1715963280.124226837] [odometer]: current_point - x: -0.1734 y: 0.0196 z: 0.0000 heading: -1.9
[INFO] [1715963280.124845392] [odometer]: lSpeed,rSpeed: (2823.000,2880.000  lEncoder,rEncoder: (0.0,0.0)  lPwr,rPwr: (-128,-128)   

<<<---- ROBOT IS NOT MOVING BUT REPORTS 2880 DPS or 1.6m/s EQUIVALENT VELOCITY --->>>

[INFO] [1715963280.125430411] [odometer]: start_point - x: -0.173 y:  0.020 z:  0.000 heading:   -2
[INFO] [1715963280.218462322] [odometer]: 
*** stopped moving
[INFO] [1715963280.218914730] [odometer]: start heading -0.0329 rads
[INFO] [1715963280.219304433] [odometer]: last heading 0.0000 rads
[INFO] [1715963280.219889507] [odometer]: current heading 0.0000 rads
[INFO] [1715963280.220388767] [odometer]: start_point - x: -0.1734 y: 0.0196 z: 0.0000 heading: -1.9
[INFO] [1715963280.220965137] [odometer]: lSpeed,rSpeed: (0.000,0.000  lEncoder,rEncoder: (0.0,0.0)  lPwr,rPwr: (-128,-128)
[INFO] [1715963280.221521544] [odometer]: stop_point -  x:  0.000 y:  0.000 z:  0.000 heading:    0 - moved:  0.175 meters in 0.1s

Dave has a maximum measured velocity of 450 DPI which is 0.25 meters per second. There is absolutely no way any GoPiGo3 robot could move at 1.6 m/s. I have seen reported speeds over 5000 DPI returned when resetting the encoders.

The difficulty for Dave comes in trying to correctly identify when Dave is moving. I thought I could use motor_status.dps but the GoPiGo3 redboard is reporting fictional motion when resetting the encoders - bummer.

Manufacturer    :  Dexter Industries
Board           :  GoPiGo3
Serial Number   :  56ECD67E5152415447202020FF192614
Hardware version:  3.x.x
Firmware version:  1.0.0
Battery voltage :  9.868
5v voltage      :  4.979
jharris1993 commented 1 month ago

Have you confirmed this on Carl?

I noticed a similarly strange behavior with Charline - if I start a Python script in Thonny that initializes an instance of the robot, and it the program gets stuck for any reason; and if I either abandon the running instance, or reset the running instance within Thonny, the robot stops responding to attempts to create additional instances of itself.  The only way to resolve this is a reboot.

I have not confirmed this on Charlie yet, but I don't recall anything like this in the past.

I do not know if this is a problem with a Thonny update or a problem with Charline, but it does have me puzzled.

May 17, 2024 8:11:43 PM slowrunner @.***>:

I do not expect a GoPiGo3 firmware "fix" for this issue - simply documenting the existence of the issue

While the GoPiGo3 API is open-source, available for us to understand to the level of our curiosity, the code that runs inside the “red board” has always required us to use black box testing for any insight.

The Raspberry Pi uses the GoPiGo3 API to send commands across an SPI bus to the red board, and interpret any returned result data. The GET_MOTOR_STATUS_LEFT, and GET_MOTOR_STATUS_RIGHT commands via the gopigo3.get_motor_status() API return:

Returns a list: flags -- 8-bits of bit-flags that indicate motor status: bit 0 -- LOW_VOLTAGE_FLOAT - The motors are automatically disabled because the battery voltage is too low bit 1 -- OVERLOADED - The motors aren't close to the target (applies to position control and dps speed control). power -- the raw PWM power in percent (-100 to 100) encoder -- The encoder position dps -- The current speed in Degrees Per Second So imagine my surprise when using the gopigo3.reset_motor_encoder() API (which sends an OFFSET_MOTOR_ENCODER SPI command) to see get_motor_status() return non-zero robot speeds, and in fact speeds far exceeding possible GoPiGo3 robot motion.

This is the result when resetting the encoders without moving the robot:

**** started moving [INFO] [1715963280.121958244] [odometer]: start heading -0.0329 rads [INFO] [1715963280.122452707] [odometer]: last heading -0.0329 rads [INFO] [1715963280.123078985] [odometer]: current heading -0.0329 rads [INFO] [1715963280.123697318] [odometer]: last_point - x: -0.1734 y: 0.0196 z: 0.0000 heading: -1.9 [INFO] [1715963280.124226837] [odometer]: current_point - x: -0.1734 y: 0.0196 z: 0.0000 heading: -1.9

<<<---- ROBOT IS NOT MOVING BUT REPORTS 2880 DPS or 1.6m/s EQUIVALENT VELOCITY --->>>

[INFO] [1715963280.125430411] [odometer]: start_point - x: -0.173 y: 0.020 z: 0.000 heading: -2 [INFO] [1715963280.218462322] [odometer]: *** stopped moving [INFO] [1715963280.218914730] [odometer]: start heading -0.0329 rads [INFO] [1715963280.219304433] [odometer]: last heading 0.0000 rads [INFO] [1715963280.219889507] [odometer]: current heading 0.0000 rads [INFO] [1715963280.220388767] [odometer]: start_point - x: -0.1734 y: 0.0196 z: 0.0000 heading: -1.9

[INFO] [1715963280.221521544] [odometer]: stop_point - x: 0.000 y: 0.000 z: 0.000 heading: 0 - moved: 0.175 meters in 0.1s * Dave has a maximum measured velocity of 450 DPI which is 0.25 meters per second. There is absolutely no way any GoPiGo3 robot could move at 1.6 m/s. I have seen reported speeds over 5000 DPI returned when resetting the encoders.

The difficulty for Dave comes in trying to correctly identify when Dave is moving. I thought I could use motor_status.dps but the GoPiGo3 redboard is reporting fictional motion when resetting the encoders - bummer.

— Reply to this email directly, view it on GitHub[https://github.com/DexterInd/GoPiGo3/issues/336], or unsubscribe[https://github.com/notifications/unsubscribe-auth/AC36Q5ACBZ6U4VUV6S7QHSLZCY247AVCNFSM6AAAAABH4PZHIWVHI2DSMVQWIX3LMV43ASLTON2WKOZSGMYDGMRTGIYTINI]. You are receiving this because you are subscribed to this thread. [Tracking image][https://github.com/notifications/beacon/AC36Q5GHHLAXXD5BOOLIGBTZCY247A5CNFSM6AAAAABH4PZHIWWGG33NNVSW45C7OR4XAZNFJFZXG5LFVJRW63LNMVXHIX3JMTHISSEISE.gif]

slowrunner commented 1 month ago

Fastest GoPiGo3 on Record (9.3m/s)

Confirmed also happens on a 7 year old GoPiGo3 (Carl) - reports traveling at 20 miles per hour briefly! (Wheels actually flinched a little)

pi@Carl:~/Carl $ python3 ~/Dexter/GoPiGo3/Software/Python/Examples/Read_Info.py 
Manufacturer    :  Dexter Industries
Board           :  GoPiGo3
Serial Number   :  BA93EB4F514E3437324A2020FF040B1F
Hardware version:  3.x.x
Firmware version:  1.0.0
Battery voltage :  10.871
5v voltage      :  5.067

To Reproduce: 1) drive GoPiGo a little to ensure non-zero encoders 2) start read_motor_status.py in background

pi@Carl:~/Carl/systests/fictionaldps $ ./read_motor_status.py &
[1] 26443
pi@Carl:~/Carl/systests/fictionaldps $ 
2024-05-17 22:47:34.018234: lSpeed,rSpeed: (0.000,0.000  lEncoder,rEncoder: (45349,-47045)  lPwr,rPwr: (-28,-28)

pi@Carl:~/Carl/systests/fictionaldps $ ./reset_encoders.py 
2024-05-17 22:47:44.488092: resetting encoders

2024-05-17 22:47:44.502749: lSpeed,rSpeed: (-16100.000,-134.000  lEncoder,rEncoder: (0,0)  lPwr,rPwr: (70,70)

2024-05-17 22:47:44.514082: lSpeed,rSpeed: (-16095.000,-130.000  lEncoder,rEncoder: (0,0)  lPwr,rPwr: (-7,-7)

2024-05-17 22:47:44.525271: lSpeed,rSpeed: (-16095.000,-125.000  lEncoder,rEncoder: (0,1)  lPwr,rPwr: (-2,-9)
pi@Carl:~/Carl/systests/fictionaldps $ 
2024-05-17 22:47:44.536336: lSpeed,rSpeed: (-16090.000,-120.000  lEncoder,rEncoder: (1,1)  lPwr,rPwr: (-4,-6)

2024-05-17 22:47:44.547352: lSpeed,rSpeed: (-16090.000,-120.000  lEncoder,rEncoder: (1,1)  lPwr,rPwr: (-4,-6)

2024-05-17 22:47:44.558347: lSpeed,rSpeed: (-16090.000,-125.000  lEncoder,rEncoder: (1,0)  lPwr,rPwr: (-4,1)

2024-05-17 22:47:44.569368: lSpeed,rSpeed: (-16090.000,-125.000  lEncoder,rEncoder: (1,0)  lPwr,rPwr: (-4,-4)

2024-05-17 22:47:44.580344: lSpeed,rSpeed: (-16090.000,-120.000  lEncoder,rEncoder: (1,1)  lPwr,rPwr: (-4,-11)

2024-05-17 22:47:44.591312: lSpeed,rSpeed: (-16090.000,-125.000  lEncoder,rEncoder: (1,0)  lPwr,rPwr: (-4,1)

2024-05-17 22:47:44.602348: lSpeed,rSpeed: (9.000,9.000  lEncoder,rEncoder: (1,0)  lPwr,rPwr: (-4,-4)

2024-05-17 22:47:44.613317: lSpeed,rSpeed: (4.000,4.000  lEncoder,rEncoder: (1,0)  lPwr,rPwr: (-4,-4)

2024-05-17 22:47:44.624303: lSpeed,rSpeed: (4.000,0.000  lEncoder,rEncoder: (1,0)  lPwr,rPwr: (-4,-4)

2024-05-17 22:47:44.635285: lSpeed,rSpeed: (0.000,-4.000  lEncoder,rEncoder: (1,0)  lPwr,rPwr: (-4,-4)

2024-05-17 22:47:44.646332: lSpeed,rSpeed: (0.000,-4.000  lEncoder,rEncoder: (1,0)  lPwr,rPwr: (-4,-4)

2024-05-17 22:47:44.657309: lSpeed,rSpeed: (0.000,-4.000  lEncoder,rEncoder: (1,0)  lPwr,rPwr: (-4,-4)

2024-05-17 22:47:44.668298: lSpeed,rSpeed: (0.000,0.000  lEncoder,rEncoder: (1,0)  lPwr,rPwr: (-4,-4)

read_motor_status.py:

#!/usr/bin/env python3

import gopigo3
import datetime as dt
import time

DT_FORMAT = "%Y-%m-%d %H:%M:%S.%f"
def main():
    try:
        gpg = gopigo3.GoPiGo3()
        lF,lP,lE,lDPS = gpg.get_motor_status(gpg.MOTOR_LEFT)
        rF,rP,rE,rDPS = gpg.get_motor_status(gpg.MOTOR_RIGHT)
        tnow = dt.datetime.now().strftime(DT_FORMAT)
        print_msg="\n{}: lSpeed,rSpeed: ({:.3f},{:.3f}  lEncoder,rEncoder: ({},{})  lPwr,rPwr: ({},{})".format(tnow,lDPS,rDPS,lE,rE
,lP,rP)
        print(print_msg)

        while True:
            lF,lP,lE,lDPS = gpg.get_motor_status(gpg.MOTOR_LEFT)
            rF,rP,rE,rDPS = gpg.get_motor_status(gpg.MOTOR_RIGHT)
            tnow = dt.datetime.now().strftime(DT_FORMAT)
            if (abs(rDPS) > 0 or abs(lDPS) > 0):
                print_msg="\n{}: lSpeed,rSpeed: ({:.3f},{:.3f}  lEncoder,rEncoder: ({},{})  lPwr,rPwr: ({},{})".format(tnow,lDPS,rD
PS,lE,rE,lP,rP)
                print(print_msg)
                time.sleep(0.01)
                lF,lP,lE,lDPS = gpg.get_motor_status(gpg.MOTOR_LEFT)
                rF,rP,rE,rDPS = gpg.get_motor_status(gpg.MOTOR_RIGHT)
                tnow = dt.datetime.now().strftime(DT_FORMAT)
                print_msg="\n{}: lSpeed,rSpeed: ({:.3f},{:.3f}  lEncoder,rEncoder: ({},{})  lPwr,rPwr: ({},{})".format(tnow,lDPS,rD
PS,lE,rE,lP,rP)
                print(print_msg)
            time.sleep(0.01)
    except KeyboardInterrupt:
        pass

if __name__ == '__main__':
    main()

reset_encoders.py:

#!/usr/bin/env python3

import gopigo3
import datetime as dt
import time

DT_FORMAT = "%Y-%m-%d %H:%M:%S.%f"
def main():
    try:
        gpg = gopigo3.GoPiGo3()
        tnow = dt.datetime.now().strftime(DT_FORMAT)
        print("{}: resetting encoders".format(tnow))
        gpg.reset_motor_encoder(gpg.MOTOR_LEFT + gpg.MOTOR_RIGHT)
    except KeyboardInterrupt:
        pass

if __name__ == '__main__':
    main()
slowrunner commented 1 month ago

Interestingly, using the EasyGoPiGo3.reset_encoders() method fictional speeds are reported but the power is set and maintained at 0, so using this method instead of reset_motor_encoder() does not cause the GoPiGo3 to flinch, (and allows my "is_moving" test to ignore the non-zero speeds if the power is 0.