Raspberry Pi Pico - Review

Table of contents

RoadTest: Raspberry Pi Pico

Author: robogary

Creation date:

Evaluation Type: Development Boards & Tools

Did you receive all parts the manufacturer stated would be included in the package?: True

What other parts do you consider comparable to this product?: For robotics Parallax BoEBot and Arduino Nano.

What were the biggest problems encountered?: GPIO pins silk screen is on bottom. Had to glue a printout pin chart next to the Pico to track GPIO.

Detailed Review:

I run a robotics and makers club at the local library.

My Road Test Mission: Build a simple robot(s) using RPi Pico, record experience and compare with other beginner robot platforms.

Comparative beginner robot platforms – Parallax BoeBot (Basic Stamp with PBASIC) , Arduino Nano

 

Comparative matrix of RP2020 controllers:  Adafruit & Sparkfun.  MicroBit and CircuitPython weren’t considered for this road test, altho robots can be built with them, they really are better suited for premade accessory boards.

 

Road Test Results In a nutshell:

Raspberry Pi Pico blows previous microcontrollers for robots out of the water !

The analog and PWM resolution is so much better in the Pico, and easy to program. Reliably driving servos and H bridges is a piece of cake !

The book "Getting Started with MicroPython on Raspberry Pi Pico" is very helpful.

I hadnt even got to loading advanced features like  AI or generic I2C shields to the Pico, but it will be on the list.

internally programmed pull up and pull down resistors are really handy !

 

Here is my first pass robot in action: https://youtu.be/7ty-Tb7d824

The second version, named Beetlebot,  can be seen operating at this link: https://youtu.be/wE7IzgW8qr4

Versiion 2 adds a HC-SR04 ultrasonic sensor in the rear for backing up collision avoidance and makes all backup and turning times random,

its acts more like a bug, at least thats what kitty tells me :-) and BeetleBot wont get stuck in corners.

 

 

 

 

 

Tutorials and online references:

https://hackspace.raspberrypi.org/books/micropython-pico

https://www.raspberrypi.org/documentation/rp2040/getting-started/

https://www.tomshardware.com/how-to/program-raspberry-pi-pico-with-arduino-ide  this link has the help to install the Arduino version needed for Pico programming on a Raspberry Pi

https://www.tomshardware.com/news/raspberry-pi-pico-tutorials-pinout-everything-you-need-to-know

To clear out Arduino (or micropython) load on the RPi Pico, use flash_nuke.uf2 , found at :

https://learn.adafruit.com/raspberry-pi-pico-led-arcade-button-midi-controller-fighter/installing-circuitpython

Getting Started with RP2040 – Raspberry Pi

 

 

This is the Thonny Python robot program:

from machine import Pin, PWM

import utime

LHSWhisker= Pin(14, machine.Pin.IN,machine.Pin.PULL_DOWN)

RHSWhisker= Pin(13, machine.Pin.IN,machine.Pin.PULL_DOWN)

 

 

LHSWhiskerLED= Pin(12, machine.Pin.OUT)

RHSWhiskerLED= Pin(11, machine.Pin.OUT)

AliveLED = Pin(25,machine.Pin.OUT)

 

 

LHSservo = PWM(Pin(16))

RHSservo = PWM(Pin(17))

# 50 Hz is 20 msec period

LHSservo.freq(50)

RHSservo.freq(50)

# 100% duty of PWM is 65200 counts

# 2 ms of 20 ms is 10% for full spd FWD

# ( 1.5 ms / 20 ms ) * 65200 = 4875 for servo zerospeed

# 1 ms of 20 ms is full spd rev , .05* 65200

zerospd = 4875

LHS_FullSpd = 3250 # LHS side servo is mounted opposite so gets a reversed reference

RHS_FullSpd = 6500

LHS_TopSpdRev = 6500

RHS_TopSpdRev = 3250

AliveLED.value(1)

 

 

