Using a Kalman filter on a single analog channel

kalman_voltage
Things have been slow here at YardBot HQ recently. Not only do I work full time as a mobile software developer, but part time I work for a mechanical engineering company (same building and owners) that will be releasing a rather exciting computer product in the near future. Add it up together and it means that my robot aspirations are somewhat lower priority. Fortunately with winter tightening its grip here in Canada, I have a little extra time indoors to devote to learning more about ROS and its related systems. One of the things I wanted to learn more about is called the Kalman Filter.

This is a math process that comes up often when looking at IMU and navigation systems. As I understand it in simple terms, it revolves around the concept of filtering data by using previous measurements and merging that with the estimated variance between measurements to predict its current state. This can be done with 1 channel or, in the case of ROS’ robot_pose_ekf node, multiple sensors. The advantage of the extended Kalman filter in the IMU example is that you can combine sensors that have different levels of drift to retrieve a more accurate snapshot of the robot’s position. I haven’t done that yet, so I’m starting simple.

Currently I have 2 Arduinos sending back analog sensor data and controlling a DC motor and linear actuator. This analog data records things like temperature, humidity, current and voltage. Current and voltage both use the MEGA’s ADC pins, so they’re susceptible to noise. I decided to develop a reusable Kalman filter class for reducing or eliminating the noise on one of these single channels.

The result is seen in the photo above. The rocky blue line is the pure data coming in from the Arduino while the nice flat red line is the output of the Kalman filter node. Unfortunately using a voltage sensor for analog filtering doesn’t quite demonstrate the entire system, as the actual value doesn’t really move around, so I’ll be trying it with other sensor inputs later.

For demonstration, here are two files that were used: the single channel kalman filter class I wrote and the ROS node that takes advantage of it.

I pulled examples from multiple sites to get this class, and the core math came from this blog. The filter itself is used in a lot of different places so you should be able to find plenty of examples. That link includes a much deeper dive into the math, so give it a read. In this file, I start by defining the coming methods and variables. Essentially you can make an instance with the required filter properties, then add an input and get the new filtered value out.

This is the file that makes it all work together. It’s configured like a typical ROS node: start the node and retrieve the included launch properties, then start up the subscribers and publishers. I create a subscriber for the unfiltered voltage topic then add a callback to generate the filtered response. In the callback you can also see where I add the input to the SingleChannelKalman instance configured earlier.

The end result is pretty solid as a first try, so I’ll be trying this setup with other analog inputs to see how it fairs.

Posted in Software Tagged with: , , , ,

Organizing with IKEA furniture

All of the pieces to YardBot spread on the table top.

All of the pieces to YardBot spread on the table top.


I moved recently and haven’t had much time to work on YardBot, and part of the problem is that there is no easy place to have my motherboards, power supplies and motors. I had the idea to grab an IKEA table with casters and use it so that I can wheel it around when not in use. One trip to the store later, I had one of these.

Since my computer case is industrial and intended to mounted, I just flipped it upside down and screwed it to the underside of the table top. With only the fan as a moving part, it doesn’t really care about orientation.

Who knows how long I’ll be able to use it as the project moves along, but for now it’s a good way to declutter.

Simple wood screws hold the industrial case to the table.

Simple wood screws hold the industrial case to the table.


The computer is secured fastened to the underside of the table.

The computer is secured fastened to the underside of the table.

Posted in Hardware Tagged with: , ,

Building Arduino firmware with CMake and catkin

A print out of the results of catkin and CMake for my Arduino firmware

A print out of the results of catkin and CMake for my Arduino firmware

As projects get more complex, the tools you use start to become somewhat unwieldy, and they are no longer as effective as before. YardBot runs with 2 Arduinos, and currently my process for updating their firmware requires starting an Ubuntu virtual machine running the same ROS version as the main computer. This is done with the Arduino IDE and anyone who uses it for advanced projects can tell you that the editor is sorely lacking when compared to other software. VirtualBox makes USB pass through difficult too, and having to run a full desktop to update software on a headless system is a bit overkill. All that to say I needed to improve the process and the internet said the answer to that was CMake and catkin.

The nice part of the ROS community is that many of the significant problems have been solved before, so you can generally get help easily. I needed this community multiple times while setting up, so here’s my process so others can learn.

The first thing to do is look at the dedicated rosserial catkin tutorial. This has the entire process listed, but in order to get my code to work, I had to figure out a number of issues.

