Showing posts with label electronics. Show all posts
Showing posts with label electronics. Show all posts

Sunday, 7 April 2024

My Robot is Hardware Complete!

 Finally I have everything assembled and wired up!



I realised my directly soldered wires were prone to snapping off the PCBs, and I needed headers to plug my servo motors into. Just having a pair of signal wires coming of the Motor2040 board was not going to cut it.


My solution was to design some additional brackets to bolt an I2C distribution board onto. A PCB I designed after Pi Wars 2019 but had never actually used on a robot until now.


This board has 4 pin sockets for I2C breakouts, along with some 5 pin sockets intended for the Pimoroni Breakout Garden boards which use a 5th pin for some other signal functions. This 5th pin for each of these sockets is connected to a header on my board. In a flash of inspiration I realised I could cut the power track to these 5 pin sockets, and by sacrificing 2 of these 5 pin outlets I could wire one of the spare 'signal' pins to V+ from the motor supply 6V line and one to GND. Then I could feed the servo supply voltage, GND and the RX and TX signals into this signal header and supply each of the remaining 5 pin sockets with high current power, GND and the signal line needed for the two servos. An extended custom lead crimping session saw the 2 servos converted to custom 5 pin JSH-PH plugs. A custom lead to supply the power and signal inputs to the board, and my servos were connected!

All that remained was to connect up the I2C input to the Motor2040 board and plug in my sensor and IMU and I was done. It was late in the evening the night before my week long family holiday and my robot was read to take away and maybe do some coding on in the evenings. Then the QWIIC socket broke off the Motor2040 board as I plugged in the final connector. I realised I it was too late to take everything apart again, and took the sensible option of going to bed to sleep on the problem.

In the morning, alongside final packing I managed to take apart the robot to remove the Motor2040 board. It has headers which can take a Breakout Garden socket (too large for the space I had) but also due to an extra GND pin on the header, could take a 4 pin JST-XH socket. Genius on the part of Pimoroni, or just good luck? Either way I was able to solder on a socket and crimp up one more custom lead and pack it all in my bag to take on holiday.


Monday, 1 April 2024

Pulling it all together!

 A few more late nights working to assemble my robot. Thankfully the CAD model went together pretty well, with just some minor filing of parts to make them fit together well. I used hot melt threaded inserts in several places which makes it very quick to assemble (and more importantly take apart) when things go wrong.


Here you can see the lower chassis with the Motor2040 board mounted at the front with the battery tray in the middle between the wheels (the battery slides into this). The UBEC sits on top of the middle battery and the USB-C battery pack is on the back, held in place with velcro straps.


The 3D printed Raspberry Pi 5 case sits on top, screwed onto a pair of bars. The screws come up from below and hold the case together, so need to be fitted before the bars are screwed down onto the robot. You can just see the Motor2040 board below the Pi here with an IMU plugged into the QWIIC socket. It was at this point that things started to go wrong. See the yellow wire which has snapped off the IMU board where I had soldered it straight to the PCB. Then I realised my Motor2040 board has no servo headers. I have nowhere to plug in the servos on my grabber!


Some frantic study of the Motor2040 board documentation and schematic revealed no broken out pins from the GPIO. There were some analogue inputs, but it turns out these are for a seperate ADC chip and not the RP2040. Then I spotted the UART pins labelled RX and TX on the board. Looking at the schematic these are directly connected to a pair of GPIOs on the RP2040, and I was not using them for serial communications as I am using the USB socket for that! I clipped my PicoScope probe ground to the USB plug (the only accessible GND point with my board mounted) and found a simple servo driving example for MicroPython. Setting the RX and TX pins as the 'servo outputs' in the example I was able to confirm the PWM output on these pins on the PicoScope. The day was saved!

Wednesday, 13 March 2019

Another Redesign: Electronics Cartridge

One problem I identified with my robot chassis design was that I could not access any of the electronics without taking the whole thing apart. It was not possible to remove the SD Card from the Raspberry Pi without unscrewing the Pi either. One option for the SD Card access which Brian Corteil suggested was to boot the Pi from a USB thumb drive instead. I had not realised this was possible, but some testing with various tiny sized USB memory sticks showed this worked very well (at least with the Pi 3b). But I was still concerned that if I had any wiring problems on competition day it would be difficult to access the internals to fix things.

