Sunday, May 28, 2017

Arduino 101 - An Introduction to the Intel Curie Module Development Board

This post is about the Arduino/Genuino Board 101 - the Intel Curie Module development board. It is a not an introduction to Arduino, AKA Arduino 101.


 

Introduction

This post is just a quick introduction to the Arduino 101. I plan to do a couple of projects in the future involving it, and I want to document a few of the questions I had when initially considering whether or not this board will work for me. I will likely update this post with any other issues I run into. 

The Arduino 101 is very different from the classic Atmel AVR based chips the world has come to know and love. The old AVR based Arduinos (easily spotted by the plethera of low cost generics available on sites like eBay) are traditional microcontroller development boards. They are basically just microcontrollers packaged conveniently and paired with the all important Arduino IDE. While I honestly have had very little exposure to most of the vast array of new boards covering the Arduino universe these days, I can say the Arduino 101 is not your slightly-younger-self's AVR. It instead is based on the very capable Intel Curie Module and wraps it in a software architecture to give you a board that looks and feels like an Arduino Uno but performs like something else entirely. Bluetooth Low Energy (BLE) support and a built in IMU make this a very capable little board for $30. While it is being marketed as an internet of things board, I say why has no one made this into a drone yet?

Overall the Arduino 101 looks like a very powerful board for anyone with the willingness to dig into the datasheets. As it is further developed, I have no doubt it will become a hallmark of the new multi-core (non-AVR) Arduino family. 

Questions Answered

What IMU is in the Arduino 101?


Is there an included IMU sensor fusion algorithm?

It does not appear that there is any sort of sensor fusion capability exposed at the Arduino level at the time of this writing. However, the 32 MHz processor is more than capable of running the Madgwick algorithm, and there is a library ready to go out of the box. I imagine it is only a matter of time before it or some Kalman filter variant is included in the Curie download or sensor fusion is implemented at a lower level. See the visualization tutorial.



Troubleshooting

Uploading Script Problem

When I first tried to use the Arduino 101 I got the "ERROR: Timed out waiting for Arduino 101 on COM##" error. No amount of  pressing the Master Reset would fix it. I was running Curie Core 2.0.2 on Windows 7, so I tried reverting to 1.0.7. Then I tried running as an administrator. Eventually I tried changing USB ports. My computer has a 2.0 port as well as a 3.0. When I changed to the USB 2.0 it worked. This could very well mean that I simply have a flaky USB port. I've certainly triggered the fuse on it a few times. However, I mention it here simply in case someone else has this problem. In my case, switching to my USB 2.0 port fixed it.

Matthew




Saturday, November 26, 2016

Arduino Interrupt Stepper Driver - CTC Mode

Introduction to the Problem

This tutorial will show how to drive a Pololu style stepper (A4988) driver using a timer interrupt. This method is non blocking, efficient, and as far as I know is pretty much what most 3D printer firmwares use.