The general process is as follows:

  1. Create a catkin project (probably best to have an Arduino specific project)
  2. Write your code inside the project’s firmware folder
  3. Create a CMakeLists.txt file to load the Arduino specific settings
  4. Create a second CMakeLists.txt file to handle compiling for a specific Arduino board and handle upload
  5. If your code is clean, upload to the Arduino with USB

If you follow the tutorial with the simple code provided, everything should work as expected. My problem was that I started with my full YardBot code and that means things like 3rd party libraries and ROS packages with custom messages.

Store 3rd party libraries inside firmware/libraries

Originally my Arduino code lived at ~/sketchbook, with all ROS message headers and libraries inside ~/sketchbook/libraries. After moving the code to my ROS workspace, I also copied the libraries. It’s best to remove the ros_lib folder, otherwise there are duplicates, but otherwise it works.

Follow proper coding conventions

With the Arduino, normally you can get away with things like not having function prototypes. The first time I compiled, I hit multiple errors for function not declared, so I had to go through everything and copy function prototypes to the top of the file. When I did this for the second Arduino’s firmware, it compiled on the first try.

Cleaning the workspace helps

When you add a new component, it’s a good idea to clean the workspace and compile from scratch. This means deleting the /devel and /build folders of the workspace.

Source before compiling

After cleaning the workspace, I ran into a problem multiple times where my custom message package would not be picked up, and that caused the Arduino header generator to fail. This meant the message definitions weren’t available, and errors were thrown. The forum solutions mostly included sourcing the correct files, so after running source [workspace]>/install/setup.bash before compiling, everything fell into place. I’ve added that process to my ~/.bashrc file, so hopefully that will always work now.

Have another ROS installation available

If you install the Arduino tools from apt, there shouldn’t really be a problem, but I ran into issues a few times where files that the system thought were there, weren’t. Running an update and upgrade didn’t help, so I ended up copying some files from my ROS desktop.

Choose the correct board definition

The second CMakeLists file includes the USB port and board definition so your code can get to the Arduino properly. Be sure to include the right port and board name. You can find the boards.txt from the Arduino core install, so it’s best to find it and browse to find yours. I used “mega” and “mega2560”.

It was a challenging couple of nights to figure it out, but now that it works, I can update the Arduino firmware without starting my virtual machine or switching USB cables between systems.

Posted in Software Tagged with: , , , ,

Closed loop PID control of a DC motor

What a PID controller should look like after proper tuning

What a PID controller should look like after proper tuning


After getting the DC motor to work nicely with my PS3 joystick, I continued by building in a control system using the PID algorithm. A feedback based control system is very important for advanced robotics, as it makes sure that what your software thinks is happening, actually does happen. A closed-loop feedback process works by taking in a sensor input and using it to adjust the output. In the case of my rather simple DC motor, an encoder generates ticks that are used to find the RPM of the motor, which is the original command.

Math

Briefly, here’s what the PID controller does, mathematically. The Wikipedia article above does a great job explaining the core components, so here is a translation of that main equation into practical pseudo code.

u(t) = K_{p}e_{n} + K_{i}\int e_n + K_{d}\frac{de_{n}}{dt}

where
K_{p} = Proportional scale factor
e_{n} = input error (setpoint – input)
K_{i} = Integral scale factor
\int e_n = cumulative error (sum += error)
K_{d} = Derivative scale factor
de_{n} = change in error since last calculation
dt = change in time since last calculation

I turned this math into a C++ node for ROS that takes an RPM input and spins the motor to that correct speed. In the previous open loop behaviour, one node takes joystick input and outputs directly to the Arduino for control. After working on the next phase, I realized that would work better in more generic nodes, which is the more “ROS way” of doing it. So instead I have one node that takes the joystick input and outputs a left/right number scaled to some limit (in this case the maximum 58 RPM of the motors). A second node reads that RPM node output and uses a PID controller to generate motor output commands. This configuration makes it much easier to test because I can use standard ROS message publishing to set a target speed.

Here I’ll show and explain the different C++ code used to build the required nodes.

Generating RPM values

First is a node called motor_RPM_node that takes encoder ticks from the Arduino and publishes the current RPM speed.

This is a relatively simple node that subscribes to /arduino/encoder and publishes on /motors/rpm. You can see that it allows you to set the number of encoder ticks per revolutions with a launch parameter. The core method is the encoder callback, which builds the time since the last tick then uses the ticks per revolution value to generate the RPM and publish in left/right configuration using a custom YardBot message.

