Skip to content

Motor Driver

Grove - I2C Motor Driver V1.3

The package for the Grove I2C Motor Driver V1.3 from Seeed Studio is created with catkin create pkg PKG_NAME [--catkin-deps [DEP [DEP ...]]]:

1
2
3
4
5
6
7
fjp@ubuntu:~/git/diffbot/ros/src$ catkin create pkg grove_motor_driver --catkin-deps rospy roscpp geometry_msgs
Creating package "grove_motor_driver" in "/home/fjp/git/diffbot/ros/src"...
Created file grove_motor_driver/CMakeLists.txt
Created file grove_motor_driver/package.xml
Created folder grove_motor_driver/include/grove_motor_driver
Created folder grove_motor_driver/src
Successfully created package files in /home/fjp/git/diffbot/ros/src/grove_motor_driver.

The package depends on the two ROS client libraries rospy and roscpp. To control the two motors the package will use the geometry_msgs/Twist message. The interface to the motor driver is done with the Python library from DexterInd which is a rewerite of the Seeed Studio Arduino library.

This library requires the following two python libraries

  • RPi.GPIO
  • smbus SMBus (System Management Bus) is a subset from the I2C protocol

These libraries should be installed with pip3, Python's package manager:

1
2
pip3 install RPi.GPIO
pip3 install smbus

Note that this will install these packages system wide. This is ok because they are installed on the Raspberry Pi which is dedicated to operate for this purpose. For a development environment it is best practice to use a python virtual environment like venv and install the packages inside it.

Connection

Afterwards the I2C port of the motor should be connected to the I2C port 1 of the Raspberry Pi 4 B. Don't forget to remove the jumper on the motor driver board which would provide power to the Pi. However, it is also not required to connect VCC and GND of the I2C connector. Only the SDA (data) and SCL (clock) wires are required.

Make sure to set the address with the dip switches on the motor driver to 0x0f because this is the default address used in the library files.

To test the physical I2C connection use i2cdetect described in Hardware Interfaces: The output should list 0f in the address table:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- 0f 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

Test Motor Driver

Test the motor driver by running one of the python files:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
fjp@ubuntu:~/git/diffbot/ros/src/grove_motor_driver/src$ python3 motor_example.py 
Forward
Back
Stop
Speed: 0
Speed: 1
Speed: 2
Speed: 3
Speed: 4
Speed: 5
Speed: 6
Speed: 7
Speed: 8
Speed: 9
Speed: 10
Speed: 11
Speed: 12
...
Speed: 25
Speed: 26
Speed: 27
Speed: 28
Speed: 29
Speed: 30
Speed: 31
Speed: 32
Speed: 33
...
Speed: 55
Speed: 56
Speed: 57
Speed: 58
Speed: 59
Speed: 60
Speed: 61
Speed: 62
Speed: 63
Speed: 64
Speed: 65
Speed: 66
...
Speed: 75
Speed: 76
Speed: 77
Speed: 78
Speed: 79
Speed: 80
Speed: 81
Speed: 82
Speed: 83
Speed: 84
Speed: 85
Speed: 86
Speed: 87
Speed: 88
...
Speed: 97
Speed: 98
Speed: 99
Stop

Troubleshooting

If you get errors like the following, make sure the I2C cables from the motor driver to the Raspberry Pi are connected (see Hardware Interfaces for more infos) and use the RESET button on the motor driver.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
fjp@ubuntu:~/git/2wd-robot/ros/src/control$ sudo python grove_i2c_motor_driver.py 
Traceback (most recent call last):
  File "grove_i2c_motor_driver.py", line 68, in <module>
    m.MotorSpeedSetAB(100,100)
  File "grove_i2c_motor_driver.py", line 57, in MotorSpeedSetAB
    bus.write_i2c_block_data(self.I2CMotorDriverAdd, self.MotorSpeedSet, [MotorSpeedA,MotorSpeedB])