The idea is this. A pololu style stepper driver (the kind that plugs into the RAMPS board) only requires two inputs from the Arduino. One is a direction pin. The other is a pulse train. One rising edge equals one step (or micro step, depending on how the set pins are wired). Most people when they first get going with steppers probably do one of two things. 1) They use some library that does all this for them (I don't know if one exists, but maybe it does) or 2) They just throw a digitalWrite in the loop() and pulse it that way. The problem with that is that it is dependent on the speed with which the loop runs. Enter Timer Interrupts

Interrupts - Conceptually

The timer interrupt is a low level feature of the ATmega family. It is not something that is provided by Arduino, and in fact functions such as millis() and delay() are based on them. I have always been a bit surprised that Arduino does not break timer interrupts out a little. They are really pretty easy to use but are very powerful. I am not going to go into great detail on the specifics of timer interrupts because there are other sources out there. The best of which is the ATmega datasheet.

The idea is this - the ATmega CPU is sitting there executing your code, pulling commands off of the stack. It does this in the same order each time. On another part of the chip there is this thing called a timer. It is counting up from 0 to some value over and over again incrementing at a set frequency. When it reaches the target value it sets a flag and goes back to 0. When that flag is set, the ATmega chip sees it and says, "it is time to execute a special piece of code. Drop everything and do it." What ever it was doing before goes back on the stack and what you put in the "interrupt service routine (ISR)" gets executed. Then it goes back to its normal business. We want to put our "pulse stepper driver" code in the ISR.

There are a couple of dangers with this, but I will just leave you with this. Keep the ISR short. Don't do any serial prints or heavy computations (floating point math) in there. Calculate those ahead of time and pull them in as compile time constants ideally.

Solving the Problem

Now I actually came up with 3 ways of solving this problem
  1. Using a fixed rate Timer Interrupt and only pulsing on some of the ISRs
  2. Using CTC mode and pulsing inside the ISR
  3. Using a special PWM mode 
This tutorial covers method 2. It uses Timer5 in Clear Timer on Compare (CTC) Mode. This allows you to call an interrupt at whatever frequency you want. If you're familiar with timer interrupts  the picture below might help. Again, I will not take the time to go into that much detail on that in this post. For now, I will point you to the ATMega datasheet which covers all of this stuff and THIS post by maxembedded.
CTC Mode - From ATMega Datasheet

Another important point is that I use direct port manipulation in the interrupt. I will not cover that here, but there are numerous examples online of how that works in addition to the ATMega datasheet. HERE is one example. I use direct port manipulation because it is much faster. As stated above, the ISR should execute as quickly as possible.

The Practical Stuff

Copy the code below. Wire it according to pins set in the code. Change the pulses per second calculation based on your setup (change it in the ISR Location calculation too). Set targSpeed in mm/s. Then set the Z_DIR_PIN and DirFlag based on the direction you want to drive. Test your code.

I hope this is helpful to someone. If it is, please let me know in the comments. If anyone that reads this has any insight into libraries available or other methods, comment those too. Good luck!

-Matthew



/*
 * Drives stepper using a pololu stepper driver and timer interrupts
 * 
 * This example uses pinouts associated with RAMPS 1.4 z-axis
 * 
 * Last edited by Matthew 11/14/2016 Arduino 1.6.7
 *                projectsfromtech.blogspot.com
 * TRCCR1A/B               
 * COM1A = 0b00 - disconnect OCR
 * WGM1 = 0b0100 - Fast PWM with the top value at compare match
 * CS1  = 0b001 - no prescaling               
 * ICNC1 = ICES = 0b0 - doesn't apply
 * 
 * */

const byte Z_STEP_PIN    =     46;
const byte Z_DIR_PIN     =     48;
const byte Z_ENABLE_PIN  =     62;  //62

//Interrupt Variables
volatile uint16_t PulseOnISRNum = 0;
volatile uint16_t isrSincePulse = 0;

//============================================================================
void setup() {
  Serial.begin(115200);

  pinMode(Z_STEP_PIN, OUTPUT);
  pinMode(Z_ENABLE_PIN,OUTPUT);
  pinMode(Z_DIR_PIN, OUTPUT);

  //setup Timer1
  TCCR5A = 0b00000000;
  TCCR5B = 0b00001001;
  TIMSK5 |= 0b00000010;       //set for output compare interrupt
  sei();                      //enables interrups. Use cli() to turn them off
}

float targSpeed = 2.5;       // mm/s
float PPS = 0;               // Pulses Per Second
int8_t DirFlag = 1;          // Direction flag. Set this to keep track of location
int32_t Location = 0;        // nanometers (m*10^-9) scaled by 10^-6 to avoid floating point math in interrupt

long clk = micros();


//============================================================================
void loop() {
  //Set Direction
  digitalWrite(Z_DIR_PIN, LOW);     // Low is forward   (based on setup)
  DirFlag = 1;
//  digitalWrite(Z_DIR_PIN,HIGH);       // High is backward (based on setup)
//  DirFlag = -1;
  digitalWrite(Z_ENABLE_PIN , LOW);   // Active Low

  // Set Speed - these calculation are based on your harware setup
  //           - Mine are for 1/16 microstepping and an m5 threaded rod driving the stage
  //------------------------
  for(float ind = 0 ; ind <3.0 ; ind = ind+0.0005)
  {
  targSpeed = ind;            // mm/s
  PPS = targSpeed * 4000;     //Pulses/s
  OCR5A = 16000000/PPS - 1;   //equation from pg 146 in datasheet- removed factor of 2 b/c I am manually pulsing in an interrupt every time
  Serial.print("Speed (mm/s): ");
  Serial.print(targSpeed);
  Serial.print("  Loop Time (ms): ");
  Serial.print(micros()-clk);
  Serial.print("  Location (mm): ");
  Serial.println(Location/1000000.);
  clk=micros();
  // Input other code here! Stepper driver will run even if this code is blocking!


}}

//================================================================================




ISR(TIMER5_COMPA_vect) {
//    digitalWrite(46, HIGH);       // Driver only looks for rising edge
//    digitalWrite(46, LOW);        //  DigitalWrite executes in 16 us  
    //Generate Rising Edge
    PORTL =  PORTL |= 0b00001000;   //Direct Port manipulation executes in 450 ns  => 16x faster!
    PORTL =  PORTL &= 0b11110111;
    Location = Location + 250 * DirFlag ;  //Updates Location (based on 4000 Pulses/mm)
}
    

Saturday, November 19, 2016

Raspian ROS on Raspberry PI B+ with Downloadable Image

I wanted to share my image of ROS Indigo for a Raspberry Pi B+. When I tried a couple of images I found online, none of them seemed to work, so I had to make my own. I will warn you that it is pretty slow, but ROS is installed. I was originally going to use this onboard a turtlebot, but I decided against it after seeing how slow it was. As far as I know it would work, but the extent of my testing was launching roscore. Here is the process I went through to create the image.

  1. Install Raspian Jessie with Pixel version September 2016
  2. Follow instructions on the ROS wiki for the ROS-Comm version on Indigo
  3. Pull Image using Win32DiskImager

Download the image here: Raspian_PiBPlus_ROS_Indigo_11_17_2016.7z


Notes:

  • It would probably be better to use the minimal version of Raspian. Like I commented above, it is pretty slow
  • I had issues building the catkin workspace. I think it was RAM related as the wiki suggests. I ended up closing everything that was open and running with the default -j4 option, and it worked.
  • Contrary to seemingly popular belief, ROS can be installed on an original Raspberry Pi. It is just painful. My install took several hours.
  • The image is 2.287 Gb compressed and 31.260 Gb uncompressed. 
I hope this is useful to someone.
-Matthew