Since the joystick teleoperation node is pretty common, I’ll leave that out. Basically depending on joystick position, there is a stream of left/right messages published to /cmd_num with the desired RPM of each motor.

A PID class

Before explaining the main component, we need a PID class to handle generating valid output. This is an excellent time to use object oriented programming practices and build a PID class that can be reused.

Much of the overall process and procedure was pulled from the excellent PID library for Arduino by Brett Beauregard. There are many convenience methods for retrieving data about the controller and it shows the input data contributing to the error. Once created as an object, the main controller simply needs to mark a setpoint, set the actual input and receive the processed output.

The main controller

Finally comes the main controller node. It subscribes to the encoder RPM topic and RPM setpoint topic and publishes to the Arduino motor. This is a pretty standard ROS paradigm: take input, process and generate output.

Once again there is a definition of the class, along with the different ROS callbacks. There is a subscriber for the RPM input and encoder RPM data, plus a service for setting the tuning parameters. I use a launch file to set the different nodes and parameters, but while testing it becomes cumbersome to constantly restart the launch file to use the updated values. By having a service server, I can set the motor to 0 and update the tunings on the fly, then mark them in the launch file.

As before the initialization methods create the callback objects and receive the launch parameters. The tuning callback sets the PID controller values. The encoder callback sets the PID input values and the RPM callback sets the PID target.

The main processing happens inside a timer callback function that is run every 0.2 seconds. This timing requires taking different factors into consideration: processing speed of your computer, output response requirement and the capabilities of your output (DC motor in this case). My particular number may change as I learn more about the overall system.

Inside the timer callback, the PID controllers generate the next output. For the special zero case, the motors are also turned off. The node tracks the output values and only publishes if the desired speed changes. This is to reduce the number of messages being sent to the Arduino. The PID controller outputs in RPM values but the motor controller itself requires an integer between -127 and 127 so there’s an extra step where the RPM value is mapped to the motor controller parameter.

Tuning the controller

So now that the controller is set up, the most time consuming aspect of building the control system is tuning it to safe and efficient levels. To do this, you need to be able to interpret response characteristics as tuning parameter changes. Admittedly I’m still working on that part, but there’s enough info on the internet that I was able to see progress. In order to see how the controller was behaviour, I opened ROS on my desktop and used rqt_plot to display the desired RPM value against the actual RPM output. That’s what I used for the nice graph at the top.

PID with large overshoot

First is output with a large overshoot. I increased Ki a little more.

PID with i decreasing

Here Kp is too low, as the output doesn’t overshoot the target of 40 RPM. This also gives a good example of what control systems are supposed to do: eliminate error. Given enough time, this system would still reach the target.

PID continuous

With this graph, I changed the target multiple times. You can see the response becomes much smoother as time goes on. Ideally all responses would be smooth like that, so I’ll continue to look into those improvements.

PID follow joystick

Finally I hooked my joystick node back in and used it to move the motor around. Here you can clearly see how the output follows the target. There are a few uneven spots where I can continue to optimize but it’s very clear that the basic behaviour is there. The next phase of improving the controller is to add some safety features that will monitor the output so that it behaves correctly in all scenarios.

Posted in Software Tagged with: , ,

Finding the performance limit of an Arduino MEGA

Arduino connected to the electrical components of YardBot
As I think up more and more things to do with YardBot, I’ve started to reach the limits of what a normal Arduino MEGA can handle. With an 8 MHz clock speed and 2KB of RAM available, Arduinos have never been about high performance. If you look back at my system structure post, you’ll see how many things need to be controlled. So far at my prototype stage I have many of the ROS nodes set up for the following systems:

  • Retrieving motor commands and setting the controller output
  • Reading the motor encoder interrupts and sending the stream back to the ROS master
  • Reading current and voltage sensors and streaming back to ROS
  • Reading temperature and humidity sensors and streaming back to ROS
  • Retrieving LED values and writing the outputs
  • Retrieving beep commands and toggling the piezo buzzer
  • Retrieving and streaming the IMU data from both gyro and accelerometer