The idea I had to solve this was to redesign my chassis so that all the electronics were mounted on a plug-in cartridge which could be pulled out of the chassis to easily access everything. This also allowed me to design a second tier to mount breakout boards on above the Raspberry Pi.

CAD model of my electronics cartridge

Having a 2 tier electronics tray posed some problems with how to route the ribbon cable which connects the touch screen display to the Pi. I went through a few iterations before building a prototype cartridge. If I routed the ribbon cable straight up through the upper tier then it limited the space to arrange the breakout boards on that tier. I ended up with a design where the ribbon cable was folded to change the orientation through 90 degrees from the Pi to the display. The fold was contained on the lower tier, which required the height of the lower tier to be higher than originally planned. Space was tight for the upper tier, and I did not take into account the height of the Du Pont connectors used to attach all the wires to the breakout boards. Another redesign of my entire chassis was required to allow another 5mm of head room. I modelled just one Du Pont connector with a wire bending over coming from it (you can see it in the CAD model above) to check I had the required headroom for the wiring.

Redesigned chassis with the electronics cartridge inserted

It all looked great in CAD, but when I came to assemble it I realised I needed a lot longer cables to provide enough slack to actually slide out the cartridge from the chassis. My ribbon cable was not long enough and 40 way ribbon cables seemed very expensive when I looked online at the usual electronics suppliers. Then I remembered somebody had pointed out that IDE hard disk cables in older PCs were just this type of cable. I checked my box of parts for modding PCs and found I had several. They all had 3 connectors, but I simply cut one off close to the middle connector to give a suitable length ribbon cable. All my other Du Pont connector leads I was making myself from a reel of ribbon cable, so I made these long enough to provide some slack.

The reality was that all this extra cable took up a lot of room, and the cartridge was very tightly packed when assembled. It was very hard to slide out due to the cables all catching on bolts, and in hindsight I could have done with another 10mm of head room in the chassis. But I can just about slide it out with a lot of cable wrangling if required to plug in a new lead. I later extended the i2c breakout to a second bus board near the front of the chassis so that I could easily plug and unplug additional ic2 devices mounted on the front of the robot without needing to remove the cartridge.

The assembled electronics cartridge with the multiple folds in the long ribbon cable. Most of the i2c device cables are missing here, apart from one connecting to the PWM breakout used to drive the servos and motor power. The 4 servo cables are also missing here.

Shown with the chassis front and front-side panels removed. The cables completely pack out the space in the cartridge.



Tuesday, 12 March 2019

Robot Software Design

I went for a modular design for my robot software. Python is very modular in structure, with each module importing the modules (or code libraries) it requires. I designed my robot software along the following lines.



Each module does a specific job, and is accessed through a few simple functions which describe the operation being performed. For example the Sensors module contains a function readDistance(sensor) which returns the distance measured by one of the TOF (time of flight) sensors. The parameter (sensor) specifies which sensor (by number) to read. The module also provides the required methods to configure and initialise the sensors, and the i2c multiplexer board they are connected to. So all the complexity of switching i2c buses, turning on sensors and reading them is wrapped up in a module with a very simple code interface.

Another advantage of a modular approach is that you can put all the code which is specific to a set of hardware (e.g. motor controllers) in a single module. The module then presents an interface with simple methods like setMotorSpeed(motor, speed). If you need to change the motor controllers used in your robot, or want to reuse the code on another robot with a similar arrangement of twin motors then you only need to replace this one module and the rest of the code can be reused without changes.

The hardware interface module is called from a module which represents the movement capabilities of the robot. In this case my robot has steerable wheels, and multiple motors wired up in two groups. So the movement control of the robot is wrapped up and controlled through a few simple functions:

  • setLeftMotorPower(speed)
  • setRightMotorPower(speed)
  • setSteering(angle)
  • setSpotTurn(angle)