while True:

    AliveLED.toggle()

 

    LHSservo.duty_u16(LHS_FullSpd)  #top speed forward on LHS

    RHSservo.duty_u16(RHS_FullSpd) # top spd fwd on RHS

                            # zerospeed = 4875

    # if no action on the whiakers go straight

 

    if ((LHSWhisker.value() ==0) & (RHSWhisker.value() ==0)):

        LHSWhiskerLED.value(0)

    if LHSWhisker.value() ==1:

        LHSWhiskerLED.value(1)

        LHSservo.duty_u16(LHS_TopSpdRev)  #top speed rev on LHS

        RHSservo.duty_u16(RHS_TopSpdRev) # top spd rev on RHS

        utime.sleep(2)

    # back up tthen right turn

        LHSservo.duty_u16(LHS_FullSpd)  #top speed forward on LHS

        RHSservo.duty_u16(zerospd) # zerospeed on RHS

        utime.sleep(2)

        LHSservo.duty_u16(LHS_FullSpd)  #top speed forward on LHS

        RHSservo.duty_u16(RHS_FullSpd) # top spd fwd on RHS

   

    if RHSWhisker.value() ==0:

        RHSWhiskerLED.value(0)

    if RHSWhisker.value() ==1:

        RHSWhiskerLED.value(1)

        LHSservo.duty_u16(LHS_TopSpdRev)  #top speed rev  on LHS

        RHSservo.duty_u16(RHS_TopSpdRev) # top spd rev on RHS

        utime.sleep(2)

    # turn right

        LHSservo.duty_u16(zerospd)  # zerospeed on LHS

        RHSservo.duty_u16(RHS_FullSpd) # top spd fwd on RHS

        utime.sleep(2)

 

        LHSservo.duty_u16(LHS_FullSpd)  #top speed forward on LHS

        RHSservo.duty_u16(RHS_FullSpd) # top spd fwd on RHS

 

Arduino IDE

MY usual PC: Install Arduino 1.8.15 on my W10 PC, wouldn’t connect COM PORT to Raspberry Pi Pico or compile Arduino example code without errors.

My Raspbeery Pi 3B: Install Arduino 2.1.05 on my Raspberry Pi, then following update instructions on: https://www.tomshardware.com/how-to/program-raspberry-pi-pico-with-arduino-ide.  .

https://www.raspberrypi-spy.co.uk/2020/12/install-arduino-ide-on-raspberry-pi/

Step 5 failed, user “pi” doesn’t exist, but does. Arduino 2.1.05 is so old, it doesn’t resemble the instruction’s screen shots. Uninstall & reinstall per Tom’s instructions. Tried a couple different ways to install, all failed.

              My backup PC: Fresh Arduino load on a different W10 PC that never had Arduino IDE installed, installed 1.8,15.

              Pico GP25 lit, but I had it used as a PU LED, so did BOOTSEL. ISE didn’t see COM port. Recycled connection and it worked for a second ! Pico connected to COM3 ! It errord on upload on Example BLINK. Did a BOOTSEL and NukeFlash. Installed                pico-setup-windows-.0.3.1-x86.exe on PC from Tom’s hardware without positive effect

 

NOTE: Raspberry Pi Pico has 40 pins. It doesnt fit on a177 hole breadboard. A minimum of 400 hole breadboard is needed.

 

 

Robot photos: a 7.4v Lipo powers the robot. A Buck boot power supply converts 7.4 V to 5.5V to a forward biased diode.

The diode output is fed to the Rspberry Pi Pico VSYS. The diode blocks 5V from backfeeding the robot from the Pico USB port when plugged in from the programming PC.

Level shifters are used in between the 3V GPIO pins to the servo 5V signal pins.

 

With a working mobile platform, ping sensors, PixyCams, GPS, QTIs, etc can be easily added to enhance the functionality of the robot.

 

 

 

 

Here is the Pico robot V1  in action: https://youtu.be/7ty-Tb7d824

 

The second version, named Beetlebot,  can be seen operating at this link: https://youtu.be/wE7IzgW8qr4

Versiion 2 adds a HC-SR04 ultrasonic sensor in the rear for backing up collision avoidance and makes all backup and turning times random,

its acts more like a bug, at least thats what kitty tells me :-) and BeetleBot wont get stuck in corners.

 

 

 

This is the V2 python code:

# This code has the BeetleBot run FWD at top spped.

# If the LHS side whisker bumps an object, Beetbot backs up and makes a righthand turn to avoid it.

# The time BeetleBot backs up is random, from 1.5 seconds to 6 seconds,.

# It will stop backing up if an object is detected 7 inches from the

# HC-SR04 ping sensor in the reat of BeetleBot.

# If the RHS whisker encounters an object, the behavior is the same except Beetlebot turns left after backing up.

 

 

 

 