All of these components are running on my original Arduino, a MEGA 1280. When I set up the DC motor for a simple open loop test, I noticed that joystick position changes weren’t accepted as quickly as they should, with some commands being dropped. This was noticeable by the fact that the motor continued to spin after dropping the deadman button or returning the stick to neutral. This is bad news for a simple DC motor test, but downright dangerous if used for a 100 lb robot.

Finding a solution means going through each block and thinking through what it does and what impact it has on the rest of the system. If you look at the list above, you’ll see that most return some data back to the ROS master. The Arduino has a limited transmit capacity. By default it operates at 57 KBps, but I’ve set it to 115 KBps in an effort to improve the situation. This helps but does not solve it. The result of the overflow is that some messages are dropped, which can cause bad response times.

Much of the code I use attempts to be non-blocking. That means there are no “delay” functions being called that hold the processor and prevent it from doing other tasks. Instead I use timers that run inside the main loop and trigger callbacks when the desired time has passed. This means that if there are any blocking segments, the timers may be delayed and performance suffers. I discovered another symptom of this when testing the piezo alert buzzer, and when requesting a 2 Hz beep, there are unequal gaps between tones. One of the potential blocking pieces is anywhere that queries an I/O pin. DigitalRead is considered an expensive operation, that is it can take a disproportionately long amount of time to complete. Adding multiple reads together like checking the emergency switch and current/voltage sensor would delay the loop and cause problems.

So the solution at the moment is to separate the functions into a second Arduino. One will operate the motors and return encoder data while the second will do the auxiliary operations like reading sensors. The motors can be considered “time critical” but sensor timing is less strict. This may change as I continue to add complexity but after learning that other mechatronics projects use multiple processors (like ArduPilot), I’m confident it will significantly improve the performance of the whole system.

Posted in Testing Tagged with: , , ,

Designing a movable snowplow

Side of robot and plowThe original purpose of YardBot, beyond career education, was to have something that will either plow the driveway for me or allow me to do it with a simple remote control. With much of the robot chassis in a stable design state, I thought I’d turn my attention to the snowplow attached to the front and describe the process I took, along with the current revision.

Engineering is basically imagination with constraints and this element is no different. Whatever final design is made, it has to fit within these properties:

Early versions

v1 snow plow

v2 snow plow
In the top photo you can see where my design started from. The wheels have gotten larger (I’m planning on using snowblower wheels that are approximately 16″ in diameter) and the chassis itself has a better proportion. The plow has a horizontal arm that attaches to the chassis with a clevis pin and is allowed to rotate up and down. I’ve continued to use this design in subsequent versions but the main difference is that the tab on the top surface is no longer used. This panel is thinner 1/8″ aluminum sheet and it doesn’t have the strength of the 3/8″ plate used elsewhere.

A problem in these designs is the mechanism that translates 2″ of travel in the actuator into a larger change of the plow. Here I’m using a vertical tab on the shovel arm to make the actuator have a clear motion. It’s not a clean stroke and is very restrictive.

Current design

Isolated plow mechanismHere is an isolated view at my current snowplow design. Instead of the actuator working directly on the shovel arm, I’m using an intermediate linkage.

Plow raised

Plow lowered

The result of the extra complexity is that the 2″ of actuator travel is converted to 5.5″ of shovel lift. The shovel arm was made wider, to 2.5″, in order to accommodate the actuator vertically. Each pin is a custom shaft with a hole for a removable cotter pin. Both actuator pins use shaft spacers to keep the actuator centred between the vertical links. In terms of manufacturing, the most difficult piece would be the shovel arm but even that can largely be done on a 3 axis machine. The rest are reasonably simple and can be routed from a single plate.

The second actuator is used to yaw the shovel left and right. It’s the same 2″ stroke unit as the lifter and can move the shovel up to 11° in either direction. Should more articulation be required, the actuator can be switched to one with a 4″ stroke and moved back along the shovel arm.

It’s been cool to see an actual practical tool get added to YardBot and it looks like it would work nicely. I don’t anticipate any material issues, as the actuator power isn’t all that high but I’ll still be going through some finite element analysis testing to validate my design.

Posted in Design Tagged with: , ,

Open loop DC motor control with a PS3 controller

1-IMG_5063The next stage of my robot project is to make software talk to hardware. Previously I mentioned how I translate PS3 controller data into something useful for a robot. Before getting into complex real-world control, I wanted to check that my example 12V DC motor would respond to my Arduino firmware and controller with simple open loop messages.

