April 27, 2025
Description
A circular structure covers a 4 wheel car chassis with Mecanum wheels. The Mecanum wheels enable the plate to move in any direction.
When the plate is pushed from any side, a sensor measures the direction of the push. The direction is translated to commands to the four Mecanum wheels, which will move the whole thing to that direction.
The robot is connected to the Arduino Cloud, which enables remote control using a smartphone.
Without further ado, here's something to look at.
This is Snootybug in modest action. I don't want to scare Tessa with a fully responsive and noisy Snootybug. She needs to gain trust. First she learns that Snootybug can give treats. Then she learns that Snootybug can move.
The robot car is set to travel 30 cm at each push. The task for your dog is to nod the robot to move to a marked spot on the flor. When the robot reaches the spot, you push a button on the remote and the robot gives a treat to your dog.
The robot performs a similar task, but now it moves without stop. At each nod or a hit against a wall or furniture, it changes direction. You can always make it stop using the remote.
Just control the movement of the robot using your phone as a remote, teaching your dog to play with it and make your dog bond with the robot using the remote controlled treat dispenser. Come up with new tricks and stunts on the fly.
A robot car chassis with Mecanum wheels is used.
The chassis is covered with a 3D printed cylindrical object, which hides the wheels. I refer to this part as the bottom plate. Some electronics is attached to the chassis, some to the bottom plate. The bottom plate will also include the treat dispenser.
The top plate lies on top of the bottom plate. With the help of six special designed “plate bearings”, the top plate can slide in any direction, some 14 mm.
In the video, I have three of all 6 plate bearings in place and the sliding works perfectly already. The final design has three more bearings to add stability. I'll also add rubber strings to make the top plate return to its central position after a push.
The plate bearing in action.
The idea is to read how much the top plate has been pushed and in what direction. For this I use Infineon's TLI493D sensor. More specifically, the 3Dsense Shield2Go board. It will be placed on the bottom plate with the sensor element at the center hub. A magnet is attached to the top plate. The sensor gives exact information about how the magnet moves above the center of the hub.
The dashboard for the robot has pushbuttons for moving in 8 directions, and a stop button. Each push on the button adds a velocity unit in that direction. Full speed requires about 10 pushes. Any push extending the max speed will result in truncating to the max speed.
Three switches work like radio buttons, turning each other off when activated. They define in which mode the robot operates:
The Treat function is active all the time. Pushing it will make the treat slider move back and forth once. The speed slide sets the maximal speed of the robot. The time slide sets the time the robot moves at each push, when in Timed movement mode.
The bottom plate seen from below. It needs to be cut in two in Slicer to fit on the printer bed. Four poles with hexagonal holes fit perfectly to the robot car chassis. The hole in the middle enables the magnetic sensor to stick up and reach a magnet attached to the top plate.
A small funnel is situated in the bottom plate and filled with treats. The bottom of the funnel drops a treat or two into a cylindrical cavity of a slider. The slider lies on top of a stopper plate. When the slider moves sideways with the force from a servo motor, a part of the slider blocks the bottom hole of the funnel while the cylindrical cavity sticks out from the side of the bottom plate and drops the treats on the floor. The slider slides back and a new treat falls into the cylindrical cavity. This mechanism is activated by a push on a button on the phone.
The treat dispenser viewed from underneath.
a) is the funnel, which will be filled with treats.
b) is the slider, rotated by the servo (d).
c) is a plate preventing the treats from falling on the floor, when the hole in the slider is in line with the funnel hole.
e) is the opening for the slider to slide out.
I used Pinta to draw the following sketch:
This is made in Pinta, but any pixel based graphic editor will do (Paint.net, Gimp…). I read this image into Inkscape and did a Trace Bitmap. I got this:
To the left I have the pixel image from Pinta. To the right I have the traced bitmap. I used the following settings in Inkscape, when tracing the bitmap:
The essential settings are:
I encourage you to explore the Stack setting. One could indeed have the different colours stacked and do the separation in Tinkercad, using a copy of the top most layer to cut away from a lower layer. I won't go further into that.
In Inkscape I can do further editing, like resizing the eyes to get them more even. I won't go further into the marvelous features of Inkscape. This is the final image in Inkscape:
This is all vector graphics. The left image shows black and red areas according to the final print. The right image shows the contours of the areas, to show that it's all vector graphics.
These are all read into TinkerCAD as SVG graphics. The top plate got this graphic on the topmost layer. To make a beautiful surface of it, I printed everything upside down, so that the graphics got printed against the printer bed.
From Inkscape I exported all black objects as a single svg file. I did the same with all red objects. I imported both files into TinkerCAD and got this:
I needed to align the objects with each other. These two objects were then placed on the top plate. I used a copy of these two objects to make a hollow object to carve out the same shape on the top plate:
Snootybug, as viewed in TinkerCAD. Here we have three objects. A white, a black and a red object. They don't overlap each other, but sit next to each other. They must be read into the slicer program as separate objects. The slicer program must slice the whole print so that each object prints completely in one turn. When the top surface of the plate is placed gainst the print bed, we wish for the red to be printed first, then the black, then the white. We need to add breaks in the G code for changing the filament. After changing from black to white, we can leave the printer to finish the whole print with white. Depending on how high the black and red objects are, the images might extend to the next layers. But I didn't add breaks for colour change at the next layers, which can be seen as white colour coming through at some spots at the black and red areas. But each layer lasts an hour to print, so it would require a lot of standing by to perform the filament change.
The top plate needs to be cut in 3 pieces to fit the printer bed! Think of it as a cake, which must be cut in 3 sectors, 120 degrees of each. The Prusa Slicer can't perform such cuts. It only cuts in two at a time. So I did the cut in TinkerCAD. Besides, having the graphics there as two separate objects made it even harder to cut using the Prusa Slicer. Someone please comment if you have an idea how Prusa Slicer could do it. Anyway, here we go:
The difficult thing is to cut the plate into three parts, where the black, red and white parts still are three separate parts to be imported into Prusa Slicer. If each third of the plate is imported as one multicoloured piece, the colour info is lost. Importing one stl file is importing one colour! (Again, someone might know more than I.)
Here I have imported the black and the red parts of the mouth third of the top plate:
From this view they look mirrored, because I rotated them after importing them. Importing the white part:
The white part turned blue, marking that it goes over the edges. I have to line up all three parts perfectly, then I group them, then I rotate the whole chunk to fit over the print bed.
After fitting the whole part on the print bed, slicing will reveal how the first layer will be drawn:
After 854 lines of G code, the tongue is completed (the only red part in this piece. That means I can load the printer with red filament in the beginning. I need to add a line in the G-code after line 855 to make the machine ask for a filament change. The Prusa Slicer can't add colour changes within one layer, only after one completed layer (got to do a feature request about that). So I need to edit the produced G-code by hand, using Notepad++.
After the tongue, the code continues with the file named “cut into three(2)”, which is the white part. I had hoped for the black part. Anyway:
At line 7436 in the code, the white part is completed and the black areas are to be printed (with file name “cut into three(1)”). That means another colour change code has to be injected here.
Seems there are 5 layers of the black and red parts:
I should have made them thinner in TinkerCAD because I intend to change colours only on the first layer. But it doesn't actually matter. I'm counting on the final print being strong enough. If I want to assure thick and clear colour areas, I would add filament changes in the 2nd and maybe the 3rd layer, too. But that would mean hours of standing by the printer.
Unfortunately I decided to print this part with a brim, thinking I could easily remove the brim. But due to the rounded edge, the brim melted into the rest of the piece. And I started this print with the red filament, having only the tongue in mind. This led to an ugly red rim in this 3rd of the top plate, visible in the video at the right edge. Unless I find a way to carve away the red rim, I have to paint it over with something.
Detail of the print. The red and the black are single layers, the rest is white.
The tongue was printed 2 layers in red, which gave the colour a deeper and fuller tone. The red filament that I used was transparent.
All three parts forming the top plate. The red rim needs cosmetics. The seams between the three parts might need some filling and some make up.
B1: A battery pack of 4 * AA batteries. To be replaced by something more powerful in the future. The 6V battery pack powers the servo motor and the four wheel motors.
B2: A 3.7 V LiPo battery powers the Arduino.
U10: A double switch to control the power from the two separate batteries.
U3 and U4: L9110S motor drivers.
U1: An Arduino MKR1010. Might as well be a MKR1000. Or any Arduino. Just take care that all 8 pins to the motor drivers are PWM pins. The L9110S accepts two PWM pins. When one pin is high and the other is low, the motor runs in one direction. Reverse both pins to run in opposite direction. This means that running on a reduced effect, the pin being high must be PWM. The circuit shows erraneosly that the board is powered through the Vin pin. Instead I use the JST connector of the MKR1010.
U5 to U8: The motors with the Mecanum wheels. As usual with connecting motors to motor drivers, we could take extra care of connecting everything according to some schematics. And then write the code to make everything rotate as it should. But since I know I would get it wrong no matter what, I just connect everything one way. Then I run some test code to actually figure out which commands I need to perform a rotation in a desired direction. The final adjustment to get it right is done in code, not by switching wires.
U9: The TLI493D magnetic sensor.
M1: A hobby servo motor. The servo takes care of the treat dispenser. The mechanism is dependable on the treats falling neatly down through a funnel. A treat might jam the flipping part, therefore this part is controlled only manually with an open/close switch. Testing is needed to see what kind of treats works the best. If I find the perfect treat that never jams and always gets dispended, the treat dispending can be automated in future dog activating programs.
So you jumped straight here to check what the friendly! Ok, let's ditch the term for a start. It's just a hot glue gun, the purpose of which is to create some objects from the hot glue being extruded from the gun. What I want is a light tube going from the RGB LED of the Arduino MKR1010 board to a hole in the side of the bottom plate. The Arduino is attached to the bottom plate, but there will be a gap between the RGB LED and the cylindrical wall of the bottom plate. A light tube will gather the light from the LED and lead it to a small bulb. The tube and the bulb will all be hot glue.
To make a perfect light tube out of hot glue, the glue needs to be run through the gun to get it melted and to get it extruded as a perfect tube. Melting makes the glue clear as molten glass. But the glue needs to be instantly cooled down before it gets deformed too much. It needs to have more or less a perfect tube form. The magic is in total reflection. Once we get light to shine along the tube, the light won't escape from the tube until it hits the end of the tube. Well, that's the theory.
To cool down the molten glue, I extrude it straight into water. Unfortunately the glue floats and forms a floating string of molten glue, which loses its circular cross section shape before it hardens enough. To get it right, I trned off the heater of the glue gun and let it cool down, testing all the time when the temperature was perfect. I also had the gun tip submerge into water to let the molten glue cool down evenly.
Here are some test “prints”:
From all test “prints”, I found a suitable piece of tube to fit between the Arduino MKR1010 and the bottom plate.
As I design while I make progress, I didn't have a hole for the light tube, so I drilled it. The piece of tube stuck out about 1 mm and worked fine as such:
If the tube had been perfectly clear, the light wouldn't dissipate at the surface of the tube, only at the end. But the light is still very bright at the end.
The light was so strong that I thought I'd add a big glue blob at the end, which turned out very well. This light can now be used to show different modes of the robot. It will blink in amber while it is making the WIFI connection and the connection to the Arduino Cloud. It will flash in green, when everything is ready. It will… well, you get the point.
Here I test the phone interface and the RGB light, changing from one mode to another. Then I activate the treat dispenser - which is on the opposite side of the bottom plate, but you can hear it. (The red rim of the top plate has got its white paint!)
All 3D-prints were made with PLA.
0.2 mm layer height.
Infills varied from 0% to 30% for no particular reason.
The top plate parts must not be printed with brims!
All 3D-printing is done. The Snootybug is ready for action. But as always, the software and the user interface, as well as the main functionalities of Snootybug, will constantly be developed.
The file section contains most of the important parts. Minor details might be missing, because they depend very much on what kind of hardware you want to use. I will add more files later, even though I bet you need to either modify them or design something from scratch to fit your chosen hardware.
#ifndef MOTORCLASS
#define MOTORCLASS
class motorclass
{
int pin1, pin2;
int corrector;
int speed;
public:
motorclass(int in_pin1, int in_pin2, int in_corrector);
void set_speed(int in_speed);
int get_speed(void);
};
#endifSpeed values range from -255 to 255. No checking is done for overflows. The ino file is in the files section below.
Each motor is defined as:
motorclass motor_LB(0, 1, 1);
motorclass motor_RB(2, 3, 1);
motorclass motor_RF(4, 5, 1);
motorclass motor_LF(6, 7, -1);…where two pins are defined for the motor. The third parameter adjusts the right rotation direction, so I don't have to swap wires, if they went wrong. L for left, R for right, B for back, F for front. Also the backwardish order came from me wiring all motors just as I saw the wires fit the narrow space. While testing, I found out which wires actually went to which motor as well as the direction of rotation.
This is a part of the user interface on the phone:
The eight buttons around the Stop button change the direction of the Snootybug with the following code:
void onPressWChange() {
// Add your code here to act upon PressW change
if (!press_W) return;
x_speed -= 5;
normalise_speed();
}
/*
Since PressNW is READ_WRITE variable, onPressNWChange() is
executed every time a new value is received from IoT Cloud.
*/
void onPressNWChange() {
// Add your code here to act upon PressNW change
if (!press_NW) return;
y_speed += 3.53553390593;
x_speed -= 3.53553390593;
normalise_speed();
}
These are the functions for pressing “West” and pressing “NorthWest”. Each of the 8 buttons kind of adds a vector of length 5 to the x and y components of the speed vector. x_speed and y_speed are global variables dividing the speed vector of the Snootybug into x and y directions. If the speed gets too high, the speed is normalised with the following function:
void normalise_speed(void)
{
float speed, ratio;
speed = x_speed * x_speed + y_speed * y_speed;
if (speed <= 2500)
return;
ratio = 2500. / speed;
x_speed *= ratio;
y_speed *= ratio;
}
I'm going to update this page in the future with more code examples, as the development continues. Tessa is an important part of the developing team and right now we are focusing on her learning the snoot interface.
License:
Creative Commons — Attribution — Noncommercial — Share Alike