from machine import Pin, PWM

# Pin uses the GPIO value , not the actual pin number

import utime

import random

 

 

LHSWhisker= Pin(14, machine.Pin.IN,machine.Pin.PULL_DOWN)

RHSWhisker= Pin(13, machine.Pin.IN,machine.Pin.PULL_DOWN)

 

 

LHSWhiskerLED= Pin(12, machine.Pin.OUT)

RHSWhiskerLED= Pin(11, machine.Pin.OUT)

AliveLED = Pin(25,machine.Pin.OUT)

 

 

 

 

LHSservo = PWM(Pin(16))

RHSservo = PWM(Pin(17))

# 50 Hz is 20 msec period

LHSservo.freq(50)

RHSservo.freq(50)

# 100% duty of PWM is 65200 counts

# 2 ms of 20 ms is 10% for full spd FWD

# ( 1.5 ms / 20 ms ) * 65200 = 4875 for servo zerospeed

# 1 ms of 20 ms is full spd rev , .05* 65200

zerospd = 4875

LHS_FullSpd = 3250 # LHS side servo is mounted opposite so gets a reversed reference

RHS_FullSpd = 6500

LHS_TopSpdRev = 6500

RHS_TopSpdRev = 3250

AliveLED.value(1)

 

 

PingTrigger=Pin(9,Pin.OUT)

PingEcho=Pin(8,Pin.IN)

 

 

def Ping():

    echotries=0

    PingTrigger.low()

    utime.sleep_us(2)  # note sleep_us is for microsecs

    PingTrigger.high()

    utime.sleep_us(10)

    PingTrigger.low()

    while ((PingEcho.value() == 0) and (echotries<30)):

        EchoStartTime = utime.ticks_us()

        echotries=echotries+1

         # This check bails out of the loop on a problem with a long echo  or failed echo, I havent been able to prove its needed.

       

    while PingEcho.value()==1:

        EchoHeard = utime.ticks_us()

    PingDeltaTime=EchoHeard-EchoStartTime

    PingDistance_cm =(PingDeltaTime*.0343)/2  # sound is 343.2 m/s .0343 cm/usec

    PingDistance_in=(PingDistance_cm)/2.54

    #print ("Measured distance is ",PingDistance_cm, "cm"  )

    print ("Measured distance is ",PingDistance_in, "inches"  )

    #print ("Echotries =", echotries)

    return PingDistance_in

 

 

def backup():

    LHSservo.duty_u16(LHS_TopSpdRev)  #top speed rev on LHS

    RHSservo.duty_u16(RHS_TopSpdRev) # top spd rev on RHS

 

 

 

 

 

 

while True:  #this is start of the main loop routine

    AliveLED.toggle()

     # if no action on the whiakers go straight

    LHSservo.duty_u16(LHS_FullSpd)  #top speed forward on LHS

    RHSservo.duty_u16(RHS_FullSpd) # top spd fwd on RHS

                            # zerospeed = 4875

  

    # if no action on the whiakers go straight, clear LEDs

  

    if ((LHSWhisker.value() ==0) & (RHSWhisker.value() ==0)):

        LHSWhiskerLED.value(0)

        RHSWhiskerLED.value(0)

    

    

      ################ LHS whisker routine, backup and turn right 

        

    if LHSWhisker.value() ==1: #gotta latch this operation

        LHSWhiskerLED.value(1)

        count=1

        while True:  # using break to exit the loop

            backup()

            #Ping()

            PingDistance=Ping()

            utime.sleep(.2)

            count=count+1

            backuptime=random.randint(8,30)  # backuptime is comprised as the number of 200msec cycles before breaking out of the backup loop

            #print ("backuptime = ",backuptime)

            print ("count = ",count)

            print ("backuptime = ",backuptime)

            #print ("LoopCycles= ",Loopcycles)

            if (PingDistance<6):

                break      

            if (count>backuptime):

                break

           # print ("ping distance = ",PingDistance)

          

    # back up tthen right turn

        RHturntime=random.uniform(.5,3)

        LHSservo.duty_u16(LHS_FullSpd)  #top speed forward on LHS

        RHSservo.duty_u16(zerospd) # zerospeed on RHS

        utime.sleep(RHturntime)

      

        #on exit of LHS Whisker routine, go staright again

    LHSservo.duty_u16(LHS_FullSpd)  #top speed forward on LHS

    RHSservo.duty_u16(RHS_FullSpd) # top spd fwd on RHS

      

        ## start RHS side whisker behavior definition

      

    if RHSWhisker.value() ==0:

        RHSWhiskerLED.value(0)

      

    if RHSWhisker.value() ==1:

        RHSWhiskerLED.value(1)

        count=1

        while True:  # using break to exit the loop

            backup()

            #Ping()

            PingDistance=Ping()

            utime.sleep(.2)

            count=count+1

            backuptime=random.randint(8,30)  # backuptime is comprised as the number of 200msec cycles before breaking out of the backup loop

            #print ("backuptime = ",backuptime)

            print ("RHScount = ",count)

            print ("RHSbackuptime = ",backuptime)

            if (PingDistance<6):

                break      

            if (count>backuptime):

                break

           # print ("ping distance = ",PingDistance)

      

    # turn left

        LHturntime=random.uniform(.5,3)

      

        LHSservo.duty_u16(zerospd)  # zerospeed on LHS

        RHSservo.duty_u16(RHS_FullSpd) # top spd fwd on RHS

        utime.sleep(LHturntime)

    

        LHSservo.duty_u16(LHS_FullSpd)  #top speed forward on LHS

        RHSservo.duty_u16(RHS_FullSpd) # top spd fwd on RHS