The LED Matrices module handles setting up and connecting a pair of rgb 5x5 LED matrix breakouts, and displaying patterns on them. A series of patterns are stored in the module and can be called by name. There is also a frame buffer which allows series of patterns to be queued up to show on the LEDs one after the other. Methods can be added to queue up patterns by name. e.g. showBlueEyes() or eyesBlink(). Animations cycle through the frames in the buffer for each display when a nextFrame() method is called.

The main program module handles output onto the main display screen. It also contains all the event handler functions for controller input. A separate module handles detecting different game controllers and mapping their buttons, sticks, hats and triggers to the same named events. So a range of game controllers can be used on the robot and they will all call the same code when their 'triangle button' is pressed.

The main module also contains the code for reacting to touchscreen input to display and navigate through graphical menus, and the main program loop which takes actions based on the mode the robot is in. In this main loop, sensors reading calls can be made, there is the call to display the next frame on the LED matrices, and trigger calls to any event handlers for the connected game controller.

Developing all the code for menus, modes and linking controller input to the robot can be very time consuming when trying to test on the robot itself. But by having the modular structure we can create a virtual copy of our robot, or Digital Twin. By writing a mock copy of each module which interfaces to the actual hardware we can work on the code without the robot being present at all. I did a lot of the coding on a laptop using Raspbian x86 running in a VirtualBox VM. Coding anytime, anywhere. Only the laptop was needed to write, debug and test much of the code.



Just 3 modules (coloured blue above) needed mock versions to the written for the robot to be virtualised. Each of these mock modules has the same name and functions in it as the real version. But the code inside the functions captures the display object from pygame and renders a representation of itself onto the display.

Digital Twin: A virtual representation of the robot
(Background Mars image from Hubble Space Telescope. Credit: NASA)

The mock hardware interface module renders the shape of the robot, and shows the motor speeds and steering leg angles. The mock sensors module generates randomly varying distance readings and renders yellow triangles to indicate the sensor values. The rgb LED matrix mock module renders a representation of each LED matrix onto the screen. I also added an option to display numerical information to aid debugging and diagnosing problems. You can see the virtual robot running in this video clip I posted on Twitter:



The graphical representation of the digital twin of my robot and the sensor output was so useful for debugging issues that I moved it from the mock module into the main robot module. All the graphics slow down the main loop so that it does impair the responsiveness of the robot. So I made it possible to switch on and off via the controller. In normal running the display shows a static graphic of a solar panel, as you can see in this video clip.