What makes it open loop? A system is considered closed loop when the output is measured by a sensor input and fed back into the control system to reach a target setpoint. An example of that is a PID control scheme, which I’ll be building next. Compare that to how this system will work. The joystick position is mapped proportionally against the available motor output but there is no check about the motor’s actual speed. If the motor was powering something under load, the operator of the joystick would need to compensate for it to reach the desired speed. If a PID controller was used, the joystick position would map to a specific speed and the controller would make sure it actually turns at that speed, regardless of the load attached.

Here’s a list of the systems in use:

ROS node

My ROS system handles message communication and in this case it takes joy messages from the PS3 controller node, converts them into left-right motor magnitudes and sends them to the Arduino via serial. In the last node I wrote, the output from the PS3 controller was a Twist message: linear motion in the x direction and angular motion around the z axis. Those real-world values (m/s and rad/s) are great for actual robots but because I only have a single motor connected a breadboard, I changed the method so that the controller’s X/Y axes map from -255 to 255 (the Arduino’s PWM output range).

This is a pretty standard ROS C++ node object. First I define the class header, along with the different public and private methods and variables. Then is the object initializer. Here I set some variable values and create the joystick subscriber and motor publisher, then the parameter method is defined.

Next is the method that does the heavy lifting: the joystick callback. It’s much the same as the previous post, except this time I’ve added a zero-out function for the deadman button. This means that if the joystick is non-zero and the deadman button is released, nothing is sent until the joystick is zeroed out. This behaviour prevents the motor from taking off when the switch is pressed again.

At first I thought merging the two axes together would require complicated math but then the more I thought about it, I realized that since the axes are bound between -1 and 1, it’s a simple matter of adding the axes together so that pushing the stick left/right will add or subtract from the forward motion. Ultimately the left/right axis is about the relative speed between left and right motors. The end result is that moving the stick to the left or right extremes with 0 forward power will spin the robot in place.

The remaining methods offer some utility of constraining output and sending the zero speed message when no joystick data is received after a timeout.

Motor controller

Motor controller on breadboard
The motor controller I’m using is an L298D model from Sparkfun. It’s connected to an Arduino MEGA and 58RPM 12V DC motor. Like most H-bridge controllers, it uses 2 pins to control direction and another for speed using PWM output. In order to make that easier to use, I made a library that takes an integer between -255 and 255 and determines the direction pins automatically. Now the motor callback just needs to feed the message values directly to the library.

The ROS message passed in is custom and is essentially a better labelled 2D vector (left and right).

iPhone monitor

Motor monitor animationWhile not being required for a robot, I thought it would be cool to have an iPhone app to monitor the different robot systems. One of the functions I’ve made is an animated view of the motor inputs. The left and right motors have arrows that show forward and reverse direction and the length of the arrow indicates the Arduino output to the motor. With this view, you can clearly see that moving the joystick to the extreme left and right positions means one motor is full speed forward and the other is full reverse.

The app uses my custom RBManager library, which in turn requires rosbridge to run on the ROS host. The phone is connected via websocket, like a mobile game might be. I hope to make a more fully featured iPad version soon and potentially offer it to the ROS community.

This is only an intro for full motor control but it’s been good to actually see hardware and software play nice together. Next up: closed loop feedback control!

Posted in How to Tagged with: , , , , , ,

Writing a custom joystick teleop node for ROS

Teleop node screenshotI’m learning a lot about ROS with every component I add to YardBot but one of the things I haven’t done yet, and will be required to do lots of, is make a custom C++ node for controlling systems. The ROS wiki has excellent documentation, and one of the better examples is how to make a node for teleoperation with a Twist message using a joystick. The plain example is a great way to learn about making C++ subscribers and publishers so I decided to start with it as my first node, with a few improvements.

The high-level design is pretty straightforward: subscribe to the joystick topic that interprets the hardware (this means you can abstract out what specific device is connected), scale the chosen linear and angular axis by a specific value and publish a Twist message on a useful topic. For a mobile robot, the resulting message is generally interpreted by a custom node that can produce direct motor commands. For now I’m using the turtlesim application to test joystick control. For improvements, I’m going to add a deadman’s switch, which is a button that must be pressed for the node to actually publish a message, and a timeout timer that zeros the output if there is no joystick message received for a set period of time.

Here is the full C++ code, and I’ll break down the different components after.

First up is class header section, where I set the public initializer along with the main private methods and variables.

