The Raspberry Pi Thread [6]


  1. Posts : 5,707
    insider build 10586.3 win10 pro 64
       #1601

    do you follow pimoroni on twitter ?
    https://twitter.com/pimoroni
      My Computer


  2. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #1602

    I do, I have a look see almost daily.
      My Computer


  3. Posts : 5,707
    insider build 10586.3 win10 pro 64
       #1603
      My Computer


  4. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #1604

    POE for a Pi has been around for a while. The 3B and 4B have that option. It can be expensive to implement though. The POE Hats plus a special POE switch.
    I saw that new doable NVMe base. One isuue is you can't boot from either one of the NVMe drives. Not with the current Pi 5 firmware anyway.
      My Computer


  5. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #1605

    All I've been doing is trying to read the motor RPM from the Motor Encoders. The read_encoders.py file works, and both encoders show the position from 0 to 360 degrees. So they must be working? Code wise anything else doesn't seem to work though? I have a thread started on the Pimoroni forum. The one who knows this stuff is currently on vacation. One thing that hinders me, at my python skill level; is the examples are over complicated. They do too many things at once. They are great demos of the device, but understanding what's going on in the file can be challenging for beginners. Or even moderate skill users.

    I have one of these on the way, VL53L5CX 8x8 Time of Flight (ToF) Array Sensor Breakout I'm going to use it for collision avoidance.
      My Computer


  6. Posts : 305
    Win 10 and 11
       #1606

    Can you post your code? Maybe I can spot where you are having a problem. After all, I am eventually going to have to do this too with my little robot car. I don't mind looking if you want me to.
      My Computers


  7. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #1607

    Code:
    import time
    import math
    from inventor import Inventor2040W, MOTOR_A, MOTOR_B, NUM_LEDS
    from pimoroni import PID, NORMAL_DIR, REVERSED_DIR 
    from encoder import Encoder, MMME_CPR 
    from encoder import MMME_CPR
    
    HALF_LEDS = NUM_LEDS / 2
    
    GEAR_RATIO = 110
    
    SPEED_SCALE = 6.0
    
    UPDATES = 100                           # How many times to update the motor per second
    UPDATE_RATE = 1 / UPDATES
    TIME_FOR_EACH_MOVE = 1                  # The time to travel between each random value, in seconds
    UPDATES_PER_MOVE = TIME_FOR_EACH_MOVE * UPDATES
    PRINT_DIVIDER = 4                       # How many of the updates should be printed (i.e. 2 would be every other update)
    
    # Multipliers for the different printed values, so they appear nicely on the Thonny plotter
    ACC_PRINT_SCALE = 0.05
    SPD_PRINT_SCALE = 40 
    
    # Acceleration multiplier
    
    POSITION_EXTENT = 180                   # How far from zero to move the motor, in degrees
    MAX_SPEED = 6.0                         # The maximum speed to move the motor at, in revolutions per second
    INTERP_MODE = 0  
    
    # PID values
    
    POS_KP = 0.025                          # Position proportional (P) gain
    POS_KI = 0.0                            # Position integral (I) gain
    POS_KD = 0.0                            # Position derivative (D) gain
    
    VEL_KP = 30.0                           # Velocity proportional (P) gain
    VEL_KI = 0.0                            # Velocity integral (I) gain
    VEL_KD = 0.4                            # Velocity derivative (D) gain
    
    pos_pid = PID(POS_KP, POS_KI, POS_KD, UPDATE_RATE)
    vel_pid = PID(VEL_KP, VEL_KI, VEL_KD, UPDATE_RATE)
    
    board = Inventor2040W(motor_gear_ratio=GEAR_RATIO)
    
    LEFT = board.motors[MOTOR_A]
    LEFT.direction(REVERSED_DIR)
    LEFT.speed_scale(SPEED_SCALE)
    LEFT_enc = board.encoders[0]
    LEFT_enc.direction(REVERSED_DIR)
    
    RIGHT = board.motors[MOTOR_B]
    RIGHT.direction(NORMAL_DIR)
    RIGHT.speed_scale(SPEED_SCALE)
    RIGHT_enc = board.encoders[1]
    RIGHT_enc.direction(NORMAL_DIR)
    
    LEFT.enable()
    RIGHT.enable()
    time.sleep(1)
    
    
    
    # Drive at full positive
    LEFT.speed(6)
    RIGHT.speed(6.0)
    
    board.leds.clear()
    for L in range(LEFT.speed()):
        board.leds.set_rgb(L, 0, 255, 0)
    for R in range(6, RIGHT.speed() + 6):
        board.leds.set_rgb(R, 0, 255, 0)
    
    time.sleep(15)
    capture_LEFT = LEFT_enc.capture()
    capture_RIGHT = RIGHT_enc.capture()
    capture_LEFT
    capture_RIGHT
    print("LEFT Speed =", LEFT.speed())
    print("LEFT RPM =", capture_LEFT .revolutions_per_minute)
    print("RIGHT Speed =", RIGHT.speed())
    print("RIGHT RPM =", capture_RIGHT.revolutions_per_minute)
    accel = vel_pid.calculate(capture_LEFT.revolutions_per_second)
    print("Vel =", capture_RIGHT.revolutions_per_second, end=", ")
    print("Vel SP =", vel_pid.setpoint, end=", ")
    print("Accel =", accel * ACC_PRINT_SCALE, end=", ")
    print("Speed =", LEFT.speed())
    time.sleep(5)# Access the motor from Inventor and enable it
    
    # Stop moving
    LEFT.stop()
    RIGHT.stop()
    
    board.leds.clear()
    for L in range(LEFT.speed()):
        board.leds.set_rgb(L, 0, 255, 0)
    for R in range(6, RIGHT.speed() + 6):
        board.leds.set_rgb(R, 0, 255, 0)
        
    time.sleep(15)
    capture_LEFT = LEFT_enc.capture()
    capture_RIGHT = RIGHT_enc.capture()
    capture_LEFT
    capture_RIGHT
    print("LEFT Speed =", LEFT.speed())
    print("LEFT RPM =", capture_LEFT .revolutions_per_minute)
    print("RIGHT Speed =", RIGHT.speed())
    print("RIGHT RPM =", capture_RIGHT .revolutions_per_minute)
    print("Vel =", capture_LEFT.revolutions_per_second, end=", ")
    print("Vel SP =", vel_pid.setpoint, end=", ")
    print("Accel =", accel * ACC_PRINT_SCALE, end=", ")
    print("Speed =", LEFT.speed())
    time.sleep(5)# Access the motor from Inventor and enable it
    
    board.leds.clear()
    
    RIGHT.speed(3.0)
    LEFT.speed(3.0)
    
    board.leds.clear()
    for L in range(RIGHT.speed()):
        board.leds.set_rgb(L, 0, 255, 0)
    for R in range(6, LEFT.speed() + 6):
        board.leds.set_rgb(R, 0, 255, 0)
    
    time.sleep(15)
    capture_LEFT = LEFT_enc.capture()
    capture_RIGHT = RIGHT_enc.capture()
    capture_LEFT
    capture_RIGHT
    print("LEFT Speed =", LEFT.speed())
    print("LEFT RPM =", capture_LEFT .revolutions_per_minute)
    print("RIGHT Speed =", RIGHT.speed())
    print("RIGHT RPM =", capture_RIGHT .revolutions_per_minute)
    print("Vel =", capture_LEFT.revolutions_per_second, end=", ")
    print("Vel SP =", vel_pid.setpoint, end=", ")
    print("Accel =", accel * ACC_PRINT_SCALE, end=", ")
    print("Speed =", LEFT.speed())
    time.sleep(5)
    board.leds.clear()
    
    
    # Stop moving
    RIGHT.stop()
    LEFT.stop()
    
    
    for L in range(LEFT.speed()):
        board.leds.set_rgb(L, 0, 255, 0)
    for R in range(6, RIGHT.speed() + 6):
        board.leds.set_rgb(R, 0, 255, 0)
    
    time.sleep(15)
    capture_LEFT = LEFT_enc.capture()
    capture_RIGHT = RIGHT_enc.capture()
    capture_LEFT
    capture_RIGHT
    print("LEFT Speed =", LEFT.speed())
    print("LEFT RPM =", capture_LEFT .revolutions_per_minute)
    print("Right Speed =", RIGHT.speed())
    print("RIGHT RPM =", capture_RIGHT .revolutions_per_minute)
    print("Vel =", capture_LEFT.revolutions_per_second, end=", ")
    print("Vel SP =", vel_pid.setpoint, end=", ")
    print("Accel =", accel * ACC_PRINT_SCALE, end=", ")
    print("Speed =", LEFT.speed())
    time.sleep(5)
    
    # Disable the motor
    LEFT.disable()
    RIGHT.disable()
    Gets me this:
    Code:
    >>> %Run -c $EDITOR_CONTENT
    
    MPY: soft reboot
    LEFT Speed = 6.0
    LEFT RPM = -102.5264
    RIGHT Speed = 6.0
    RIGHT RPM = -101.9872
    Vel = -1.699787, Vel SP = 0, Accel = 5.980709, Speed = 6.0
    LEFT Speed = 0.0
    LEFT RPM = -130.1845
    RIGHT Speed = 0.0
    RIGHT RPM = -130.1866
    Vel = -2.169742, Vel SP = 0, Accel = 5.980709, Speed = 0.0
    LEFT Speed = 3.0
    LEFT RPM = -27.2943
    RIGHT Speed = 3.0
    RIGHT RPM = -26.96078
    Vel = -0.454905, Vel SP = 0, Accel = 5.980709, Speed = 3.0
    LEFT Speed = 0.0
    LEFT RPM = -63.22392
    Right Speed = 0.0
    RIGHT RPM = -62.75304
    Vel = -1.053732, Vel SP = 0, Accel = 5.980709, Speed = 0.0
    >>>
    I get different numbers each time I run it, so I have it messed up pretty good.
    pimoroni-pico/micropython/modules_py/inventor.py at main . pimoroni/pimoroni-pico . GitHub
    pimoroni-pico/micropython/modules/encoder at main . pimoroni/pimoroni-pico . GitHub
      My Computer


  8. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #1608

    @Catnip. I can control the motor speed no problem, near as I can tell anyway. They look to be turning in the correct direction and the correct speed. Where things fail is trying to read the rpm etc from the encoders. The files I'm looking at for code are here.
    pimoroni-pico/micropython/examples/inventor2040w/motors at main . pimoroni/pimoroni-pico . GitHub

    This works, it shows the correct orientation as I turn the wheels.
    pimoroni-pico/micropython/examples/inventor2040w/read_encoders.py at main . pimoroni/pimoroni-pico . GitHub

    Other examples don't work though, and do odd things etc, but don't throw up any error messages?
      My Computer


  9. Posts : 305
    Win 10 and 11
       #1609

    [QUOTE=alphanumeric;2618860]
    Code:
    import time
    import math
    from inventor import Inventor2040W, MOTOR_A, MOTOR_B, NUM_LEDS
    from pimoroni import PID, NORMAL_DIR, REVERSED_DIR 
    from encoder import Encoder, MMME_CPR 
    from encoder import MMME_CPR
    
    HALF_LEDS = NUM_LEDS / 2
    
    GEAR_RATIO = 110
    
    SPEED_SCALE = 6.0
    
    UPDATES = 100                           # How many times to update the motor per second
    UPDATE_RATE = 1 / UPDATES
    TIME_FOR_EACH_MOVE = 1                  # The time to travel between each random value, in seconds
    UPDATES_PER_MOVE = TIME_FOR_EACH_MOVE * UPDATES
    PRINT_DIVIDER = 4                       # How many of the updates should be printed (i.e. 2 would be every other update)
    
    # Multipliers for the different printed values, so they appear nicely on the Thonny plotter
    ACC_PRINT_SCALE = 0.05
    SPD_PRINT_SCALE = 40 
    
    # Acceleration multiplier
    
    POSITION_EXTENT = 180                   # How far from zero to move the motor, in degrees
    MAX_SPEED = 6.0                         # The maximum speed to move the motor at, in revolutions per second
    INTERP_MODE = 0  
    
    # PID values
    
    POS_KP = 0.025                          # Position proportional (P) gain
    POS_KI = 0.0                            # Position integral (I) gain
    POS_KD = 0.0                            # Position derivative (D) gain
    
    VEL_KP = 30.0                           # Velocity proportional (P) gain
    VEL_KI = 0.0                            # Velocity integral (I) gain
    VEL_KD = 0.4                            # Velocity derivative (D) gain
    
    pos_pid = PID(POS_KP, POS_KI, POS_KD, UPDATE_RATE)
    vel_pid = PID(VEL_KP, VEL_KI, VEL_KD, UPDATE_RATE)
    
    board = Inventor2040W(motor_gear_ratio=GEAR_RATIO)
    
    LEFT = board.motors[MOTOR_A]
    LEFT.direction(REVERSED_DIR)
    LEFT.speed_scale(SPEED_SCALE)
    LEFT_enc = board.encoders[0]
    LEFT_enc.direction(REVERSED_DIR)
    
    RIGHT = board.motors[MOTOR_B]
    RIGHT.direction(NORMAL_DIR)
    RIGHT.speed_scale(SPEED_SCALE)
    RIGHT_enc = board.encoders[1]
    RIGHT_enc.direction(NORMAL_DIR)
    
    LEFT.enable()
    RIGHT.enable()
    time.sleep(1)
    
    
    
    # Drive at full positive
    LEFT.speed(6)
    RIGHT.speed(6.0)
    
    board.leds.clear()
    for L in range(LEFT.speed()):
        board.leds.set_rgb(L, 0, 255, 0)
    for R in range(6, RIGHT.speed() + 6):
        board.leds.set_rgb(R, 0, 255, 0)
    
    time.sleep(15)
    capture_LEFT = LEFT_enc.capture()
    capture_RIGHT = RIGHT_enc.capture()
    capture_LEFT
    capture_RIGHT
    print("LEFT Speed =", LEFT.speed())
    print("LEFT RPM =", capture_LEFT .revolutions_per_minute)  White space violation?
    print("RIGHT Speed =", RIGHT.speed())
    print("RIGHT RPM =", capture_RIGHT.revolutions_per_minute)
    accel = vel_pid.calculate(capture_LEFT.revolutions_per_second)
    print("Vel =", capture_RIGHT.revolutions_per_second, end=", ")
    print("Vel SP =", vel_pid.setpoint, end=", ")
    print("Accel =", accel * ACC_PRINT_SCALE, end=", ")
    print("Speed =", LEFT.speed())
    time.sleep(5)# Access the motor from Inventor and enable it
    
    # Stop moving
    LEFT.stop()
    RIGHT.stop()
    
    board.leds.clear()
    for L in range(LEFT.speed()):
        board.leds.set_rgb(L, 0, 255, 0)
    for R in range(6, RIGHT.speed() + 6):
        board.leds.set_rgb(R, 0, 255, 0)
        
    time.sleep(15)
    capture_LEFT = LEFT_enc.capture()
    capture_RIGHT = RIGHT_enc.capture()
    capture_LEFT
    capture_RIGHT
    print("LEFT Speed =", LEFT.speed())
    print("LEFT RPM =", capture_LEFT .revolutions_per_minute)  White space violation?
    print("RIGHT Speed =", RIGHT.speed())
    print("RIGHT RPM =", capture_RIGHT .revolutions_per_minute)  White space violation?
    print("Vel =", capture_LEFT.revolutions_per_second, end=", ")
    print("Vel SP =", vel_pid.setpoint, end=", ")
    print("Accel =", accel * ACC_PRINT_SCALE, end=", ")
    print("Speed =", LEFT.speed())
    time.sleep(5)# Access the motor from Inventor and enable it
    
    board.leds.clear()
    
    RIGHT.speed(3.0)
    LEFT.speed(3.0)
    
    board.leds.clear()
    for L in range(RIGHT.speed()):
        board.leds.set_rgb(L, 0, 255, 0)
    for R in range(6, LEFT.speed() + 6):
        board.leds.set_rgb(R, 0, 255, 0)
    
    time.sleep(15)
    capture_LEFT = LEFT_enc.capture()
    capture_RIGHT = RIGHT_enc.capture()
    capture_LEFT
    capture_RIGHT
    print("LEFT Speed =", LEFT.speed())
    print("LEFT RPM =", capture_LEFT .revolutions_per_minute)  White space violation?
    print("RIGHT Speed =", RIGHT.speed())
    print("RIGHT RPM =", capture_RIGHT .revolutions_per_minute)  White space violation?
    print("Vel =", capture_LEFT.revolutions_per_second, end=", ")
    print("Vel SP =", vel_pid.setpoint, end=", ")
    print("Accel =", accel * ACC_PRINT_SCALE, end=", ")
    print("Speed =", LEFT.speed())
    time.sleep(5)
    board.leds.clear()
    
    
    # Stop moving
    RIGHT.stop()
    LEFT.stop()
    
    
    for L in range(LEFT.speed()):
        board.leds.set_rgb(L, 0, 255, 0)
    for R in range(6, RIGHT.speed() + 6):
        board.leds.set_rgb(R, 0, 255, 0)
    
    time.sleep(15)
    capture_LEFT = LEFT_enc.capture()
    capture_RIGHT = RIGHT_enc.capture()
    capture_LEFT
    capture_RIGHT
    print("LEFT Speed =", LEFT.speed())
    print("LEFT RPM =", capture_LEFT .revolutions_per_minute) White space violation?
    print("Right Speed =", RIGHT.speed())
    print("RIGHT RPM =", capture_RIGHT .revolutions_per_minute) White space violation?
    print("Vel =", capture_LEFT.revolutions_per_second, end=", ")
    print("Vel SP =", vel_pid.setpoint, end=", ")
    print("Accel =", accel * ACC_PRINT_SCALE, end=", ")
    print("Speed =", LEFT.speed())
    time.sleep(5)
    
    # Disable the motor
    LEFT.disable()
    RIGHT.disable()
    Gets me this:
    Code:
    >>> %Run -c $EDITOR_CONTENT
    
    MPY: soft reboot
    LEFT Speed = 6.0
    LEFT RPM = -102.5264
    RIGHT Speed = 6.0
    RIGHT RPM = -101.9872
    Vel = -1.699787, Vel SP = 0, Accel = 5.980709, Speed = 6.0
    LEFT Speed = 0.0
    LEFT RPM = -130.1845
    RIGHT Speed = 0.0
    RIGHT RPM = -130.1866
    Vel = -2.169742, Vel SP = 0, Accel = 5.980709, Speed = 0.0
    LEFT Speed = 3.0
    LEFT RPM = -27.2943
    RIGHT Speed = 3.0
    RIGHT RPM = -26.96078
    Vel = -0.454905, Vel SP = 0, Accel = 5.980709, Speed = 3.0
    LEFT Speed = 0.0
    LEFT RPM = -63.22392
    Right Speed = 0.0
    RIGHT RPM = -62.75304
    Vel = -1.053732, Vel SP = 0, Accel = 5.980709, Speed = 0.0
    >>>
    Thanks for posting the code. I don't see anything immediately wrong with this, but I suspect that the "revolutions per minute" method is what is giving you trouble. For one thing, your RPM is negative (or did you want that?). Also, there is a random function in the "rev per minute" method that may be setting the start point to a random number, as near as I can tell. I also highlighted what I think are whitespace violations in the above code. Have a look and see if you agree. I have bolded my comments.

    I will write this in pseudocode, but this is more or less what I would do:
    Code:
    # set up everything as you have (motor speed, direction, etc.)
    
    # verify the angular distance in degrees for the encoder wheel that you are using (I assume that it is optical)
    # How many slots are in the encoder wheel?  Divide 360 by that number.  That is your angular distance in degrees
    # make a constant to hold the zero point of the encoder wheel.  If it gets to 360 degrees, it must be set back to zero for the next set of counts.  360 and zero are the same point on the wheel.
    # make the code able to differentiate between forward and reverse by using positive numbers for forward and negative numbers for reverse.  The RPM function has to be able to deal with those negative numbers
     #then:
    
    angular_distance = whatever the angular distance is
    slot_count = the number of slots in the wheel, this becomes counts per rev
    revolutions = holder for the revolutions count  (this is a variable)
    pulses = the pulses from the encoder wheel  (variable is used here)
    
    def getRPM(which motor, motor speed, direction... etc...)
         while()  # make a loop in python that will go on until you decide to stop it for testing purposes
              # you can use a timer here to measure the time in one revolution
              # start timer
              pulses += GetPulse(encoder)
              if pulses == slot_count:
                   #stop timer
                   RPM = 60 seconds / timer_value  #this gives your approximate RPM
                   pulses = 0  # reset the pulse count here
                   #reset timer
                   #print the RPM somewhere
    
               # if the method falls through to here it means that the pulse count does not equal a full revolution and will go through the loop again until it gets a full revolution
    I hope the above makes sense. My python is not so good (improving, but not so good) but to me, that is the easy way. The examples use trigonometry to work out the RPM. You could use trig to be more precise, but it is a bit more involved and I am not sure how to do it without a setup here of my own to experiment on. I have some encoder sensors coming from DigiKey, but it will be a little bit before I get them set up.

    Anyway, mess around with my pseudocode and see if you can get an actual python method to count the RPMs properly. Let me know how it goes and I will think about this some more.

    Good luck.
      My Computers


  10. Posts : 15,037
    Windows 10 IoT
    Thread Starter
       #1610

    The -rpm just means it thinks the motors are running in reverse. You can set the speed from -6 to +6. The default value is -1 to +1, if you don't set a speed scale. I want to use 6 RGB LED's for each motor as RPM indicators. So I set my speed scale to 6. I may go back to 1 for further testing though. I can reverse the encoder direction to get + numbers. I have the left motor set to reverse direction, and should be doing the same for it's encoder. Thanks for the code, will be tinkering with this over the weekend.
      My Computer


 

  Related Discussions
Our Sites
Site Links
About Us
Windows 10 Forums is an independent web site and has not been authorized, sponsored, or otherwise approved by Microsoft Corporation. "Windows 10" and related materials are trademarks of Microsoft Corp.

© Designer Media Ltd
All times are GMT -5. The time now is 11:35.
Find Us




Windows 10 Forums