(Post Pi Wars 2019 competition I published the full source code for my digital twin robot on github. You can play with my virtual robot using the code on the 'mock' branch. Full instructions and code here: https://github.com/Footleg/PiWars2019/tree/mock )

Monday, 18 February 2019

Pi Wars Robot Electrical Design


The fundamental components I needed for my raspberry Pi based robot were a Raspberry Pi board, a servo driver board and dual motor controllers. On top of this there would be various sensors and a camera. I decided early on I wanted some sort of display and buttons to control a menu system on the display to set the various modes of the robot for different challenges. The display I chose was the HyperPixel 4.0 touch screen display which Pimoroni had just released. This would give me a beautiful full colour display and the touch screen would enable me to use the screen itself to select menu items.

The next decision was how to power the robot. I had learned from other people of the problems with using a power source for the Pi shared with the motors. If the motors draw too much power then the supply to the Pi can dip, causing reboots or crashes. One way to avoid these problems is to provide a completely separate power supplies to the Pi and to the motors/servos. But this is not necessary provided the power supply can provide enough power for all components at their full loads. I decided to use a high discharge current LiPo battery. I planned to use UBECs (Universal Battery Eliminator Circuit) to eliminate the need for different battery voltages. I could supply 5V to the Raspberry Pi using one UBEC, and 6V to my motors and servos using a second UBEC. I already had experience using the cheap Hobbywing 3A 6V/5V switch mode UBEC for robots. These are readily available online (try eBay). I tend to buy 10 at a time from China so I have a stock of them in my parts box ready for projects.

Early prototype wiring to test the servo and motor drivers, powered by a LiPo battery and two UBECs

For the motor drivers, you need to choose some which can supply the voltage your motors require and handle the maximum current which the motors can pull. My robot was using 6V rated micro metal gearmotors with 1:50 ratio gear boxes. According to the listing on the Pimoroni website these have a stall current of 770mA. Stall current is the current the motors will draw if they are fully powered and the shaft is prevented from turning. Typically this can happen if the robot is trying to drive up too steep a slope or into an obstacle which prevents it moving, so all motors could draw this current at the same time. My design had them wired up as 2 pairs of 3 motors in parallel, so I needed a 6V supply to the motors and a maximum stall current of 3 x 770mA = 2.3A. I already had a pair of Adafruit DRV8871 motor driver breakout boards, capable of supplying up to 3.6A per board. The UBEC circuit can supply a steady 3A at 6V so I would need a UBEC per motor driver. I built a test circuit for a single motor and found it did not work. Reading the specifications of the motor driver board again I realised if needed a minimum of 6.5V input voltage. So my UBEC regulating the voltage down to 6V would not work.

Some discussions on Twitter led me to the decision to drive the motors directly off the battery voltage. This could be as high as 8.2V when fully charged, but seeing as the software would limit the motor power using PWM anyway I could set a limit to prevent the motors getting the full power of the battery. They would still be getting peaks of more than 6V during the on-cycle of the PWM signal, but the motors are not such sensitive components that this should be a problem, and I had been advised that these motors could be over-driven safely at these voltages. At a higher voltage I would have more speed, more torque but also a higher stall current. But I would not need a UBEC per motor driver now. The driver boards I had can supply up to 45V to motors, and up to 3.6A so this should work fine.

Next I looked up the HyperPixel touch screen board on the excellent pinout.xyz website to find out which GPIO pins it used on the Raspberry Pi. The answer turned out to be all of them! But it did break out the software i2c bus so I still had the option to control i2c hardware from a Pi using this screen. I was already planning to drive the servos using an Adafruit 16 channel 12 bit PWM servo driver board which is an i2c device, so that should work. But I had no GPIO outputs available on the Pi to drive the motor driver boards. I discussed some options with Brian Corteil of Coretec Robotics at one of the monthly robot club sessions he organises at Cambridge Makespace. These included the following:
  • Use an Arduino to provide some additional PWM outputs
  • Use a second Raspberry Pi to connect sensors and drive the motors
  • Use an i2c GPIO extender breakout board
Then it occurred to me that what I needed to drive my motors were digital PWM outputs, and this is exactly what the 16 channel PWM board I was planning to use to drive my steering servos had in abundance. I built a test circuit on a breadboard to experiment with this. I made a mistake thinking I would drive the servos at 6V, because while the motor driver boards can drive motors at up to 45V, the logic inputs to the board are only rated up to 5.5V. My 6V PWM output damaged one of the boards and I had to replace it. My steering servos were plenty fast enough and strong enough using a 5V supply, so I switched the UBEC supplying power to the servos back to 5V.

The last piece of the puzzle was how to drive multiple laser time of flight distance sensors over i2c when the boards I had chosen (the VL53L1X breakout by Pimoroni) had a fixed address. I read it is possible to switch this address on power up, but this presumably required powering up each sensor board in turn, and that would require more digital outputs which I did not have. An easier solution was to use an i2c board which provides switchable i2c buses, and I chose the TCA9548A I2C MULTIPLEXER from Adafruit.

To connect up all my i2c devices, and supply power to the Raspberry Pi, I made a small power and i2c bus breakout board using strip-board. I built this with 5 pin connectors to match the Adafruit PWM board and Pimoroni range of i2c breakouts which all have 5 pin headers including an interrupt line.

i2c and power bus board

The UBEC supplying power to the Pi and screen was connected to this, and power supplied over the i2c V+ and GND lines to all components. You can see the complete wiring diagram below.


The electrical design for my robot (click to see larger version)

In order to mount the display on top of the robot, I soldered up a right angle GPIO connector using a Pimoroni Pico HAT Hacker board which enabled me to connect the display to the Raspberry Pi using a ribbon cable. I soldered a second 4 wire ribbon cable onto this connector to supply power to both the Pi and the display, and to connect the software i2c bus to my breakout bus board. I was relieved when I connected this all up and saw it working as intended.

Working display and Pi powered via the i2c bus and power breakout board

The next challenge was going to be how to fit all this electrical hardware and connecting wiring into my robot chassis.