Introduction: A 4WD Robot Driven Via Remote USB Gamepad
For my next robotics project, I was forced to architect/design my own robot platform due to unforeseen circumstances.
The goal is to have it be autonomous, but first, I needed to test its basic driving ability, so I thought it would be a fun side-project to have behave and be controlled as if it were an RC (radio-controlled) vehicle, but instead use a USB Gamepad.
The results have been about as good or better than I expected.
The advantage of going the USB Gamepad route, with lots of programming, is that I can customize it and add onto what I have already done. I don't have any actual experience building an RC vehicle, but I imagine that one is pretty much stuck with whatever the RC transmitter(joysticks/buttons, etc) and the RC receiver come with.
For instance, I have added some recognition that the robot has hit a wall, just by having the software detect high currents and low encoder speed values.
Optionally, one can add some USB webcams to the robot, depending on how many and their placement, one can drive the robot around the living area and into another room, while sitting somewhere else in front of the computer that has the USB Gamepad connected to it.
This Instructable will not be a true, detailed, all-inclusive, step-by-step how-to but I will try to give as much detail as I can.
Suggested Parts: Most of this I obtained from Servo City (Actobotics).
2 - 13.5" U-channels, for the sides of the base frame. The motors are mounted onto this. I went with something shorter and my motors are mounted at the very corners, and it made it difficult to mount them.
2 - 12" U-channels for the front and back of the base frame.
2 - 15" U-channels for the bumpers, front and rear
2 - 7(or was it 7.5"?) U-channels for the front columns. This isn't too critical, the lengths can vary. It depends how tall are the rear columns, and at what height you choose to put the angled U-channel that connects between them.
2 - (length?) U-channels for the angled member, front-to-rear, connecting the upright columns. This one is critical, because Servo City / Actobotics sells 45 degree angled panels or brackets for this purpose, but you'll have to do some math / trig to make sure you get the correct lengths.
2 - (length? ) U-channels to serve as higher-level side bumpers, again these depend on what you do with the base
2 - (length?) U-channels to serve as higher-level front and rear bumpers, ditto issue to above.
1 - (length?) U-channel to serve as topmost member, spans across the rear columns. This one may not be too critical, since you can mount on top, or in front of / behind the upright columns.
12 (aprox) L-channels or brackets. These serve multiple purposes but essentially provide structural integrity/strength to the corners of the base frame AND the upright columns.
4 (+?) 3-hole to 5-hole flat-channels. These also provide structural strength to the robot.
ServoCity sells two main kinds of large-area flat panels, useful for using as bottom skid-pan, or top where your battery and or controllers would go, or even for higher-up surface for sensors.
There's a 4(4.5?)" X 12" panel , and I think the other is a 9(9.5?)" X 12 panel.
Now this is where things get interesting , and may confusing and pricey (small parts add up). All channels, etc, can be attached to each other via these connecting pieces, of which there are SEVERAL. This is where I'm sorry I don't have a comprehensive, detailed, specific parts list.
And the thing is.. you don't really know which ones you might need , or how many.. because there's so many ways you can fit these pieces together.
I can list what I have used:
The following two are very handy, and I would just stock up on these:
Next is all of the screws(bolts). I started with a package of EACH size, and I've gone through most of them. I used longer screws where the size didn't matter, and reserved the shorter ones for where they were REQUIIRED because no other length would work.
Lastly, you should get 1 bag of these:
I didn't use that many, but they (I think) are critical to make sure your motors do not vibrate loose from the frame over time. Only two would work per motor, due to the U-channel
You'll need at least 4 of these, you might get an extra one or so in case you cause damage to one (trust me, you might be putting on / taking off the motors a few times):
Typically, motors shafts are 6mm, and axles are 1/4" (0.25in).
I would get some black screws, supposedly stronger, and use them for the above clamps, and NOT use the screws that come with the clamps:
(I think these are the ones): https://www.servocity.com/6-32-black-oxide-socket-...
4 - 1/4" (0.25") diameter bearings
1 - bag of black 1/4" spacers
4 - Clamping D-Hubs
4 - D-Shafts (#6340621.375" (1-3/8")
4 - 6" heavy duty wheels
Note that I love these wheels but they have a hard rubber edge. They seem to do well on hard floors, and carpet, and probably hard concrete walks. Won't do well on grass, sand, etc.
ALSO, they will tend to smudge your carpet!!!
4 - motors:
I went with the 223 RPM , good top indoor speed, also could move my robot (heavy with 2 SLA 12V batteries) quite easily in slow motion.
2 - motor encoders for the motors. (Servo City's Roboclaw only handles 2 encoders)
1 - Roboclaw 2X45A motor controller, make sure you get the one with the green terminal blocks on it, not the pins.... welll... each have their advantages. Hindsight.. I might have gotten the pins.
I think that's it from Servo City.
SparkFun sells Arduino Uno (that's what I used), and also Redboard Artemis as your drive manager.
You'll want a Raspberry Pi 3 (or 4?) as your high-level "brains" and interface to you.
You'll need wiring, switches, fuses, and a very robust "flyback" diode.
I used a Duracell 12V 14AH deep-cycle SLA battery, but you can use whatever.
WARNING! The design of this robot (TALL, and WIDE, but SHORT), assumes a kind of heavy center of gravity, such as an SLA battery would provide. It may not do well with those other types of newer technology battery packs. LiPo, Lion, etc. It could easily tip over.
From Pololu I got a few barrel plug adapters, so that I could independently power the Arduino and/or the Redboard, even though they would be connected to the Raspberry via USB, because I didn't want to have to rely on the Raspberry's power. (Especially mounting cameras, sensors, etc.)
You'll need a 12-to-5V step down voltage regulator, minimum 5A (?) for the Raspberry. The others can handle anything between 7 to 15V so directly to the SLA battery.
That's about it for parts.
What I would NOT do - 90 degree beveled gearing.
Again, there are many videos in my Robotics youtube playlist detailing most of the above.
Step 1: Construction
Frankly, all of my construction steps are already in the form of youtubes. You can see those in my Robotics playlist, starting at "Wallace Robot 4". The previous ones (Wallace II, Wallace III) also have good material
Step 2: Test the Roboclaw, Motors, and Encoders
The makers of Roboclaw (BasicMicro) have a Windows application that you can use to make sure you wired the motors and encoders correctly to the Roboclaw. You will be hooking up same-side motors in parallel to the Roboclaw. You can choose to use the encoder wires, on only the rear motors, or the front motors, or maybe even better -- DIAGONALLY.
The reason for my suggestion has to do with (later) checking for a stuck robot. Having a status diagonally of if the front/rear wheels are/are not turning might be better than just the front, or just the rear.
NOTE: what I have NOT done is to use the Arduino to also connect (via GPIO pins) to the encoders - if you did that, you could have the Roboclaw handle 2 encoders, and then have the Arduino handle the other two, and just query the Roboclaw for it's two encoder values (and speeds).
NOTE: I used the BasicMicro's application to pre-configure the Roboclaw for Ramping Up / Ramping Down. This is good for protecting the hardware and the electronics. There's a video about that in my Robotics playlist.
I almost forgot : I also bought some bullet-connector cables that go between the motor cables, and the Roboclaw. NOTE: if you do this, you'll notice that the total cable length is REALLY LONG. But I didn't want to have to cut any if I didn't need to. I did (for later steps) encounters communication issues with the USB between the Raspberry and the Arduino, probably due to EMI noise.. but I have worked around that with software.
If it becomes a problem, you can cut wires short - you can also buy metal shielding (from Amazon, 1" diameter).
Last thing: This I have yet to do --- have the Roboclaw auto-configure or auto-tune (using encoders) so that both left and right side motors move at same speed and the robot goes straight.
Mine does curve very slightly over about 12 feet but not enough that I felt the need to do anything about it.
Step 3: Adding and Programming the Arduino
You'll need the barrel plug and some wiring, also a USB cable. Make sure you get the correct one for the Arduino connector.
You'll need to download the Arduino IDE.
Here at Github is the latest sketch that handles driving the robot:
You will connect the Arduino to your computer running the IDE, and based on how the sketch is written, you would be using pins 10 and 11 on the Arduino for serial communications (Software Serial) with the Roboclaw.
I developed a simple communications protocol between the Raspberry Pi and the Arduino.
It's ASCII-character based, which makes it easier to debug and test just using the Arduino IDE's "serial monitor" window.
The commands start at number "0" (zero) and just go up as needed
The commands starting in the "20"s are direct Roboclaw commands, and the ones below that number are strictly Arduino-related commands.
Due to the EMI noise, I improved the command string to include a checksum.
So, any string will include:
# number of tokens in string including this one
Example, say you want the Arduino to respond with it's menu of commands:
4 0 12 16
"4" is four tokens in string.
"0" is the MENU command.
"12" is the random number I chose.
"16" is the sum of 4 + 0 + 12.
That same MENU command could be different:
4 0 20 24
Because I chose a different random number, the checksum is also different.
Example, say you want to move forward at 100 % speed:
5 29 0 134 100
"5" five tokens
"29" the FORWARD command
"0" the random number
"134" the checksum
"100" the parameter 1 (the speed in this case)
If the Arduino can not verify that incoming string, it just drops it / ignores it , no response.
If the Arduino does not receive a next movement command with X milliseconds, it sends a STOP motors to the Roboclaw.
The Arduino starts up and starts sending an auto-status to the USB port... unless told to stop doing that.
At this point you should be ready to try controlling the Roboclaw and watching the motors turn, just by using the "Serial Monitor" on the IDE.
Step 4: Adding and Programming the Raspberry Pi (node.js)
Again, if you take a look at my Robotics playlist, even from the start, I went over every step to get the Raspberry up and running.
The one thing I might have glossed over is that you will need a 5V regulator, and either somehow construct, cut/modify a USB cable for it, or power the Raspberry another way.
Here at Github is everything you need in the Raspberry to communicate with the Arduino via USB.
There are even test scripts.
You can take a look at the node.js server code and you will see how the Raspberry converts the terse numeric instructions, into REST-type url strings. You can use "curl" to send test commands.
http://your RP3 IP address:8084/arduino/api/forward/50
will cause the motors to momentarily rotate the wheels forward.
If you put that in a shell script loop, you would see the wheels keep turning.
The node.js code (server.js) includes a re-connection feature in case serial comms are lost to the Arduino. You can test this by just unplugging the Arduino from the Raspberry, and re-plugging it.
Make sure that you match the serial baud rate between the two.
If you get the test scripts to run and you're seeing the wheels turning, then you're ready for the next step.
Step 5: Final Step - Programming / Using the Web Page Client
Included in the Github link to the Raspberry portion of all this, are the client files.
index.html. index.js. p5.min.js.
They handle the USB Gamepad via the Gamepad API (browser-based) and you should see the various buttons and sliders also available on the web page.
The raw X- and Y-axis values of the joysticks are between 0 and 1.
But the Roboclaw motor controller library function being used in the Arduino to drive the motors, expects a value between -100 to 0 (backward) or (0 to 100) forward.
Soo.... that's the purpose of including the p5.min.js. It just happens to have this very nice, convenient map() function where you give it the raw value, it's raw(current) range, and the new, desired range. And it converts the raw value into the value at the new, mapped range.
Another point: At 100 speed, the robot can be very tricky. I was constantly running into something. But even as you get better at that, it's still touchy when rotating left or right.
Something for you to add would be similar to the current Max Speed slider on the web page. That slider determines what is the highest or max value that you will be mapping the joysticks Xs and Ys to.
Say you are mapping 0 -> 1 to 0 -> 100. When you push the joystick full stop, you're at 100. Touchy. Might be too fast.
But, if you slide that Max Speed slider back a bit, now you're mapping 0 -> 1 to 0 -> 80 or 70.
That means that you have more leeway to move your joystick without such a large change in the speed being sent to the node.js(and to the Arduino).
And addition you could make is to separate the Xs (rotate left or right) from the Ys (forward or backward) into their own max available speeds.
Thus, you could leave the Ys at 0 to 100, 0 to -100 for fast linear motion, but lower the Xs max speed for more controlled rotational movement. Best of both worlds.
Step 6: Optional: Drive Robot With Mouse Drag and / or Touch Events
Further, you know then that while the joysticks' Xs and Ys are negative 1, through zero, to plus 1, those have to be converted between zero and 100. Well, the max depends on the max speed setting on the web page.
Soo... the only thing to do to use either the mouse, or touch events (as on a smartphone), is to capture those events, grab the Xs and Ys.
BUT ---- those Xs and Ys are NOT between negative 1 and 1. They start 0 and increase positively, because they are essentially the pixels or relative screen coordinates of some HTML element (such as a bootstrap panel) or a canvas.
So there again, the P5's Js library's "map()" function is very handy to re-map to what we need.
I refactored the code to have two different web pages, one for desktop using the Gamepad, another one for mobile, using the touch events.
Also, once the Xs and Ys are re-mapped , they are fed into the same chain of code , etc, as are the Xs and Ys from the Gamepad.