Here is the main class constructor for the node, which I’ve called JoyTeleop. You can see that I’m subscribing to the /joy topic and publish the twist message on /cmd_vel (this is remapped by a launch file to connect to turtlesim). UpdateParameters is a method that queries the rosparam server and retrieves the values we need for operation: linear and angular axes index, deadman switch button index, linear and angular axes scale factors. I set all of those values with a launch file, but the code here also sets a default value if they’re not found.

This method is the primary call for generating the Twist message. First we check the status of the deadman switch button. If it’s pressed, scale the axes according to the parameters set above and publish the message. If the switch is not pressed, check the previous value and send a zero message to stop whatever it is you’re controlling. At the bottom is a call to create a timer that will send a zero message if no callback is received after 0.5 seconds (2 Hz).

Here I define the timer callback and the blank twist message generator. You’ll notice from the turtlesim example that only the forward direction and z axis rotation properties are actually required (the rest are 0 on initialization).

Finally there is the main ROS program loop, where we initialize the ROS environment, assign the node a name, construct the custom node class object and spin ROS to trigger callbacks.

A simple call to catkin_make inside the ROS workspace will build the new node, but only if you’ve set up CMakeLists properly. It took me some time to actually get my node to compile correctly, so here are the sections that may help you build the node as well. It’s not a complete CMakeLists file but contains some of the properties I had to specifically set.

Many of these values are explained in depth by the ROS wiki but I found some additional properties were required. First is the catkin_package property that sets what libraries and packages are required. I had a linker error when compiling my node, so that’s why include_directories and target_link_libraries are set. The add_executable property is the key entry, as it tells catkin to actually make your executable. Inside the call you name the node and assign whatever source code files are required.

Since this node now requires setting parameters and depends on another node, I thought it was a good time to also learn about roslaunch, which makes it easy to set properties and launch nodes together. YardBot will have multiple launch files to start the different systems but for now this component only needs to launch the joystick node and this custom one.

Above is the complete roslaunch file I’m using. It’s reasonably easy to follow along based on the wiki, especially if you’ve used XML before. The first parent is where we start the joystick node, while setting the property dev which is the hardware port the joystick is connected to. Next comes our custom node, with related properties. You’ll also see that I’m remapping /cmd_vel to /turtle1/cmd_vel so that I can test with turtlesim. If you look at the parameter values, you can also see that the left analog stick controls both linear and angular movement and the deadman switch is R1 (right top trigger).

In the scheme of robot nodes, it’s pretty simple, but you have to start somewhere. Once I’ve finalized more of the nodes I’m planning on building, I’ll be sharing that process but for now I’m just pleased I can get meaningful output from hardware. Next I’ll be trying to integrate that into a 12V motor to test the full hardware/software integration.

Posted in Software Tagged with: , , ,

Prototyping part of the electronic system with Arduino

Computer, PSU and Arduino breadboardWhen I started this project I knew I couldn’t attack it all at once. This was for reasons of time, money and tool access so I have to pick away at it whenever I can. Currently that means working on the low-level Arduino controller and its integration with ROS, using a number of sensors that I had lying around or I bought for the project.

This post will describe the parts I used and go over the Arduino coding in reasonable detail. I won’t be including the full program but will be limited to the subscriber and publisher code that I’m using.

Components

The Arduino is communicating with ROS via the rosserial_arduino node, available on the ROS wiki. It has great documentation and I’ll skip the basic setup steps.

12V fuse block

Power distribution

The primary job is to provide power for all of the subsystems. As I mentioned previously, YardBot is controlled by a Mini ITX computer running Ubuntu and ROS. This box takes 12V DC input and distributes it internally to all related computer systems, like a standard tower PSU. While the robot itself will get 12V power from a 24V battery regulated down, prototyping is easier with a wall-driven source. For that I’m using a 350W computer PSU I’ve modified for electronic projects. I decided to use Traxxas RC power connectors in many places, for their high current capacity and solid connection. The main 12V output on the PSU has a connector soldered on the end that I feed to the fuse block through the AttoPilot sensor. The fuse block has a common ground to make wiring up different parts easy. Eventually YardBot will use a new fuse block for each common voltage level (24V, 12V and 5V).

AttoPilot 45A sensor

Power sensing

Between the PSU output and fuse block is the AttoPilot current and voltage sensor. This monitors the power coming from the batteries for low power situations and keeps an eye on current draw. A ROS node will check the published data to see if it remains inside the safety bounds.

