Intel Edison/Seeed/Nexus 3WD OmniRover




Introduction: Intel Edison/Seeed/Nexus 3WD OmniRover

Lately I have been working on a simple, hackathon-friendly kit for mobile robotics based on the Intel Edison module. My goals are a robot capable of autonomous navigation and omnidirectional movement for less than $250, all included (the processor and battery as well as all the mechanics and electronics). I also wanted it to be possible to build it without soldering in under an hour (the "no soldering" is because this is difficult to do in certain hackathon locales, like hotel ballrooms).

While my "kit" is not yet complete I am sharing my current progress here, then will update as it evolves. Right now the system does have a few issues: I still need a good sensor package for autonomous navigation, the cabling solution could be improved, it's not completely solder-free, and I need a better way to do battery level sensing. However, the basic system is close to satisfying my goals, and the system may make a nice basis for your own robotics project.

I am also working on a software stack based on Node.js as an evolution of the course I have taught on using Node.js for programming IoT applications. That is also not quite yet ready for release but the end of this instructable I am including a simple Node.js test script that demonstrates most of the necessary hardware interfacing. You can likewise use that as a basis for your own projects.

I should mention here that I am an Intel engineer but any opinions I express here are my own.

Step 1: Collect the Parts and Tools

You will need to collect some stuff:

  • Intel Edison module with Arduino adapter: $90
    • Note that you can buy this from Seeed along with the other parts below.
    • I assume later that you have set this up (firmware updates, etc) following the online instructions.
  • Nexus Omniwheel base: $100
  • Various Seeed Grove parts:
    • Grove Base Shield V2: $8.90
    • Two Grove I2C motor drivers: 2 x $16.90
    • Grove 0.1" header adapter cables, pack: $3.90
      • To plug in encoders; these are a bit of a hack, if you are handy with a crimper and can attach Grove connectors to the existing encoder cables you may be able to avoid using these. But at least this approach doesn't require any special tools or soldering.
  • Other hardware
    • 12 header pins (to break apart into 3 groups of 4 and use for connecting encoder cables): $0.50
    • 2x 1cm x 16cm velcro straps (for battery): $1.00
    • 4x 3/16” 0.5” bolts (to mount Edison Arduino board on standoffs): $1.00
    • 10x 2.6mm x 10mm metric bolts and nuts (to mount Grove modules): $3.00
    • 10x 4mm plastic standoffs for 2.6mm bolts
    • 3S 11.1V 2200 mAh Lithium polymer battery: approx $30.00
      • This is the smallest battery that will give you a reasonable runtime, but there is lots of room for a bigger battery if you want. I actually use a much larger battery in my build.
      • I used one with a Dean’s connector but you can use a different connector (eg a Traxx connector) if you find or build a matching battery cable
    • Power cable: $8.00
      • See next step for parts breakdown and build instructions
    • Low battery alarm for at least a 3S battery: $3.00
      • Many options here; you can reuse it on other projects
      • I recommend one that shows each cell and lets you adjust the alarm threshold (3.3V is too low, a better threshold is 3.6V). Here is a suggestion (not the one I used, though):
  • Other:
    • Balance charger that can handle least 3S Lithium Polymer batteries
      • If you don't have one yet, it's a good investment, and can be used for lots of other projects (drones, etc).
      • These come as low as $10 but make sure you get one that can do balance charging, and of course that has connectors for the batteries you use. This is the minimum:
      • However, slightly more expensive chargers can charge batteries much faster. The above will take about 6h to charge a reasonable-sized battery battery, a faster charger will take only 20 minutes or so.
      • This is what I use (about $35). It comes with a Dean's connector so if you use Traxx batteries you may have to pick up an adapter. Also an extra 3S extension cable is convenient to charge the battery while it is in a bag. It can also do handy things like adjust batteries for storage and discharge batteries for safe disposal:
    • Fireproof lithium polymer charging safety bag: $2
      • Yes, you need one of these. LiPo fires are nasty. Do NOT charge the battery while it is in the robot. Note that most home robots (eg Roombas) use NiMH batteries, which are substantially safer during charging. Unfortunately they are also a lot heavier.
    • Crimp tool (this also happen to come with a bunch of crimps so you won't have to buy any): $13
  • Optional: I will show these in my build but you don't really need them. In particular battery level sensing using the Grove voltage divider does not work very well for some reason, and you unfortunately need to solder the cable to make sure it stays connected. I am working on a better solution; in the meantime, I recommend the external sensor, above. A buzzer or speaker is useful for other reasons but you obviously can't use it as a battery level alarm without a way to sense the battery level.
    • Grove voltage divider (to monitor battery voltage): $5.90
    • 3S balance connector extension cable: $2.00
    • Grove buzzer or speaker module (low battery warning): $1.90 to $3.50
    • 6x 2.6mm x 10mm metric bolts and nuts: $2.00
    • 6x 4mm plastic standoffs for 2.6mm bolts: $1.00

Step 2: Build the Power Cable

You need the following to make the power cable. This can be done without soldering if you can find a battery connector preassembled with some wires. Here is an example:

If you cannot find a preassembled battery connector cable you will have to make it, which will require some soldering. If you have to make a battery connector cable, get these parts:

  • Battery wires: $1.00
    • 2x 8cm (one red, one black) 12AWG
    • 12AWG is probably overkill but it's what my (preassembled) battery cable came with, and is typical for RC racing battery cables.
  • Heat shrink for 12AWG wire: $1.00
  • Male Dean's connector: $2.00

If your battery uses a different connector, of course you want to find and use a mating connector for your battery connector. Otherwise you will have to find an adapter. The most common battery connectors are Dean's and Traxx. I use Dean's (also known as a T-connector), as it is the most common in Asia, but Traxx is more common in North America. There are also lots of other options. Probably you want to research the battery first and then build the cable.

Once you have a battery connector cable in hand, to make the rest of the power cable you will need the following:

  • Two crimp connectors for wire: $1.00
    • For min 12AWG wire
    • Included in many crimp tool kits...
  • Wires for motor drivers: $1.00
    • 4x 16cm (two red, two black) 16AWG
    • Of course buy some reels, use the rest in other projects
  • 5.5mm OD 2.1mm ID barrel plug for Edison: $2.00
    • This is the same as the one used for Arduinos, so those will work
    • Cut wires to 16cm length

Build instructions:

  • If necessary (if you can't find it preassembled), build your own battery connector:
    • Strip and solder 12AWG wires to Dean’s connector, or do whatever is necessary for other kinds of connectors
    • Attaching red to positive terminal and black to negative (look at your battery to see which is which, but do NOT solder this or build the cable with the connector attached to the battery...)
    • Cover solder joints with heat shrink to avoid shorts
  • Strip ends of all other wires
  • Optional: tin ends of wires
    • This improves stability in the screw terminals, but is not strictly necessary
    • Try not to get too much solder when you tin the wires, it will make it hard to insert them into the screw terminals. Get just enough on to keep the filaments from fraying. The way to do this is to heat the wire and let it "wick" up solder applied to the end. If you do get too much on you may have to scrape it off to get the wires to fit in the screw terminals.
  • Crimp wires as shown, matching red to positive, black to negative
    • This does require an inexpensive crimp tool (see last step); there are a few other kinds of crimps you can use but these can handle a lot of current and are mechanically strong.
    • Make sure the stripped ends of the wires insert fully into the splice before crimping
    • After crimping give each wire a strong tug to make sure they won't come out

Step 3: Mount the Grove Motor Drivers on the Top Plate

Unpack the Nexus 3WD Omni frame and mount two Grove motor drivers on the top panel, using five 2.6mm nuts and bolts and five plastic spacers each. You need the plastic spacers to keep the bottom of the motor drivers from touching the frame, otherwise they will short out.

In my picture I used 2mm bolts and nuts because I had them on hand, but they were a little small. Still worked, though.

Optional: You might want to put washers under the nuts. Threadlocker is also a good idea to keep the nuts from working loose, but use the blue, plastic-safe kind if you do use it. Another way to keep the nuts from coming loose is to use a second "jam" nut.

Step 4: Route Motor Cabling

Unpack the bottom panel of the Nexus frame, mount the wheels, and route the power and encoder cables as shown in the picture. Note that I have tried to route the power and encoder cables along different paths to avoid noise from the high-current motor cables (which will be carrying a pulsed PWM signal...) from showing up as noise on the encoder inputs. In particular try to avoid laying the power and encoder cables lengthwise along each other.

Step 5: (Optional) Mount Speaker Module

Mount the speaker module on the bottom frame using three 2.6mm bolts, nuts, and plastic spacers. You can also see some velcro straps in this picture which we will use later to mount the battery.

A Grove speaker module lets you play different tones. If you just want an alarm you can also use a Grove Buzzer module here, which is a little cheaper.

Step 6: (Optional) Mount Voltage Divider

This step is optional, and unfortunately requires soldering. I'm looking for a better solution so you may want to skip it.

Mount the Grove voltage divider module on the side opposite the speaker module on the bottom frame. You can set the scaling switch on the voltage divider to either 3x or 10x. The picture shows 10x but I ended up using 3x as it gives better resolution. That only works though it you set up the Edison/Grove interface for 5V (which you have to do anyways as the motor drivers only work at 5V).

Then, modify the 3S battery voltage extension cable by cutting both the GND and the opposite (full voltage) wire, stripping them, and soldering them together. You can then attach these points to the voltage divider inputs. You really do need to solder these: if you just twist them together and try to use the screw terminals in the voltage divider module to hold them together, there is a chance they can slip out, which then poses a shorting hazard, as then there is a loose wire with the full voltage of the battery behind it.

Finally, connect your external alarm to the end of the extension cable. This gives you a backup alarm and also lets you calibrate your own sensors. Once things are calibrated and your sensing is working reliably you can remove it and use it in some other project.

NOTE: Unfortunately I was not getting very accurate readings with this setup, so for this reason (and in addition to the annoyance of having to solder the cable) I actually recommend you skip it. If you are going to have to solder something anyway you may as well replace this setup with a simple resistor network, which works better, is cheaper, and lets you measure each cell, not just the overall battery voltage. You can make one using a Grove prototyping module fairly easily (it is shown in the picture of the yellow rover).

Step 7: Wire Up Encoder Cable Adapters

The Nexus kit comes with three very nice Namiki motors that each include a 4-wire optical quadrature encoder interface for measuring speed and position. The encoder cables included in the Nexus kit are electrically compatible with the Grove inputs (5V, GND, two signal wires), but have 0.1" female header connectors rather than Grove connectors on the ends. The order of the wires is also different.

To make these work without needing a fancy crimp tool to change the connectors or having to splice cables you can get a set of Grove adapter cables and plug them in. I used a strip of four 0.1" header pins (pushed down so they stuck out equally on either side of the plastic spacer) to connect the encoder cables to the Grove cables. Since they were a little loose (find extra-long header pins if you can) I then wrapped the connections in tape to hold them together.

When setting these up, pay attention to the order of the colors on the Grove cables relative to the encoder wires, since the power, GND, and signal wires are not in the same order. You may want to double-check the connections against the signal documented on the motor encoder PCBs (you might have to unscrew one of the motors to get a good view, though).

Step 8: Mount Battery

Strap down the battery with some velcro straps through slots in the lower frame as show in the picture. This setup will hold the battery in place reasonably firmly while still allowing it to slide out for charging. Due to the possible fire hazard, you should NOT charge the battery while it is in the robot. Always remove it and charge it in a fireproof bag.

Stick on one extra velcro loop; this is handy for tidying up the (excessively...) long encoder wires as shown. If you want to keep the battery from sliding out, you can also add an extra velcro strap over the end of the battery, sticking it to the other straps. The other end of the battery will then be held securely by two of the frame standoffs.

Note I used a pretty big battery here, a 5200mAh 11.4V 3S battery, because I plan to use this particular build for all-day demos. However, a smaller battery, say a 2200mAh, is just fine. Conversely, there is room to fit an even bigger battery if you want. Also, although the motors are not as perky if you do this, it is also possible to run the system off a 2S (7.4V) battery, but get a 3S if you can.

Step 9: Wire Up Power Cable to Motor Drivers

Thread the power cable through the central hole in the top frame and connect it to the power inputs on the motor drivers (next to the Grove connector), taking care to get the polarity right.

Remove the small jumper next to the power inputs on the motor drivers. This lets the motor drivers use their own power regulators to power themselves directly off the battery, reducing the load on the Edison Arduino adapter board power regulator.

Step 10: Attach Grove Cables to Motor Drivers

Plug in a pair of Grove cables to the motor drivers.

At this point you should also make sure the motor drivers have different I2C addresses. Leave one at the default 1111 (15 decimal) setting and change the other to 1010 (10 decimal). Unfortunately for some reason 1110 (as shown in the picture) does not actually work, it will still respond to address 1111.

Step 11: Mount the Top Panel

Mount the top panel on top of the robot. Thread the encoder, speaker, and battery level sense wires through the central hole, and thread the motor wires through corner holes convenient to the motor connections on the motor drivers. You may have to wrap the excess length of the motor cables around the vertical standoffs. Screw down the top panel. Optional: use (blue, plastic-safe) thread locker on the frame screws.

Step 12: Connect the Motor Wires

Connect the motor wires to the motor drivers as shown. Note that you will have two motors on one driver and one on the other driver. For the motor driver with only one motor connect it to the M2 channel. Also, the motor driver with only one motor attached should be the one with the default 1111 address.

Step 13: Mount the Edison

I assume you have previously unboxed the Intel Edison module and the Arduino adapter board for it. Mount the Edison on the adapter board as shown in the online instructions for the Edison.

We are then going to use the bolts and standoffs included in the Edison/Arduino box to mount the Edison on the robot. Note however that the included bolts and standoffs use English units, so you have to track down four additional 3/16" bolts. Alternatively find some metric M3 standoffs the same length and six M3 bolts (capheads work well). You need bolts for both the top and the bottom. Also the standoffs need to be tall enough so the motor drivers will fit under them, so if you use your own standoffs keep this in mind.

Using four bolts from underneath, place the standoffs in the slots as shown but don't tighten them down completely. Arrange the cables as shown. The voltage divider and power cables should go out the end where the power and analog connections will be on the adapter board, while the encoder and speaker cables should go to the bottom side of the adapter board. Criss-cross the motor driver Grove cables to keep them tidy; they will both still be able to reach the I2C plugs on the adapter board.

Put the Edison adapter board on top, line up the standoffs with the holes on the Edison board, then finger tighten the standoffs in place by holding a finger over the bolt coming in from underneath. Once the standoffs are in the right place, put in bolts from the top to attach the Edison adapter board and tighten things down.

Step 14: Mount Grove Base Shield

Plug a Grove base shield in the Edison. You have to do this AFTER you mount the Edison adapter board, since it blocks access to two of the mounting holes.

Step 15: Plug in Grove Connections

Plug in the various Grove cables:

  • Motor drivers each connect to one of the I2C ports
  • Voltage divider cable (if you use it) connects to the A1 port
  • Encoders each connect to ports D2, D4, and D8
  • Speaker connects to D6, which is a PWM-capable port

This cabling setup is designed to avoid pin 7, which if used causes WiFi issues on the Edison. In addition it leaves the UART free, which is useful for various things.

Don't worry too much about figuring out which connector goes with which motor, we will sort that out in a later step.

Note the pictures show the barrel connector plugged in. You actually want to unplug it before the next step...

Step 16: Power Up

You're now ready to power up. Double-check all connections, looking especially for things that might short out the battery (double-check the voltage divider cable in particular, make SURE it has not worked loose from the screw terminal).

Do NOT plug the barrel connector into the Edison just yet. If it's plugged in, unplug it. One of the reasons we want to leave this unconnected during powerup is that the battery connector tends to spark when you connect it, and it is hard at first to make it connect cleanly without multiple make/break contacts. This is not a nice thing to do to a Linux system. So it's better to power up the rest of the system first, then power up the Edison last once the main power is securely attached.

First plug in the Dean's connector. This can be take a lot of force; try not to touch the terminals as you connect the cable, and push it all the way in so no metal is showing.

The LEDs on the motor drivers should light up.

Second, plug in the balance connector extension cable and check the battery voltage on the battery alarm. Make sure each cell is at least 3.6V. If it is not, take everything apart, slide out the battery, and charge it, then put it back in and repeat the above steps.

Assuming you have gotten this far and nothing has caught fire, plug in the barrel connector to the Edison. Some LEDs on the board should come on and the Edison should boot up. If you have not done so already, update the firmware on the Edison and set it up to access an WiFi access point using USB cables. Once you have WiFi set up you can dispense with cables and program it over the air.

One final issue is that the motor drivers' firmware can get a little confused by noise from the Edison during boot and their firmware can hang. If at any point you have found a motor driver is not responding, you can reset it by pushing the small reset button on each driver. You will have to stick a finger under the Edison adapter board to reach it.

Step 17: Load Test Software

Now we have to program the Edison to control the robot. I will give some simple test code in this step designed to check that all the hardware is working and to let you make sure the correct encoder is associated with the correct motor channels, but will leave more complex programming up to you (and to later posts...).

I am going to use Node.js to make it easier to connect to web services and such later but it is also possible to use C/C++, Python, Arduino, or Java if you want. I am also going to use MRAA and UPM, some simple hardware interface libraries provided by Intel. There are other Node.js HW interface options there too, like cylon.js and JohnnyFive, that you might want to look at later.

However, let's set things up to use MRAA and UPM. First, follow the instructions to update MRAA and UPM to the latest versions. You can find documentation for this on the Intel site but if you have already updated the Edison firmware to a reasonably recent version then the following should grab the lastest versions from the online repos (note: Edisons will have to have internet access first...). After logging into the Edison as root issue the following commands:

opkg update
opkg upgrade libmraa0
opkg upgrade upm

Then you want to put the following script somewhere on the Edison, say in "omnitest.js" in your home directory, and then run it using "node omnitest.js". Alternatively you can load this code using the free Intel XDK (IoT Edition), which makes the edit/upload/run cycle more convenient, provides a debugger if you want it, and also manages resolving npm module dependencies (however, this test script intentionally avoids using external modules other than UPM and MRAA to make installation easier). Loading code by the XDK also sets it up to run automatically at boot. I will show how to use that in more detail later.

Use this script to make sure the encoders, sensors, motors, and speakers are all working. Basically, the script spins the robot back and forth and forth in place by running all motors forward, then backward, then it runs each motor in turn. Make sure all three encoders count up and then down in the first back and forth motion. Then check that when each motor spins in turn that the correct encoder channel is responding. If not, either swap around encoder cables or change the pin assignments in the script. If one of the motors is not spinning you may have reversed the IDs for the two motor drivers. I recommend changing the pin assignment in the script rather than messing with the wiring. You may also want to tweak the scaling constants for the voltage divider (if you are using it) to get a more accurate reading. Basically look at the raw reading, look at the external voltage checker, and then enter the right constants into the script to calculate the scaling ratio.

Once this test script is running and the above is all sorted out, the hardware should be ready for more sophisticated coding!


/* Omnirover demo.
* Exercises motors, reads data from sensors and dumps it to the console, tests sound.

var test_motors = true;
var test_batt = true;
var test_encoders = true;
var test_sound = true;

var Mraa = require('mraa'); // general HW I/O
var MD = require("jsupm_grovemd").GroveMD; // UPM Grove motor driver
var RE = require("jsupm_rotaryencoder").RotaryEncoder; // UPM Rotary encoder

var pins = {
// Battery connected through Grove voltage divider, on /3 setting
batt: 1, // analog input; total battery level, divided by 3.

// Grove "speaker" module (can also use buzzer module)
speaker: 6, // can be used to output various tones using modulated PWM

// Quadrature encoders for each wheel (swap around as needed to get correct encoders on correct wheels)
encoder_A1: 2, // wheel 1, A input
encoder_B1: 3, // wheel 1, B input
encoder_A2: 8, // wheel 2, A input
encoder_B2: 9, // wheel 2, B input
encoder_A3: 4, // wheel 3, A input
encoder_B3: 5, // wheel 3, B input

// Motor drivers
motor_driver_bus: 0, // Bus (hardware I2C)
motor_driver_01_id: 15, // I2C address for motors 0 and 1 (channel 0 is not used)
motor_driver_23_id: 10 // I2C address for motors 2 and 3

// ==== MOTOR TEST
var motor01 = new MD(pins.motor_driver_bus,pins.motor_driver_01_id);
var motor23 = new MD(pins.motor_driver_bus,pins.motor_driver_23_id);

// Helper function to set motor speeds and directions more easily
function set_speed(m0,m1,m2,m3) {
var abs_m0 = Math.floor(255*Math.abs(m0));
var abs_m1 = Math.floor(255*Math.abs(m1));
var abs_m2 = Math.floor(255*Math.abs(m2));
var abs_m3 = Math.floor(255*Math.abs(m3));
var dir_m0 = (m0 > 0) ? MD.DIR_CW : MD.DIR_CCW;
var dir_m1 = (m1 > 0) ? MD.DIR_CW : MD.DIR_CCW;
var dir_m2 = (m2 > 0) ? MD.DIR_CW : MD.DIR_CCW;
var dir_m3 = (m3 > 0) ? MD.DIR_CW : MD.DIR_CCW;

// Motor test
if (test_motors) {
} else {

function periodicMotorForward() {
console.log("MOTORS: ALL FORWARD");

function periodicMotorStop1() {
console.log("MOTORS: STOP");

function periodicMotorBackward() {
console.log("MOTORS: BACKWARD");

function periodicMotorStop2() {
console.log("MOTORS: STOP");

// Use the following three functions, in conjunction with the encoder test,
// to make sure the encoders are associated with the correct motors
function periodicMotorForward_1() {
console.log("MOTORS: FORWARD MOTOR 1");

function periodicMotorForward_2() {
console.log("MOTORS: FORWARD MOTOR 2");

function periodicMotorForward_3() {
console.log("MOTORS: FORWARD MOTOR 3");


// Reads all the encoders periodically and prints out their current counts
if (test_encoders) {
var encoder1 = new RE(pins.encoder_A1,pins.encoder_B1);

var encoder2 = new RE(pins.encoder_A2,pins.encoder_B2);
var encoder3 = new RE(pins.encoder_A3,pins.encoder_B3);
setInterval(function() {
console.log("encoder1: ",encoder1.position());
console.log("encoder2: ",encoder2.position());
console.log("encoder3: ",encoder3.position());

var batt = new Mraa.Aio(pins.batt);
var batt_scale = 11.93/0.8; // Voltage divider, /3 setting
function read_batt_sensor() {
var br = batt.readFloat();
var bv = batt_scale * br;
console.log("raw batt reading:",br);

if (test_batt) {

// ==== SOUND TEST
var speaker = new Mraa.Pwm(pins.speaker);

var speaker_duty = 0.5;
var speaker_freq = 600;
var speaker_on_interval = 1000;
var speaker_off_interval = 10000;

if (test_sound) {
} else {

function start_alarm() {
console.log("alarm on");

function stop_alarm() {
console.log("alarm off");

Step 18: Power Down

When you power down the system you have to take some precautions to make sure the battery does not drain.

First, unplug the barrel connectors for the Edison. If you are feeling nice you can issue "shutdown -P now" on the command line first but it's not really necessary; the Edison uses a robust journaling file system and can (usually) take just being powered off.

Then, unplug the balance connector. The reason to disconnect this first upon powering down and last upon powering up is that the Grove voltage divider has a powered op-amp, and it's not really nice to feed it a big input without power to the op-amp (again, I really wish I just had a simple resistor network here...). Also, you don't want to leave the balance connector or voltage sensor plugged in when storing the system as they will slowly drain the battery. With any luck, the alarm will go off when you are not around, then it will proceed to kill your battery by draining it beyond the point of no return...

Finally, unplug the battery.

If you are storing the system for a long time, or are travelling, take out the battery, use a balance charger to adjust its voltage for storage, and store it in a fireproof bag. Note that airlines generally do allow you to take lithium batteries with you as long as you have them in carry-on (not checked!) luggage and in a fireproof bag, and as long as they are a reasonable size (these are).

Be the First to Share


    • Pocket-Sized Speed Challenge

      Pocket-Sized Speed Challenge
    • Audio Challenge 2020

      Audio Challenge 2020
    • Maps Challenge

      Maps Challenge

    3 Discussions


    5 years ago

    More to come. Just getting the basic frame described here.