Anonymous
  • Gary,

     

    Nice robots and good to see the Pico being used in one. I have been meaning to make a whisker mobile robot for a while and even have the switches with whiskers waiting to be used. Maybe I'll have a look soon.

     

    Dubbie

  • As promised, Version 2 enhancements were added, and now the world has BeetleBot !

    The second version, named Beetlebot,  can be seen operating at this link: https://youtu.be/wE7IzgW8qr4

    Version 2 adds a HC-SR04 ultrasonic sensor in the rear for backing up collision avoidance and the code is modified so backup and turning times are random,

    its acts more like a bug, at least thats what Roadtest Kitty Assistant tells me :-) and BeetleBot wont get stuck in corners.

  • I have built several similar robots based on  Arduino Nanos. I love Arduino Nanos.

    I also have a MKR1000 robot, a BoeBot, etc..

     

    My personal inventory of PIRs, ping sensors, servos, sound cards, sensors du jour, etc are mostly 5V.  3V ones are now available.

    The Raspberry Pi Pico can power the 5V devices, but the interface to the GPIO is best to stay with 3V.

    This robot's limit switches were powered from 3V so GPIO pins werent an issue. The servos need level shifters, or some type of interface driver to go from 3V to 5V on the signal control. 

     

    I use that same sensor/accessory inventory with RaspberryPi projects, Arduino Projects, and now Raspberry Pi Pico, and I have level shifters on hand for GPIO. 

    Interestingly enough, when using the Arduino Nano, I sometimes had to add a buck boost set to 5V to power aux devices anyway, and sometimes the sensors and devices ( like a WTV-20 audio player ) needed a 3V external power supply as well.

    About 10 years ago, I had also built interface boards that used optical isolators instead of level shifters, level shifters are more convenient in my opinion, eliminating that current limit resistor for the LED. The opto-coupler tho can drive a higher voltage and current load.

     

    I really have an appreciation for the advantages the Raspberry Pi Pico can add to a design. Not every design needs a Pico either.

     

    In summary, I'd always had to have a way to cope with 5V and 3V sensors and boards, interfacing with 5V and 3V controllers, and various voltages and battery types.  Its just a part of life, not a showstopper. 

  • Recently I was thinking about the chips on the market. Mostly I decided it was AVR8, PIC8, PIC16, and PIC32, and ARM32. and some other chips that aren't used in hobby boards that much.

     

    There definitely is tradeoff for speed. ARM chips have similar pricing to AVR but have faster clocks, more functionality, etc. Harder to solder, harder to flash, most are only 3.3V compliant.

     

    Even worse if you go to 64 bit... most CPUs today operate under 1V(I believe).

     

    Tech is improving way too fast.

  • Did you construct a similar robot with a Nano? If yes, did the GPIO output voltage difference lead to any challenges?

     

    The 3.3 volt output of the Pico causes me concern. I buffer Pi's GPIO to use them in my projects. The 5V output on the Nano eliminates that need.