As shown by the Sparkfun documentation, reading the sensor is as simple as monitoring an analog pin and scaling accordingly.

Much of the code here is reasonably self explanatory. You can see that I define a few properties like scaling factor and pins, then assign the ROS message type and publisher topic. All of the topics used by the Arduino will be assigned the /arduino domain to keep things easy to read. I use a timer library to read and publish sensor data on a set time interval.

9DOF IMU and breadboard

IMU data

ROS uses IMU data extensively. The IMU, or Inertial Measurement Unit, uses an accelerometer, gyroscope and optionally a magnetometer to track how a vehicle travels. Used in combination with wheel encoders, the robot can have a reasonably accurate picture of where it is at any given moment. YardBot uses the LSM9DS0 IMU from Sparkfun, with full accelerometer, gyro and magnetometer capabilities on 3 axes each for 9 degrees of freedom. It connects to the Arduino via i2c at 3.3V, so that is the second PCB you can see on the breadboard above. It is a logic level shifter that allows the 5V Arduino to communicate with the 3.3V sensor. The Arduino does very minimal processing in order to avoid delays and blocks so in this case, it produces a standard IMU message and publishes it.

Similar to the power sensor, I define static properties first then build the classes used by ROS and the Arduino directly. The IMU message has 3D vectors for orientation, angular acceleration and linear acceleration, with covariance data for each channel. Since at the moment I don’t have an orientation element, I’ve set the covariance of it to -1 in the array. Covariance itself is a measure of a sensor’s presumed accuracy. Right now I’m using standard ROS recommended values but those will be modified as I gain experience and see valid output.

Much of the missing methods are provided by the SparkFun library, which makes it pretty easy to get meaningful data from the sensor. You might notice that I’m not using the /arduino domain for this sensor, and that’s because standard ROS behaviour is to use /imu_data, which is assumed for other processing nodes.

DHT03 sensor and buzzer

Environmental data

I thought about what other sensors I might like to include on YardBot and one of the easy ones is a temperature and humidity sensor for environmental data. This has safety benefits too, as it allows the robot to monitor itself for overheating and excessive moisture. I’m using a watchdog node that will check the sensor data and provide feedback accordingly. The DHT03 sensor is very common and has a very good library for reading it from Adafruit. I publish both temperature and humidity channels on independent topics.

Once again I use a pretty standard process from the DHT library. The timer runs every second instead of 0.1 seconds because the sensor can only be read at 4Hz, or every 0.25 second. Since environmental data isn’t as critical as something like the IMU, I just publish once per second.

Warning buzzer

This feature is a little more about “what else do I have lying around that I can add in?” but I think it does serve a practical purpose. Shown in the photo above is a 2 wire motherboard speaker used to make that POST beep on computers. Arduino has a method called tone() that oscillates a pin at high frequency to generate a sound, so I’m using it to warn about operating conditions. It’s connected to a ROS subscriber that will likely be used by the watchdog node and the message content contains the number of beeps to make.

After making the node work, I noticed that with all of the callbacks, timers and methods running together, the Arduino is not completely real-time. Even though the timer is set to run every 1/4 second, I can tell the beeps are not consistent. It’s just something I’ll have to keep in mind for future nodes, and is actually the reason I’ve offloaded most of the high cost calculations to the Mini ITX board.

This is the first ROS subscriber on the Arduino, and it receives a simple integer message that corresponds to the number of beeps to make. The callback itself processes the integer and either turns off the beeper directly or sets the number of toggles to make. Every time “toggleBeep” is called, it switches the state of the tone pin.

YardBot LEDs

LED status indicator

Feedback to the robot operator is very important so YardBot uses an LED to share information. The actual robot will be using a full LED strip but for now I’m starting work with a simple 5mm RGB LED. It’s controlled by the LED topic and a custom ROS message. The iPhone app I wrote for YardBot can control the LED directly but the primary driver will be from other nodes sharing their statuses. For example, it glows green when first connected, then will glow yellow for current usage and blink red when the batteries are low.

iPhone app screenshotThis is a screenshot of the native iPhone app I wrote using my custom ROSbridge library and it provides a method to send the red, green and blue colour channels, the LED mode (on, off or blink) and blink interval.

