I previously experimented with Grandeur Cloud to monitor some sensors data. Now I had to benchmark it for speed.
What could be better for this than an RC car controlled over internet. Not only did I use Grandeur Canvas to test it, I also made a simple html/javascript based joystick web app using the JavaScript SDK provided by Grandeur to control my robot car.
Be aware that the project works over the internet only. And so your car would use WiFi to connect to internet.
This tutorial is very detailed so that nobody gets stuck anywhere while replicating it.
Hardware SetupThe following schematic presents the overall connections on the car's hardware.
First things first, after gathering all the hardware, begin with soldering the wires onto the motors.
There are four motors, which form two pairs, each pair having two motors of each side connected in parallel, that is, both left-front and left-back motor are connected in parallel and both right-front and right-back motor are connected in parallel.
Using provided screws and locks, mount the motors as follows:
Put the motor driver on the chassis and mark the holes. Use a solder iron (or a drill) to bore the chassis and fix the motor driver with bolts.
Put the battery pack and charging module on the chassis and fix it just like the motor driver. Here I fixed the battery using the hot-glue gun.
You can use any battery pack with voltage between 5 and 12 volts. Above this voltage requires removing the 5V enable jumper and providing a separate 5V supply to the NodeMCU for power. This separates the power supply for the NodeMCU and the motors. For simplicity, I chose a 7.2V battery pack so I don't need two power supplies. It is basically two rechargeable 3.7V Li-Ion Cells joined in series and connected to a charging/protection module.
Connect the Battery Pack with the motor driver.
From the motor driver, pull out the jumpers ENA and ENB, because we'll be providing PWM here to control the motors speeds. Make sure the 5V enable jumper is present because it connects the regulator that will power our NodeMCU from the same battery pack. Use the jumper wires to connect the driver as per the schematics provided above. Following pictures can be used as reference for connections:
Bend two long screws and use following arrangement to fix the NodeMCU perpendicular to the the chassis. This allows us to easily program the microcontroller even after the assembly.
This is how the assembled car looks like from the top:
There is another acrylic sheet that is used to cover the mounted parts. Both sheets are joined using long metallic nuts.
This completes the assembly. To program the NodeMCU, connect it to the PC using Micro-USB cable.
IMPORTANT: Turn off the
battery Pack when connecting the
NodeMCU to PC.
Download The Following (if not already present/installed):
- Arduino IDE
- Node.js
- GitHub repo grandeur-bot that contains the code for the Car's NodeMCU program and the Joystick web app.
Open Arduino IDE and in the File menu, go to preferences and add the following URL into the "Additional Board Manager URLs" field:
https://arduino.esp8266.com/stable/package_esp8266com_index.json
Go
to
"Tools→board→Boards manager" and search for "esp8266". Install the core.
In this project, we are using grandeur-cli
which is a command line tool to serve/authenticate webapps meant to communicate with Grandeur.grandeur-cli
depends on the node.js runtime environment.
After installing node.js, open a command prompt and type the following to install the grandeur-cli
:
npm install -g grandeur-cli
Verify the installation by typing grandeur
or grandeur -v
into the terminal (command prompt) and hitting enter. Installation is successful if it shows a similar output as follows:
Open the Arduino sketch from the grandeur-bot-firmware
directory of the grandeur-bot repo in Arduino IDE. Also open the index.html file in the grandeur-bot-web-app
folder using notepad or any other editor (VS Code etc.). We need to put in the security credentials from the Grandeur dashboard in both the firmware as well as the webapp for them to be able to work with Grandeur.
- Sign-up (or login) at https://www.cloud.grandeur.tech/.
Create a new project and copy the APIkey from the dashboard and paste it into the Arduino code.
In the devices section, create a new model "dir" with schema as follows:
{"D":0}
Create a new device and copy/paste its ID and token into the required places in the firmware and web app's "index.html" (only device-ID required in web app).
In the accounts section of Grandeur dashboard, create a new user account. A user account is mandatory to control/monitor a device from an app. We'd have to pair this account with our device that we created in the last step.
Here's how to pair this user account with our device:
Generate Access credentials/tokens for the web app from the settings section. Copy paste these in the "index.html" file of the web app.
Put the credentials of the user account created previously in step 4 and project API key in the web app's "index.html" file and save it.
The project requires 9 button widgets for each direction: North, North-East, East, South-East, South, South-West, West, North-West, and Center (Stop). All of them in push mode. Every one of them has "C"as its off-state value. The on-state value represents the direction (N, NE, E, SE, S, SW, W, NW, C, respectively).
Notice that the movements are mapped to the 2D directions on a compass and the button's release is used as a stop signal.
Step 8: Add WiFi Config and UploadFinally in Arduino IDE, add WiFi credentials in the code then save and upload it.
The NodeMCU is now programmed so we'd detach it from the PC and turn on the battery pack.
Next section guides how to control the car over the internet.
Controlling the Car from the NoCode Canvas AppNow it's time for action. Run the canvas and use the push button widgets to control the car.
NOTE: If the directions seem reversed, change the #defines in the NodeMCU program.
Canvas app is great for testing the hardware and the connectivity to Grandeur. So now that we know our car hardware is working perfectly and is connected and controllable with Grandeur, let's make our HTML joystick.
Setting up the Joystick WebAppLet us run the web app now.
- Open command prompt and cd into the web app directory (where the "index.html" is present) and run following two commands:
grandeur init
grandeur serve
The first line initializes the directory as a Grandeur project's workspace, that is, a part of your Grandeur project The second one runs a local development server with hot reload. We also need to go to the settings on Grandeur dashboard and add the localhost domain into the allowed domains field to allow requests coming from the URL
http://localhost:3000.
Now we can control our car from the joystick.
The code has plenty of comments to make it digestible however one should also take a look at my grandeur-thermohygrometer as it will help with the basics of Arduino SDK for Grandeur Cloud. Following is a diagram to explain how it all works.
The joystick sends compass directions (N, NE, NW, S, SE, SW, E, W) when moved and "C" when at rest. So depending upon the first two characters of the direction state variable we evaluate the speeds and directions for both left and right wheels.
Regarding Grandeur's Arduino SDK, following things are important here:
- Project initialization
Grandeur::Project project;
project = grandeur.init(apiKey, token);
- variable change callback prototype
void cb(const char *path, const char *state);
The "state" will contain value of variable associated to "path".
- Attach callback
project.device(deviceID).data().on("D", cb);// D is the direction variable
The "cb" function will be called every time a change in variable "D" occurs on the internet so the code becomes event driven in nature.
NOTE: If the directions seem reversed, change the #defines in the NodeMCU program.
#define LFor D3 // left forward
#define RFor D4 // right forward
#define LBck D1 // left backward
#define RBck D2 // right backward
#define LPWM D5 // left speed
#define RPWM D6 // right speed
WebApp Code DiscussionThe web app code is pretty much simple thanks to the joystick library by Roberto D'Amico. We only have to edit the index.html so let's look at some difficult lines:
- The linking of grandeur JavaScript library
<script src="https://unpkg.com/grandeur-js"></script>
This line of code brings the Grandeur SDK into our web app from a CDN server. So that we can communicate with Grandeur.
- Over scroll behavior
<body style="overscroll-behavior:contain;">
In case of mobile browser swiping down the joystick caused the page to refresh. which is disabled by this style element.
- Connection/Authentication status with Grandeur
<h1 style="text-align:center;user-select:none;" id="status">Starting</h1>
- On the top of page there will be a heading that reads Starting/logging in/authenticated/connected/network error. This actually is the state of connection with Grandeur. If you see a "Network Error" here, that is bad. Check the following:
1- Internet access is available.
2- The web app's URL (localhost or anything else) is added in the allowed domains in settings section of Grandeur dashboard.
- Joystick division
<div id="joyDiv" style="width:480px;height:480px;margin:auto;"></div>
- Add the joystick library
<script src="./joy.js"></script>
Adding this line allows us to use the joystick library in our web app.
- Beginning of our JavaScript code block
<script type="text/javascript">
- Custom color scheme for joystick
var joyParam = { "title": "joystick", "internalFillColor": "#000000", "internalStrokeColor": "#000033", "externalStrokeColor": "#000033", "externalFillColor": "#000000" };
- Joystick object reference
var joy = new JoyStick('joyDiv', joyParam);
- Grandeur project reference
var project = grandeur.init("PROJECT-API-KEY", "ACCESS-KEY", "ACCESS-TOKEN");
These three parameters are obtained from the Grandeur dashboard as explained in the "Setting up Grandeur" section above. This object is very well documented here.
- Polling the joystick value periodically
setInterval(function () {
const dir = joy.GetDir(); /* joystick direction */
if (dir !== gdir) /* detect change */
{
gdir = dir; /* update cached value */
if (devices && connected) /* determine whether cloud is connected */
devices.device(deviceID).data().set("D", dir); /* send new direction */
}
}, 100);
This is a periodic function that runs every 100 milliseconds and compares the current joystick value dir
with previously cached value gdir
and if a change is detected and the cloud connection is ok it passes this change onto the target device identified by "deviceID" via the variable D
and updates the cached value.
- Connection status function
project.onConnection((status) => {
switch (status) {
case "CONNECTED":
document.getElementById("status").innerText = "Connected"; /* update page heading */
devices = project.devices(); /* obtain reference to paired devices */
connected = true; /* update cloud status flag */
break;
default: /* connection lost
document.getElementById("status").innerText = "Disconnected";
connected = false;
}
});
As mentioned in documentation, the project reference object can be used to monitor connection status change and here the heading text is used to indicate it. Also the registered devices reference is obtained upon successful connection. A global variable "connected " is there to prevent errors caused by invalid communication attempts in other parts of the web app.
- Login with user account
async function login() {
const email = "USER-ACCOUNT-EMAIL";
const password = "USER-ACCOUNT-PASSWORD";
document.getElementById("status").innerText = "Logging in";
var auth = project.auth();
try {
var res = await auth.login(email, password);
switch (res.code) {
case "AUTH-ACCOUNT-LOGGEDIN":
case "AUTH-ACCOUNT-ALREADY-LOGGEDIN":
document.getElementById("status").innerText = "User Authenticated";
break;
default:
document.getElementById("status").innerText = "Authentication Failed";
if (res.code == "AUTH-ACCOUNT-ALREADY-LOGGEDIN") dispay_joystick();
}
}
catch (err) {
document.getElementById("status").innerText = "Network Error";
}
}
This function is executed on startup and it requires credentials of a user account registered in dashboard to which the target device is paired. Pay attention to the auth object and spare time to read its awesome documentation.
- End of script
/* Call login on startup */
login();
</script>
This marks the end of JavaScript code block and the call to "login" function sets the things into motion. Upon successful login the connection status will change and the polling "setinterval" function will start reporting changes to the target device.
That's all folks.
Comments
Please log in or sign up to comment.