Building Andino — Open source robot Part 2 Hardware Assembly & Testing
In previous article we setup the host computer and RPi to make sure we are able to run the robot in simulation mode. In this article, we will focus on hardware build of the Andino robot. The GitHub repo for Andino robot hardware has fairly good diagrams and bill of materials but it doesn’t go into specific details of how to put everything together or assemble things. And the connection diagram is very high level and its going to be very challenging for someone building a robot for first time to make sense of it.
Bill of Materials needed for hardware build of Andino robot with some of my own modifications and comments:
- Raspberry Pi 4 B (4 Gb)
- Chassis 2 x Print 3d Chassis OR you can purchase something like this recommended on github repo WheelsRobot Smart Car Kit. Here is link to my own modified version of chassis plate STL file that uses L-Shape DFRobot motors
- Motors 2 x Hobby Motor with Encoder. Embedded encoders are recommended for better accuracy and reliability. I used DFRobot motors instead of ones recommended on github repo since I already had them and these motors come with built-in Encoders. They have L-shape and I-shape, I have used L-shape and for that I had to redesign my own chasis plates.
- Arduino Uno
- Motor Driver L298N Dual H Bridge
- RPLidar A1M8
- Raspi Camera Module V2, 8 MP
- Powerbank 5V — Any power bank is suitable: Mind size / weight / output current(>=2A). I used two separate batteries — power bank for RPi and a 4xAA battery holder that will generate close to 6V to supply power to motors. This keeps the power for RPi and motors separate so in case motors consume the battery power too much, it will not cause a brown-out for RPi.
- (Optional) Power Step up DC — DC boost converter-If motors support higher voltage than 5V a step-up(e.g: to 9V) can be added between power bank(5V) and motor driver
- Fixing & Mount — M3 bolts/fasteners — M3 Spacers — M2.5/2.0 bolts/fasteners for SBC
- Standoffs of various lengths
In addition, to this you may need a few more things like:
- Additional dupont wires with different combinations male-to-male, female-to-male or female-to-female depending on how you wire it.
- You may need additional standoffs to increase the height between two base plates to make sure you have room to accommodate DuPont wires sticking out of various boards.
- You may need some velcro ties like these or silicone ties like these to make sure batteries are held tightly with the base plate.
- We are doing the wiring purely using dupont wires and screw terminals to keep things simple but you can use more perma boards and solder the wires if you are good with soldering. I’m not great at soldering so I would rather build a PCB and get it printed than solder so many connection points.
High Level plan for Assembly and Testing
The basic assembly requires you to assemble all part in following high level simplified steps to get overview of the process:
- Bottom chassis plate — attach motors to bottom of the bottom chassis plate
- Install RPi4, L298N and Arduino UNO on top of the bottom chassis plate. For UNO I used a different case instead of mounting it directly on the chassis because the case makes the hole pattern more uniform than the weird pattern UNO has by iteself. The link is actually a SCAD file so you’ll need to install OpenSCAD and export the STL file for it.
- Mount Top chassis plate using tall standoffs to clear height of all components and some additional space on top for DuPont wires
- Mount the RPLidar, RPi Camera, RPi battery and motor battery on top of Top chassis plate
Of course, as you are mounting components in each layer you want to start connecting the wires according to the wiring diagram below.
I would highly recommend that you don’t even add the Top chassis plate until you have run all the tests to make sure following things are working:
- While connecting Arduino directly to host computer, you are able to upload and test Arduino program for motor controller and drive motors using serial commands directly against Arduino UNO
- You are able to then connect the RPi and Arduino UNO and repeat the same serial command tests from RPi instead of directly from your host computer
- Finally, you are able to drive motors via joystick control using ROS2
At this point you can add the Top chassis plate and mount RPLidar, RPi Camera and install both batteries. Now, you can test the Robot in mobile fashion not tethered to any cables.
At this point we can actually try doing these things:
- Drive the robot around the room [powered by batteries] using joystick
- Run SLAM to start mapping the surroundings and even save the map
- Finally, use the generated map to do Nav2 based autonomous navigation avoiding obstacles and such
Assembly Instructions and photos
When I was trying to build my Andino robot, I knew I was going to use my own L-Shape motors from DFRobot and the Andino chassis from the git repo was not going to work for me. So I went ahead and built the entire chassis plate from scratch using FreeCAD that I’ll add the STL files to my own fork of the andino git repo. Also, it is difficult to identify where to mount which component so I went ahead and marked holes for each component with color codes in the diagram below. Hopefully, this makes easy for anyone who wants to follow where to mount specific components.
Some additional pointers to keep in mind
- The top and bottom chassis plates are identical and its the same plate printed twice mounted on top of each other separated by a bunch of standoffs.
- UNO has very weird mounting pattern which I originally built it on my CAD design but then decided against it by using a freely available UNO holder that has more rectangular shaped hole pattern so you’ll need to 3D-print that UNO base plate before you can mount that plate on the chassis. You can install OpenSCAD and generate an STL file yourself by downloading design files from here
- For RPLidar I made sure to create dual hole pattern initially not knowing which direction the Lidar is facing so you can use whichever pattern makes it so the bigger rotating cylinder is facing front rounded portion of robot and smaller pulley is facing the backside of the robot.
- The slots in back side are provided to pass through velcro straps or zip ties to hold the batteries for RPi and motor.
- The Caster wheel I used was slightly shorter than the main wheels so I had to 3D Print a spacer to adjust the height of the Caster wheel with the height of the other wheels so that the robot chassis stayed horizontally leveled. This is nice but you can simply use a wooden piece with drilled holes to adjust the height if you don’t want to 3D print it.
- I purchased my RPi Camera from PiHut and I also got mounting plate for RPi Camera, I just had to print a small piece with two holes to attach that mount to front of the chassis. You can simply use a wooden piece or a plexiglass piece with matching holes to achieve this.
The two images below show the mounting holes for various components. The images are not representation of top and bottom chassis plate, just showing it in two separate images where the mounting holes are to mark them clearly. The top and bottom plates are identical copies and you would want to mount as described above in high level plan section. Again, this is what worked for me and its just a guideline, as long as you are able to mount all the components on the plates and still keep robot fairly balanced, that’s what matters.
After you have mechanically mounted the components on bottom chassis plate i.e. motors, RPi, L298N and Arduino UNO, follow the wiring diagram and the table below to make sure you have connected all the components correctly.
If you are using the pin numbers suggested below, you may have to go ahead update the andino_firmware/src/hw.h file to match the pin numbers used.
Another point to remember, if you are testing your motors for more than 3 seconds it may stop the motors as there is a constant named kAutoStopWindow for 3000 millisec timeout defined in the constants.h file. I changed it to 30000 during testing to help me allow sufficient time to test.
Wiring Diagram
Wiring Table
I have used slightly different pin numbers than specified in the Andino repository as these are the pins that worked for me. But it is really easy to change those in the header file of Andino hardware if you decide to use different pin numbers.
Photos during assembly
Testing motors in standalone mode [Directly from Arduino]
Connect host computer [your laptop or desktop] to Arduino UNO using the USB cable. And make sure to upload the andino_firmware to Arduino UNO.
The simplest way to achieve this is by installing platformIO Command line version [you can also do the same using Arduino IDE].
Assuming you have installed platformIO, if not follow the steps here. Make sure to check the baudrate defined in the Constants.h header file within andino_firmware/src/constants.h. The Andino repository has it set to 57600 [when you initiate the connection make sure to use the same baudrate in commands later].
Run following commands when Arduino UNO is connected to the host computer.
# open terminal and switch to andino_firmware directory at andino_robot_ws/src/andino/andino_firmware
# execute following command to upload andino_firmware to Arduino UNO
pio run --target upload -e uno
# after you see sucess message for upload run the following command to connect
pio device monitor -p /dev/ttyACM0 -b 57600
# this will show you a prompt where you can start entering your serial commands
# get encoder readings
e [ENTER]
# run motors forward at 700 ticks/sec
m 700 700
# stop motors
m 0 0
# run motors backwards
m -700 -700
# stop motors
m 0 0
This should confirm direction of spinning for both motors. If the motor direction is not correct, you can exchange the IN pins for M1 or M2 motor to correct it. If the encoder reading sign [+ve or -ve] is not showing same for both motors when moving in the same direction, you can exchange the encoder pins [channel A & B] for that particular motor to make the sign +ve when moving forward and -ve when moving backwards.
Measuring the ticks rate for the motor:
Stick a piece of tape on each wheel approximately at same location. Make sure the motors are connected to Arduino and stopped [and the encoders are powered].
Make sure to send following two commands to Arduino UNO over serial monitor:
r
e
r — command will reset the encoders and e — command followed immediately will print the current values to 0 0 which is what we want.
Now, move the wheel [one wheel at a time] approximately 10 times.
And then run the e command again and note down the values for each wheel. Do the simple math the final tickcount/10 to get the ticks per revolution. You can now get the ticks per second for each motor by referring to specs of the motor [or if you have optical RPM meter you can measure the speed of each motor and multiply ticks per revolution by revolutions per min like this:
tpr [ticks per revolution] — 960 per revolution as shown in specs from DFRobot
rpm [revolution of motor] — 160 rpm as shown in specs from DFRobot
ticks per second = (tpr * rpm)/60 = (960 * 160)/60 = 2560 ticks/sec Max
You can use this as max to test the motors with m command which takes ticks per second for motors.
Testing motors in standalone mode [from RPi]
Now that we have tested the motor controller directly running the motors from Arduino serial monitor commands, we can repeat the same test from Raspberry Pi connected to Arduino. So make sure to unplug the USB cable from your host computer and connect it between RPi USB port and Arduino UNO and then follow these steps:
While you are in root directory of Andino repository on your RPi, build and source the ROS2 workspace.
Note: I have tried using the “o” command as documented in the andino repo but for some reason it doesn’t work so I have stuck to “m” command
colcon build
source install/setup.bash
Run following commands from terminal connected to RPi to test the motors
# 1. get current encoder readings for both motors
motor_driver_demo --serial_port=/dev/ttyACM0 --msg='e'
# output will look like this
Motor driver is connected: True
Waiting 2 seconds for the Microcontroller to be ready...
Sending message: e
Response: 0 0
# 2. move the motors in fwd direction with given tick count e.g. 700
motor_driver_demo --serial_port=/dev/ttyACM0 --msg='m 700 700'
# 3. stop the motors
motor_driver_demo --serial_port=/dev/ttyACM0 --msg='m 0 0'
# 4. move the motors in backward direction with given tick count e.g. -700
motor_driver_demo --serial_port=/dev/ttyACM0 --msg='m -700 -700'
# 5. stop the motors
motor_driver_demo --serial_port=/dev/ttyACM0 --msg='m 0 0'
Testing motors with ROS2 and joystick
In order to test the robot while still on stand [wheels not touching the ground to be safe] via joystick, we will need to launch following commands as described below on RPi to make sure we are able to control the wheels using joystick remotely. To keep things simple the assumption here is you are inserting the USB key for your joystick controller in one of the ports of RPi and you have tested that it is generating the joy command using process described on this blog post.
cd andino_ws
colcon build
# on RPi terminal window 1
source install/setup.bash
ros2 launch andino_bringup andino_robot.launch.py include_rplidar:=false include_camera:=false
# on RPi terminal window 2
source install/setup.bash
ros2 launch andino_bringup teleop_joystick.launch.py
# host computer you can also run rqt from your host computer to see the node graph of all the nodes
rqt&
The rqt graph will look something like this:
as you can see the twist_mux can take input from 3 different sources — teleop_twist, teleop_keyboard and directly from Nav2 via cmd_vel topic. And it can prioritize which command takes priority to send to the final cmd_vel topic.
And here is the video of the robot moving while on stand:
That’s it for this step, in the next article we will actually make the robot mobile and try to do SLAM and Nav2.
Have fun building!!!