The LED code uses RGB and Colour libraries I wrote to encapsulate colour channels. It’s simpler than storing red, green and blue variables at the top level of the program. Once again we assign relevant pins, build the ROS objects as required and define the subscriber code. Inside the callback the LED mode is assigned based on the message mode and a colour is built from the message colour channels. Only the “blink” mode has anything of real interest, as I start a timer based on the message interval then toggle the colour with the method toggleLED.

With all of the components connected and the Arduino running, start the serial_node program with rosrun. Once it’s connected, you can monitor the data stream by using rostopic echo.

Even though the Arduino has many capabilities, it’s important to remember its limitations and use it as a low-level controller rather than doing expensive calculations. Hopefully this provides a solid base to build and improve on during the project.

Posted in Design Tagged with: , , , , ,

Planning the robot’s systems

A robot, or any other engineering project, requires a careful round of planning and design. In fact, the design stage takes the most time, percentage wise, and the more details that are worked out early on, the easier and smoother actual construction should go (I say should because design mistakes can happen and may not be caught until parts come together). Project complexity goes up significantly as systems are added and removed, so it’s important to design them all properly.

Since I’ve thought a lot already about what capabilities YardBot will have, I thought I’d detail the systems that I’m going to build in.

Mechanical system diagram

Mechanical System

Being a hardworking yard robot, YardBot will be made from sturdy material. I’m planning on 3/8″ thick aluminum plate, which will hopefully be used in many different places to make sourcing parts as well as manufacturing easier. With 16″ snowblower wheels on the outside, the wheel shafts are supported by a standard D shaft between two bearing plates. Between the plates is a chain socket to string chain between the wheel shaft and motor shaft at the center. A chain is required to allow one motor to power two wheels together. Using a belt is also an option. I’m still investigating that, and at the moment I feel that a chain will provide a stronger connection between motors and tires.

Separate from the main propulsion system is the ability to power and drive other 12V attachments. The idea that spawned the project was to have something to shovel the driveway, so I’m in the process of designing a way to mount a standard snow shovel to the front, with 2 linear actuators connected to allow the shovel to yaw side to side and lift up and down. These attachments will be fastened to the front tabs, or hitched to the rear. My hope is that I can use a variety of yard equipment for different jobs (no more hauling leaf bags!).

High level electrical schematic

Electrical System

All of these devices need to be powered. For that, I plan on using 2 12V lead acid batteries in series for 24V. That voltage is primarily because most wheelchair motors operate at 24V. Since this isn’t all that common for other electrical gear and controllers, it will be stepped down to both 12V and 5V of onboard power. The best way to do this efficiently is to use a DC-DC switching step down converter. A standard automotive fuse block is used to provide a common ground to the battery and break out the different voltages.

There are multiple sensors and input devices connected to the fuse blocks, and each needs to have a clear path back to the battery. As shown in the high level schematic above, there is a Mini ITX computer, Xbox Kinect and linear actuators drawing power from 12V, while the 5V block provides power to the onboard WIFI router and LED strip. Additional power for 3.3V sensors is provided by the onboard voltage regulator of the Arduino MEGA.

Crucially, at the very top of the chain is a current and voltage sensor on the 24V line. This data will be fed into the Arduino as a sort of “watchdog” program. The different components have certain current ratings, and with two wheelchair motors providing 10s of Amps of current, it’s important to monitor everything. Additionally it allows the system to read the battery voltage and alert me accordingly.

Communication system diagram

Communication System

With so many devices sending and receiving info, it’s important to plan how each communicates together. This high-level diagram illustrates the communication path for the major components. There is a mixture of one-way and bidirectional communication, along with wired and wireless protocols. The primary interconnect to the Arduino and Mini ITX computer, running ROS. The Arduino acts as an actuator for the high level planning and processing done by ROS. Its role is to take the sensor inputs and publish them to the ROS system, as well as subscribe to ROS messages for outputs. Sensors connect to the Arduino by using analog input (current/voltage sensor), i2c (IMU) or serial (motor controllers), with the GPS receiver and Kinect talking to ROS with USB. I hope to be able to use the Kinect for rudimentary path finding, but it’s a significant challenge. The GPS sensor I bought is not as accurate as commercial units, but I’m optimistic I can take advantage of it (GPS based hockey rink clearing!).

Integrating this many different systems together will definitely be an interesting learning experience. I hope that by planning things out as much as possible beforehand I can learn about the right way to do things and help construction go smoothly when I get started.

Posted in Design Tagged with: , , ,