IOError: [Errno 110] Connection timed out
fjp@ubuntu:~/git/2wd-robot/ros/src/control$ sudo python grove_i2c_motor_driver.py 
Traceback (most recent call last):
  File "grove_i2c_motor_driver.py", line 68, in <module>
    m.MotorSpeedSetAB(100,100)
  File "grove_i2c_motor_driver.py", line 57, in MotorSpeedSetAB
    bus.write_i2c_block_data(self.I2CMotorDriverAdd, self.MotorSpeedSet, [MotorSpeedA,MotorSpeedB])
IOError: [Errno 121] Remote I/O error

Try pressing the RESET button and release it right before executing one of the scripts. You should also be able to detect the motor driver with i2cdetect -y 1:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fjp@ubuntu:~/git/2wd-robot/ros/src/control/src$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- 0f 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

As you can see the address of the motor driver is detected at 0x0f.

In case of the following output, where every address of the I2C bus seems to be taken, it is most likely that the SDA (data) and SCL (clock) signal cables are switched:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 
10: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 
20: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 
30: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 
40: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 
50: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 
60: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 
70: 70 71 72 73 74 75 76 77

To solve this make sure the SDA and SCL cables are connected to the right pins on the Raspberry Pi. See Hardware Interfaces for more infos.

Another solution is to restart the Raspberry Pi while making sure that the motor driver is powerd on by connecting it to the battery pack.

ROS Node for Motor Driver

To use the available library of the Grove I2C motor driver in ROS we need to create a wrapper node, called motor_driver. The node subscribes to the topic /2wd_robot/cmd_vel which is of type Twist message from the geometry_msgs header. To send commands to the motor the . These topics can be published with nodes from the navigation stack or with rostopic pub for test purposes.

https://en.wikipedia.org/wiki/Differential_wheeled_robot

http://wiki.ros.org/differential_drive

After the node has been implemented, we need to build the workspace with catkin build:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
fjp@ubuntu:~/git/2wd-robot/ros$ catkin build
----------------------------------------------------------------
Profile:                     default
Extending:          [cached] /opt/ros/melodic
Workspace:                   /home/fjp/git/2wd-robot/ros
----------------------------------------------------------------
Build Space:        [exists] /home/fjp/git/2wd-robot/ros/build
Devel Space:        [exists] /home/fjp/git/2wd-robot/ros/devel
Install Space:      [unused] /home/fjp/git/2wd-robot/ros/install
Log Space:          [exists] /home/fjp/git/2wd-robot/ros/logs
Source Space:       [exists] /home/fjp/git/2wd-robot/ros/src
DESTDIR:            [unused] None
----------------------------------------------------------------
Devel Space Layout:          linked
Install Space Layout:        None
----------------------------------------------------------------
Additional CMake Args:       None
Additional Make Args:        None
Additional catkin Make Args: None
Internal Make Job Server:    True
Cache Job Environments:      False
----------------------------------------------------------------
Whitelisted Packages:        None
Blacklisted Packages:        None
----------------------------------------------------------------
Workspace configuration appears valid.
----------------------------------------------------------------
[build] Found '2' packages in 0.0 seconds.                                                                          
[build] Updating package table.                                                                                     
Starting  >>> grove_motor_driver                                                                                    
Starting  >>> grove_ultrasonic_ranger                                                                                                                                                                              
Finished  <<< grove_motor_driver                     [ 1.0 seconds ]                                                
Finished  <<< grove_ultrasonic_ranger                [ 1.0 seconds ]                                                                                             
[build] Summary: All 2 packages succeeded!                                                                          
[build]   Ignored:   None.                                                                                          
[build]   Warnings:  None.                                                                                          
[build]   Abandoned: None.                                                                                          
[build]   Failed:    None.                                                                                          
[build] Runtime: 2.0 seconds total. 

As the final note of the build output suggests, we have to source the setup.bash files in the devel space.

1
fjp@ubuntu:~/git/2wd-robot/ros$ source devel/setup.bash

To make the ranger node executable we have to modify the ranger.py file:

1
fjp@ubuntu:~/git/2wd-robot/ros/src/grove_ultrasonic_ranger/src$ sudo chmod a+x ranger.py