iOS to µC Using HM-1X in Objective-C

Originally posted on www.letsmakerobots.com

(This node will probably float a bit, have lots of work to do on it. My apologies.)

I’d been wanting to create a bridge between Arduino and iOS for awhile. Not going to lie, not a huge fan of iOS devices, but since my wife won an iPad Mini I’ve begrudgingly accepted they fill a need. Still, my hacking has orbited robotics and any device I can’t connect to a robot frustrate me. Well, a year ago I realized an iPad Mini would connect to an HM-10, and therefore, robot.

Sadly, the app used to connect to the HM-10 was LightBlue, an app with little versatility. However, it allowed me to confirm everything was in place to the connect the iPad Mini and a robot. Of course, I wasn’t willing to pay several hundreds of dollars at the chance I could develop an app. Well, the idea got filed under “NSF.”

But, two months ago I was contacted by Simon Riley, the CEO of Carduino. He asked why I had stopped short of developing an iOS app to interface with the HM-10 BLE Serial modules. My response was short: Lack of funds. I explained to develop in iOS (legally, and therefore weary and worry free) you need an iOS developer’s license and a Mac to develop from; I hadn’t money for either. Simon responded the next day, “Maybe we can help with that.”

Long story short, Carduino donated to the cause and I used my robot allowance (you married guys understand) to purchase the rest. So, what did I get?

Mac Mid 2009

Price ended at $469.99. I spent a little more than I should, but since Carduino had added to the kitty I was worried about getting something I’d be unable to run Xcode. Therefore, I spent a little extra in hopes to get a machine that would allow me to write code efficiently.

I have to take a moment and remind people, I wear a white hat. Dear Amy2865, before you sell a laptop, be sure to log out of your eBay account. Also, Jared Kusma, I’m liking your laptop, but I _did _clean the keyboard thoroughly before using it. And the spots on the screen.

Alright, enough of the teasing. Moving on.

I deal with clinical delusions. But, I’m learning to force them to serve me. I realize I’ll never be as good as I feel in the throes of a delusion. Yet, I’ve allowed these words to guide me,

Believing I can do anything, may not be true. But believing it is enables me to do_ almost_ anything.

Well, when I accepted Carduino’s funds to help develop an app I might have been delusional. I didn’t tell anyone I’d never used a Mac before, let alone wrote Objective-C. But one thing I believed, if I determine myself to do something I will. Of course, my timeframe is my own and the product might be apparently hackish, but it will get done.

Anyway, I admittedly had no idea what I was doing, so I decided to journal as I went.

This brings me to my disclaimer:

I am not a professional programmer. I do not pretend to be. With that, please feel free to point out my mistakes, inefficiencies, or ineffective code in general. Part of the reason I post articles like this is for the peer-review. But don’t expect me to apologize much for stuff I didn’t catch. Working a full-time job in a non-tech field, having a wife in graduate school, raising a four-year-old, well, these things leave me little time to program, and nearly no time for code review.

I don’t think there are mistakes in my code, I know there are. Alright, self-deprecation aside, let’s get going.

1. Setting up the Environment

First, you need a Mac and a Developer’s License. The Mac really needs to be at least 2008 or later to effectively code for the current iOS (7.1 at writing, 8.0 being in beta).

After looking over many “deals” on eBay I decided on a Mac Book Pro 2009. It seemed old enough people didn’t have an unhealthy attachment. Later than 2009, it was like people were selling their pretty daughter.

I chose the Mac Book over Mac Mini. The Mac Book came with a monitor and peripherals. Maxhirez warned me some Mac Mini’s have proprietary video out, which would force me to buy a monitor as well.

I was a a lot worried an eBay Mac would be DOA. When it finally came in, I was relieved to see it boot up. But, within an hour it overheated and crashed. Worried the crap out of me. I then realized this laptop had two video cards and the display settings were full-blast. I backed down the video settings and the temperature seemed to hold. Still a little worried. When I get the app written for Carduino I’ll probably take it apart, clean the heat-sink fins and reapply thermal paste.

So, price for the Mac:$469.99

Well, I had the Mac, now what?

I began researching costs for iOS developers’ license. It’s $99 a year.

This is supposed to allow you to write and publish iOS for the entire year. I bit the bullet and ordered it.

Purchase the Publisher’s License:

Download Xcode

Once you have your Mac and Developer License, time to setup Xcode.

If you try to compile your app and youget an error regarding a certificate, and doesn’t automatically resolve, you can download a certificate manually.

Download Developer certificate

1. Log on to iOS Dev Center and Download you Developer Certificate

You will need to apply this certificate to the apps you write to publish them–even on an ad hoc basis.

2. The App We’ll Write

This write-up describes writing an app for Bluetooth 4.0 iOS devices to enable a serial connection to an Arduino. To facilitate the serial connection on the Arduino-end a HM-10 acts as a peripheral, which in turn, interacts with the Ardunio via a serial connection.

The HM-10 operates on 3.3v and the Arduino 5v, but I created an Instructable on how to convert the HM-10 to 5v.

The HM-10 is a low cost (6.87 USD, shipping ~.20) Bluetooth 4.0 module.

  • Order from Fastech: HM-10

3. Preparing to Develop in Xcode 5

Before I started this projects I’d never used a Mac, never seen Xcode 5, let alone looked at Objective-C code. But, like the delusional man I am, I thought, “Well, it’s got the word ‘C’ in its name; couldn’t be that hard for me to learn.” Stupid me.

Objective-C is silly. Well, I shouldn’t say its entirety is silly; the verbosity and syntax are silly, though. The idea being everything is spelled out, nothing abbreviated, which makes the code chewy to read. Anyway, I’ll stay away from psychological rants about brevity being the essence of wit. Or how humans will psychologically gravitate towards messages easy to encode and decode.

This article isn’t going to go into much on how to write Objective-C or use Xcode, since there are already many excellent guides.

The site I found most useful was Ray Wenderlich’s

His written tutorials are free, but giving the visual component of Xcode I paid $15 for a subscription to his video tutorials. Both written and video tutorials are excellent. Learned pretty much everything I needed from him and his peers.

I would list other tutorials, but really, Ray’s covers everything you’d need to write this app–well, besides the Bluetooth part, which I’ll cover. But one surprisingly helpful video was Apple’s introduction toCoreBluetooth Framework.

  1. 101 Core Bluetooth (You need an Apple Device to watch it.)
  2. Advanced Core Bluetooth (You need an Apple Device to watch it .)

Also, several videos and articles I found:

  1. InvasiveCode
  2. Chris Miles

Lastly, the iOS code I have was not written by me. I’ve just chopped it up in hopes to understand it. The original author is a friend of mine:

4. The UI Layout

The app we’re going to write is pretty simple. Really, it is. It takes the values from two Slider Controls and sends them via Bluetooth to an Ardunio. The Arduino in turn converts these values into direction and PWM values for two wheeled-motors.

Ok, open Xcode and let’s start a new projects. We are going to use a Single View projects.

The first step in creating our app will be laying out the user interface. This boils down to a few items.

View for Background Image:

  • 3 x Labels – Steer Value, Acceleration Value, RX Data
  • 2 x Image Views – for Slider Tracks
  • 2 x Slider Controllers – For PWM Values
  • 2 x Buttons – TEST Send and Scan Devices Menu Button
  • 1 x View – Acts as a hideable container for scanned devices.

The Scan Devices View will act as a container for the Devices Table View. We will set its initial state to hidden and then reveal it programmatically triggered by the Devices Menu Button.

The Scan Devices View will have 2 items.

  • 1 x Button – Back
  • 1 x Table View – Contains BLE Device information

If all goes right, our UI should end up looking something like this:

If you’d like to create your own layout, I’ve created a video you can follow along:

Or if you prefer, you can download my skeleton layout:

Just download the projects as zip. Then, within the projects there is another zip titled: bleAppStartLayout.zip Simply unzip this projects and open it in xCode if you’d like to write your own code to go with the skeleton layout.

5. Code

There are three parts to the code of our app.

Code to control…

  1. The Bluetooth connection
  2. User interface
  3. Devices List

In this article I’m only going to cover the Bluetooth code in depth. The rest is either pretty straightforward

Objective-C Bluetooth Code (and some UI):

Before we get going, it’ll help to be slightly familiar with Bluetooth 4.0’s standards and protocols. Also, iOS’ recommendations on using CoreBluetooth, Apple’s API for Bluetooth 4.0 hardware.

The big take away for us is the differences between Central and Peripheral roles.

This doesn’t mean our bot cant receive data or iOS device can’t send data, it simply defines the relationship between the devices. The role decides which device controls the connection and data flow. For the sake of this app thebot will be setup as a Peripheral and theiOS device will be the Central. This is my opinion, but it seems the BLE hardware connected to the uC or CPU with the greatest speed should take the Central role.

The header file – bleApp.h

To access the Bluetooth 4.0 functionality of compatible iOS devices, Apple provide the CoreBluetooth Framework. This framework is brought into your app code in the typical C fashion, by importing it inbleApp.h

#import <CoreBluetooth/CoreBluetooth.h>

Once the framework is imported we have access to the API methods.

References to the methods can be found here:

Alright, I’m going to attempt explaining something I poorly understand, Objective-C Delegates.

I believe a delegate is a collection of services your code can subscribe. I think of them much like interrupts in Arduino. Each time a specific event happens a method is called. You setup the delegates you wish to subscribe at the top of yourbleApp.h:

@interface ViewController : UIViewController <CBPeripheralDelegate,
CBCentralManagerDelegate, UITableViewDelegate, UITableViewDataSource>

Here we are calling on subscribing to four delegates:

  1. CBPeripheralDelegate
  2. CBCentralMAnagerDelegate
  3. UITableViewDelegate
  4. UITableViewDataSource

The CoreBluetooth Central Manager, the CoreBluetooth Peripheral, User Interface Table View Delegate, and the User Interface Table View Data Source. Right now we are only going tofocus on the Bluetooth delegates.

Another way to think of delegates is a collection of little scout robots who report when a specific event takes place.

These delegates are a collection of little methods who will be called at specific events. For example, the CBPeripheralDelegate has the method-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error. This method is called whenever iOS app discovers BLE peripheral. Again, these methods areevent driven–this means something usually has to happen before the come report to your code.

Here are the major methods we will be using to control the iOS BLE hardware:

  1. centralManagerDidUpdateState
  2. centralManager DidDiscoverPeripheral
  3. centralManager didConnectPeripheral
  4. peripheral didDiscoverServices
  5. peripheral didDiscoverCharacteristicsForService
  6. pierpheral didDiscoverDescriptorsForCharacteristic

Next, we declare the properties we will need. If you know as little about Objective-C properties as I did here’s a good tutorial.

//
//  ViewController.h
//  Carduino
//
//  Created by Ladvien on 6/21/14.
//  Copyright (c) 2014 Honeysuckle Hardware. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <CoreBluetooth/CoreBluetooth.h>

@interface ViewController : UIViewController <CBPeripheralDelegate,
CBCentralManagerDelegate, UITableViewDelegate, UITableViewDataSource>

// Instance of Central Manager.
@property (strong, nonatomic) CBCentralManager *centralManager;
// Stores a list of discovered devices, the key being their UUID.
@property (strong, nonatomic) NSMutableDictionary *devices;
// Instance method, used to act when a peripheral is discovered.
@property (strong, nonatomic) CBPeripheral *discoveredPeripheral;
// Instance method, used to act when a peripheral is selected to connect.
@property (strong, nonatomic) CBPeripheral *selectedPeripheral;
// Holds UUIDs.
@property (readonly, nonatomic) CFUUIDRef UUID;
// Stores peripheral characteristics.
@property (strong, nonatomic) CBCharacteristic *characteristics;
// Stores the advertising data of a peripheral.
@property (strong, nonatomic) NSMutableData *data;
@end

That should be all the code we need in our header file.

bleApp.m – Our Implementation

1. The UI Connection

Objective-C operates under the Modal-View-Controller design modal. We don’t have to go too deep into this design theory to be dangerous, the main thing we want to take away is UI elements are connected to our code with keywords. For UI elements we wish to change programmatically we set aIBOutlet and for UI elements we wish to generate an action we use the-(IBAction) methods.

An example of using an IBOutlet would like this:rxLabel.text = @”Got data”;

An example of a -(IBAction) method would be:

-(IBAction)menuButtonTouchUp:(id)sender{ [do stuff] };

All good, now how do we make IBOutlets and IBActions? First, click on the “Tuxedo” button

Now, hold CONTROL and click on the UI element you want to create an Action or Outlet, then drag to your code between@interface and@end.

Ray Wenderlich’s tutorials explain this process well. So, I wont rehash. A couple hints though, you can type out each of the IBOutlets and IBActions, but unless the dot on the bar next to where it is written is filled in, it is not connected to an element. Also, if you hover your mouse over the little dot while in tuxedo-view, the element it is connected to will be highlighted.

Ok. So, we need to connect up all of our UI elements. I’ll simply refer back to my video on the layout. Or I suggest you use the skeleton bleApp layout, since I’ve already wired up the UI elements.

Either way, we need to end up with code that looks something like this:

#import "ViewController.h"
@interface ViewController ()

// Timers.
@property (nonatomic, retain) NSTimer *steerSliderRecoilTimer;
@property (nonatomic, retain) NSTimer *accelerationSliderRecoilTimer;
@property (strong, nonatomic) IBOutlet UITableView *tableView;

//Outlets.
@property (strong, nonatomic) IBOutlet UIView *mainView;
@property (strong, nonatomic) IBOutlet UILabel *steerLabel;
@property (strong, nonatomic) IBOutlet UISlider *steerSlider;
@property (strong, nonatomic) IBOutlet UISlider *accelerationSlider;
@property (strong, nonatomic) IBOutlet UILabel *accelerationLabel;
@property (strong, nonatomic) IBOutlet UIView *devicesView;
@property (strong, nonatomic) IBOutlet UILabel *RSSI;
@property (strong, nonatomic) IBOutlet UILabel *rxDataLabel;

//Buttons in Devices Table.
@property (strong, nonatomic) IBOutlet UIButton *backFromDevices;
@property (strong, nonatomic) IBOutlet UIButton *test;

//BLE
@property (strong, nonatomic) IBOutlet UIButton *scanForDevices;

// Bytes used for switch-array.
@property (assign) uint8_t accelerationByte;
@property (assign) uint8_t steeringByte;

//Steer slider.
- (IBAction)steerSlider:(id)sender;
- (IBAction)steerSliderTouchUp:(id)sender;
- (IBAction)steerSliderTouchUpOutside:(id)sender;
- (IBAction)steerSliderTouchDown:(id)sender;


// Accceleration slider.
- (IBAction)accelerationSlider:(id)sender;
- (IBAction)accelerationSliderTouchUp:(id)sender;
- (IBAction)accelerationSliderTouchUpOutside:(id)sender;
- (IBAction)accelerationSliderTouchDown:(id)sender;

// Menu
- (IBAction)menuButtonTouchUp:(id)sender;
@end

1. CBCentralManager

Ok, let’s get our Bluetooth going. Objective-C has a method that runs once if the UI loads,-(void)viewDidLoad method.

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Allocates and initializes an instance of the CBCentralManager.
    _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}

We will add more code in this method later, but for now this will work. Here, we are simply allocating and initializing an instance of the CBCentralManager object. It has two arguments,initWithDelegate, we set this to self and the queue we set to nil. This allows us to inherit the CBDelegate from the ViewController.h. The queue being set to nil simply means we are going to allow the CentralManager to manage our data.

centralManagerDidUpdateState

This method is called each time the BLE hardware on the iOS device changes state. Here, we are using it to check if the iOS’ Bluetooth hardware has been turned on.

ThecentralManagerDidUpdateState is a method called by the CoreBluetooth (CB) Central Manager Delegate whenever the BLE hardware in your device changes state. Here, it is being called when our app first begins. It will also be called each time the iOS Bluetooth is turned on or off.

// Make sure iOS BT is on.  Then start scanning.
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    // You should test all scenarios
    if (central.state != CBCentralManagerStatePoweredOn) {
        // In case Bluetooth is off.
        return;
        // Need to add code here stating unable to access Bluetooth.
    }
    if (central.state == CBCentralManagerStatePoweredOn) {
        //If it's on, scan for devices.
        [_centralManager scanForPeripheralsWithServices:nil options:nil];
    }
}

The central.state property is set by the CBCentralManager Delegate. It has six states:

  1. CBCentralManagerStateUnknown – Device can’t be read, etc.
  2. CBCentralManagerStateResetting – Device is resetting
  3. CBCentralManagerStateUnsupported – this device doesn’t support BLE.
  4. CBCentralManagerStateUnauthorized – Your app isn’t authorized to use BLE
  5. CBCentralManagerStatePoweredOff
  6. CBCentralManagerStatePoweredOn

We will only be using the last two states. Our code checks if the BLE hardware is enabled; if it is not, it does nothing. Eventually, I’ll probably add an alert to notify the user, but right now, it does nothing. If the hardware is enabled, then it executes the centralManager instance method with two argumentsscanForPeripheralsWithServices: nil andoptions: nil.

In case you didn’t have time to read the BLE protocol manual, I’m going to give you a crash course. Let’s start with the service tree. The magic of Bluetooth lies in its advertisment protocol. The Central BLE device is scanning the air, while the Peripheral is advertising its information. The information advertised coordinates services the peripheral device has available.

If you have a minute, Ada has an excellent article on Generic Attribute Profile (GATT) written by Keven Townsend (I like his stuff).

Keep two things in mind, first, I’m still learning what the hell I’m talking about. Two, jnhuamao and I have a history. I’ve watched their BLE firmware develop over the years. When the first procuded the HM-10, it didn’t conform to any BLE protocols. Now, they’ve got a damn fine product. Of course, they seem to be trying to get old school Bluetooth thinking to fit BLE. For instance, they equate the “Master” role of their modules with Central role protocol. Likewise, they equate “Slave” with Peripheral role. This confuses me a little, since

For the HM-10 it looks something like this,

When iDevice scans the HM-10 it’ll report back the FFE1 characteristic, which is the characteristic address for RX/TX on the HM-10.

centralManager didDiscoverPeripheral

The centralManager didDiscoverPeripheral method executes every time a new service has been discovered. It provides several bits of information about the discovered peripheral. First, the peripheral information itself, this includes its name, UUID, etc. Further information can be pulled from the advertisementData dictionary. Lastly, which is a neat attribute of BLE, you can access the RSSI of the discovered device before ever connecting.

// Report what devices have been found.
- (void)centralManager:(CBCentralManager *)central
 didDiscoverPeripheral:(CBPeripheral *)peripheral
     advertisementData:(NSDictionary *)advertisementData
                  RSSI:(NSNumber *)RSSI
{
    // Set peripheral.
    _discoveredPeripheral = peripheral;

    // Create a string for the discovered peripheral.
    NSString * uuid = [[peripheral identifier] UUIDString];

    if (uuid) //Make sure we got the UUID.
    {
        //This sets the devices object.peripheral = uuid
        [self.devices setObject:peripheral forKey:uuid];
    }

    //Refresh data in the table.
    [self.tableView reloadData];

}

9:Our code set an instance variable_discoveredPeripheral to the most recent discovered peripheral.

12: Creates a string variable and sets it to the discovered peripheral’s UUID.

14: Checks to see if we got a proper UUID string in the uuid variable.

17: Here we are calling the setter method for thedevices NSMutableDictionary. We are setting the object service information from the discovered peripheral and the key is the discovered peripheral’s UUID. This is going to allow us to recall at least 6 discovered services.

- (NSMutableDictionary *)devices Sett Method

We are going to store the last six peripherals discovered.

- (NSMutableDictionary *)devices
{
    // Make sure the device dictionary is empty.
    if (_devices == nil)
    {
        // Let's get the top 6 devices.
        _devices = [NSMutableDictionary dictionaryWithCapacity:6];
    }
    // Return a dictionary of devices.
    return _devices;
}

4: We check to see if we’ve initialized the dictionary. 7: If we haven’t then we setup the dictionary with a six device slots, then, we set a slot to the last discovered device.

10: When we are done, we return the devices dictionary.

The devices method will be called many times throughout our program. Eventually, we will use the dictionary to populate a table of discovered devices.

centralManager didConnect

The centralManager didConnect method executes whenever your app connects to a specific BLE device.

// Run this whenever we have connected to a device.
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {

    // Set the peripheral delegate.
    peripheral.delegate = self;
    // Set the peripheral method's discoverServices to nil,
    // this searches for all services, its slower but inclusive.
    [peripheral discoverServices:nil];
}

5:Once we’ve connected we activate the peripheral delegate methods.

8: After we have connected to a particular peripheral, we call theperipheral discoverServices method. Again, by setting thediscoverServices tonil we search for all services on our newly connected peripheral.

2. CBPeripheralDelegate

peripheral didDiscoverServices

Here, we enumerate through all the services on the connected peripheral. This is a slow way to discover services, but it’s inclusive and easy. And since the HM-10 only has two services, and only one service active at a time, we don’t lose any time.

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    // Enumerate through all services on the connected peripheral.
    for (CBService * service in [peripheral services])
    {
        // Discover all characteristics for this service.
        [_selectedPeripheral discoverCharacteristics:nil forService:service];
    }
}

4: This is a fancy for-loop called enumeration. It goes through all the services listed in the(CBPeripheral *)peripheral, which is a small list on the HM-10. If it is in the peripheral role, which is default, it only has one service.

7: Here we calldiscoverCharacteristics method on each service on our connected device. Again, passing thenil argument means we want to discover all characteristics, as oppossed to a specific. Slow, but inclusive.

peripheral didDiscoverCharacteristicsForService

For each service, we enumerate each of its characteristics.

- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverCharacteristicsForService:(CBService *)service
             error:(NSError *)error
{
    // Enumerate through all services on the connected peripheral.
    for (CBCharacteristic * character in [service characteristics])
    {
        // Discover all descriptors for each characteristic.
        [_selectedPeripheral discoverDescriptorsForCharacteristic:character];
    }
}

4: We go through each characteristic of each service on the connected peripheral.

7: We call thediscoverDescriptorsForCharacteristic method on each discovered characteristics.

peripheral didDiscoverDescriptorsForCharacteristic

We are accomplishing two things in this method. First, we are getting the character version of the hex values FFE0

6:The firs thing we do is convert the HM-10’s characteristics from FFE1 to character values, 255 and 225.

8:Next, we check to see if we got two characters, and they are 255 and 225

12-23: We do a quick enumeration through the services and characteristics. For each characteristic, for each service, we call the selectedPeripheral setter method. We pass thesetNotifyValue argument totrue. This automatically receives serial data. Each time serial data is received the method

-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error

{

    //Put RX data collection here.

}

We’ll write our RX method when we get to UI, since we’ll set our rxDataLabel to automatically update with incoming data.

Also, the we are setting up an automatic RX notification method. But, another way to do this is by setting thesetNotifyValue to false. Then, each time you want to get RX data you can call thedidUpdateValueForCharacteristic method manually.

- (void)peripheral:(CBPeripheral *)peripheral
didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic
             error:(NSError *)error
{
    //Store data from the UUID in byte format, save in the bytes variable.
    const char * bytes =[(NSData*)[[characteristic UUID] data] bytes];
    //Check to see if it is two bytes long, and they are both FF and E1.
    if (bytes && strlen(bytes) == 2 && bytes[0] == (char)255 && bytes[1] == (char)225)
    {
        // We set the connected peripheral data to the instance peripheral data.
        _selectedPeripheral = peripheral;
        for (CBService * service in [_selectedPeripheral services])
        {

            for (CBCharacteristic * characteristic in [service characteristics])
            {
                // For every characteristic on every service, on the connected peripheral
                // set the setNotifyValue to true.
                [_selectedPeripheral setNotifyValue:true forCharacteristic:characteristic];
            }
        }
    }
}

sendValue

This method is called whenever we want to send information to the peripheral. It has data passing argumentstr, but we wont be using it. The app we are writing automatically assemblies a data string and send it to the peripheral each time it is called. To send our data we simply must insure it is in the appropriate variable.

This app takes the values of two slider with a range of -255 to 255. We then do a little data manipulation. On the iOS device a byte takes 8 bits. Same for an unsigned character. But I found if you assign a value greater than 127 then ARC will automatically generate two-bytes for a single unsigned value. To get around this and hang on to full resolution of the Arduino, we convert the slider ranges from 255 to 125-0 or 125-1. The one is a bit set in a switch-array,controlByte. Then, when the Arduino receives the data it converts it back to full range, 255.

Regarding the direction, using the same switch array,controlByte, weset a bit low or high depending on whether the slider indicates 0 to -255 or 0 to 255. Again, when this makes it to the Arduino it is converted into direction of the motors.

Ok! Let’s step through the code.

- (void)sendValue:(NSString *) str
{
    for (CBService * service in [_selectedPeripheral services])
    {
        for (CBCharacteristic * characteristic in [service characteristics])
        {
            // Round the float.
            steeringValue = lroundf(self.steerSlider.value);
            accelerationValue = lroundf(self.accelerationSlider.value);

            // SEND STRING
            //  DIR-MA    DIR-MB    PWM-MA  PWMA-MB EOTC
            //  CON Byte  CON Byte   0-255   0-255    :
            NSMutableData *myData = [NSMutableData data];

            // CONTROL BYTE
            //  BIT: 7=CAN'T BE USED
            //  BIT: 6=
            //  BIT: 5=Breaklights ON
            //  BIT: 4=Headlights ON
            //  BIT: 3=127+ MOTOR B
            //  BIT: 2=127+ MOTOR A
            //  BIT: 1=MOTOR B DIR
            //  BIT: 0=MOTOR A DIR
            NSUInteger controlByte = 0;


            //Steer value is negative number.
            if(steeringValue < 0)
            {
                // Set the reverse bit.
                controlByte |= 1 << 0;
                steeringValue = (steeringValue * -1);
            }

            // Acceleration value is a negative number.
            if(accelerationValue < 0)
            {
                // Set the reverse bit.
                controlByte |= 1 << 1;
                accelerationValue = (accelerationValue * -1);
            }

            // If steer motor is greater than 127.
            if (steeringValue > 127) {
                // Set the bit indicating 128-255.
                controlByte |= 1 << 2;
                // Remove excess from text.label
                steeringValue -= 128;
            }

            // If steer motor is greater than 127.
            if (accelerationValue > 127) {
                // Set the bit indicating 128-255.
                controlByte |= 1 << 3;
                // Remove excess from text.label
                accelerationValue -= 128;
            }

            //NSLog(@"After: %i", controlByte);
            // Breaklights
            //controlByte |= 1 << 5;
            // Headlights
            //controlByte |= 1 << 4;

            // Load all the data into myData.
            [myData appendBytes:&controlByte length:sizeof(unsigned char)];
            [myData appendBytes:&steeringValue length:sizeof(unsigned char)];
            [myData appendBytes:&accelerationValue length:sizeof(unsigned char)];

            // Create a string with all the data, formatted in ASCII.
            NSString * strData = [[NSString alloc] initWithData:myData encoding:NSASCIIStringEncoding];
            // Add the end-of-transmission character to allow the
            // Arduino to parse the string
            str = [NSString stringWithFormat:@"%@:", strData];

            // Write the str variable with all our movement data.
            [_selectedPeripheral writeValue:[str dataUsingEncoding:NSUTF8StringEncoding]
            forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
                self.rxData = @" ";
        }
    }
}

3-6:Like before, we are enumerating through all services and characteristics on our connected peripheral.

8-9: We get the slider values, round them into an integer and load them into appropriate integer variables steeringValue and accelerationValue.

14:Setup a data variable to hold our send string.

25:We create a byte variable to act as our switch-array.

29-42:Determine direction the motors should go based on the sign of the sliders.

45-58: Decide whether we need to divide the range.

67-69:Load the processed data into data variable.

72: Create a string using the data we’ve processed, then, convert it to ASCII to be sent to the Arduino.

75:Add the “:” character, which will act as our end-of-transmission character.

78: Finally, we send the completed data string to the peripheral.

Voila!

Full source code for this projects can be found here:

Here’s the Arduino sketch that goes with it:

FTDI Bitbanging GCC

Originally posted on www.letsmakerobots.com

This is a short note on how to setup a C programming environment for the FTDI chip in bit banging mode, since that’s what I had difficulty doing.

There may be easier ways to go about this, but I wanted to use GCC to compile a small C program to control the 8 IOs. The purpose was to write a small command-line program that would reset my LPC1114 before and after programming.

To setup the environment:

1. I downloaded and setup MinGW32.

2. I then downloaded FTD2XX libraries. This included the ftd2xx.h file and ftd2xx.lib.

3. I then stole the test code from Hack-a-Day’s article on bitbanging with the FTDI.

4. I modified the code as they suggested by including, in this order, the Windows compatibility files:

#include <stdio.h>
#include <stdarg.h>
#include <windows.h>
#include <windef.h>
#include <winnt.h>
#include <winbase.h>
#include <string.h>
#include <math.h>
#include "ftd2xx.h"

5. I then used the rest of their code as a base: Hack-a-Day’s FTDI PWM Code

I used this line to build it:

$ gcc -o ftdi_PWM ftdi_Test.c -L./ -lftd2xx

You must have both the ftd2xx.h and ftd2xx.lib in the same directory as you attempt to build.

6. I then wrote two programs, one to send DTR and CTS high and low in order to reset the LPC1114 into programming mode. ** Second, to send DTR and CTS high and low in order to send the LPC1114 into **run program mode. The idea being, I could use the typical Sparkfun FTDI programmer to program my LPC1114.

  1. LPC1114_reset_to_program
  2. LPC1114_reset_to_bootloader

That’s it. Just wanted to make sure this was out in the universe for the next guy’s sake.

LPC1114 -- GCC Toolchain Setup

Originally posted on www.letsmakerobots.com

UPDATE: I tweaked the source and rebuilt lpc21isp to allow for automatic mode switching, bootloader and program, from an FTDI breakout.

A few months ago Bdk6 sent me an LPC1114 ARM processor. Not going to lie, I had little idea how to use the chip.

Bdk6 and his kids had created the Valdez family with the chip:

I tried several IDEs to get the chip going. I wasn’t happy with any of them.

LPCXpresso was confusing and intimidating. Since I was trying to learn the chip and a new IDE. Add to this, NXP didn’t have libraries for the chip, so I was trying to integrate the LPC1114 CodeBase libraries. They appeared to be incomplete and unkept. It didn’t matter, I couldn’t seem to integrate the libraries into LPCExpresso.

I then started using Mbed. A lot more luck there. But it was uncomfortable. I’m betting most reading are familiar with Mbed, therefore, I won’t go into the usual rants about it being webbased and closed-source.

There are other problems with Mbed.

First, it is not a complete development solution. You need a flashing tool to upload code to the LPC1114 chip. The easiest tool to use is FlashMagic, which gives you a nice GUI to interact with the LPC1114. There is a slight problem, Mbed produces a .bin file and the LPC1114 needs a .hex file, subsequently, FlashMagic only allows uploading of .hex files. So, you have to use a third tool to convert the file from .bin to .hex before uploading. Sigh. It’s a lot of trouble.

Anyway, I eventually got it to blink a light

I craved more freedom, so I started looking for tools that’d allow me to code for the LPC1114 freely. A bare-metal solution. Just me, a compiler, and the LPC1114 User Manual (datasheet). Luckily, most of the work had been done for me. Frank Duignan, Ted Burke, and Bdk6 had pretty much all the answers pre-compiled for my little brain. Here’s the steps I used to get a command-line programming environment setup.

1. Download and install GNU Tools for ARM Embedded Processors (Win32 Release – 2013, quarter 3).During the installation, make sure to check the box “Add path to environment variable.”

Check “Add environment variable.”

If you missed this part, you can add a path to the environment variables by:

Right clicking on This PC / My Computer –> Properties –> Advanced system settings –> Environment Variables –> Select “Path” under “System Variables –> Edit. Go to the end of the list of paths, add a semicolon, then place the path of the GNU tools bin.

For me, this was “C:\Program Files (x86)\GNU Tools ARM Embedded\4.7 2013q3\bin

We are going to add several paths to the path systems variables. So, refer back to these steps as needed.

2. Download Frank Duignan’s Windows linker script, LPC1114 header file, and build batch file.

Duignan’s LPC1114 tools

Ted Burke was nice enough to put these up for us. However, there’s two pieces missing for us to use these amazing tools.

3. Create a workspace folder. e.g., “C:\Users\Ladvien\Documents\LPC1114_Bare_Metal”.

4. Install binutils for file conversion. Binutils has to be compiled for Windows, though, I was able to find them pre-compiled.

Download Binutils compiled for Windows

Really, we are only using Binutils for objcopy, which is at the end of the batch file. This translates the .elf produced by the ARM compiler into a .hex file. To unzip Binutils file I’d recommend using 7zip. After installing them add the bin folder to your environment variable (see step 1). For me, I added “C:\Users\Ladvien\Documents\LPC1114_Bare_Metal\Ming32\bin”.

5. Create a build script in a batch file.

Create a build batch file recommend by Duignan and Burke. Open your workspace folder, create a new text file, enter the following:

arm-none-eabi-gcc -mcpu=0 -mthumb -v -g -c init.c -o init.o
arm-none-eabi-gcc -mcpu=0 -mthumb -v -g -c main.c -o main.o
arm-none-eabi-ld init.o main.o -v -L "C:\Program Files (x86)\GNU Tools ARM Embedded\4.7 2013q3\lib\gcc\arm-none-eabi\4.7.4\armv6-m" -lgcc -T linker_script.ld --cref -Map main.map -nostartfiles -o main.elf
objcopy -O ihex main.elf main.hex

Save the text file in your workspace as “build.bat” Be sure to include the quotation marks, since this will convert the file from a text file to a batch file. This is the same build commands put together by Duignan, but I’ve added the “-v” option. This is the verbose mode and will spit out an errors during compiling.

6. Setup a C++ friendly text editor, like Programmer’s Notepad.

7. Create a file called main.c in your workspace directory. Enter the following text:

/* Simple PWM demonstrator program
 * The program simply ramps the duty of pin 10
 * from 0% to 100%  and then resets back to 0%
 *
 */

#include "lpc111x.h"

void ConfigPins()
{
	SYSAHBCLKCTRL |= BIT6 + BIT16; // Turn on clock for GPIO and IOCON

	// Begin Port 0 setup.
	// Make Port 0 bit 5 behave as a generic output port (open drain)
	IOCON_PIO0_5 |= BIT8;
	// Make Port 0 bit 10 behave as a generic I/O port
	IOCON_SWCLK_PIO0_10  = 1;
	// Make Port 0 bit 11 behave as a generic I/O port
	IOCON_R_PIO0_11  = 1;
	// End Port 0 setup.


	// Make pin 10 behave as a PWM output CT32B1_MAT0
	IOCON_R_PIO1_1 |= BIT1 + BIT0;
}
void initPWM()
{
	// will use counter/timer CT32B1
	// Turn on CT32B1
	SYSAHBCLKCTRL |= BIT10;
	// Use match register 3 as period register because its output
	// is not pinned out.  A value of 48000000 produces a frequency of 1Hz
	// so, to generate a 30kHz pwm signal, set MR3 = 48000000/30000 = 1600
	TMR32B1MR3 = 1600;
	TMR32B1MR0 = 1600; // Zero output to begin with
	TMR32B1MCR = BIT10; // Reset TC on match with MR3
	TMR32B1TC = 0 ; // Zero the counter to begin with
	TMR32B1PWMC = BIT0; // Enable PWM on channel 0
	TMR32B1TCR = 1; // Enable the timer

}
void setDuty(int Duty)
{
	// sets the duty to the percent specified.
	// Need to 'invert' the requested duty as the PWM mechanism
	// resets the output at the start of each PWM cycle and then
	// sets it on match.
	TMR32B1MR0 = (100-Duty) << 4;
}
void delay(int dly)
{
	while(dly--);
}
int main()
{
	int Duty=50;
	ConfigPins();
	initPWM();
	while(1)
	{
		setDuty(Duty++);
		if (Duty > 100){
			for (Duty > 1; Duty--;){
				setDuty(Duty);
				delay(100000);
			}
		}
		delay(100000);
	}
}

Save the main.c file.

I’ve modified the above code from Duignan’s to make it comparable to the Fade sketch in the Arduino examples.

8. Open the command prompt in your workspace directory. Run your build.bat file.

After running the build.bat, it should build five files: **main.o, int.o, main.map, main.elf, main.hex. **If it doesn’t build correctly, double check the path variables for both the compiler and binutils.

We still have the problem of getting the main.hex uploaded to the LPC1114. You can use FlashMagic, like above, but I’m trying to stick to the command line, that’s where lpc21isp comes in.

I’ve pre-built lpc21isp for Windows.

Download LPC21ISP (now with automatic mode switching! :)

But if this doesn’t work for you, then you’ll have to build it yourself.

10. Create a another batch file called,LPC1114_upload.bat

Only one line this time:

lpc21isp -wipe -localecho -hex main.hex COM3 57600 12000

You’ll have to adjust the COM port to the port you are using. Here is a little bit of a** guide using lpc21isp**. Also, you’ll either need to put the lpc21isp file in one of the folders added in the path variable. Or, make sure the LPC1114_upload.bat and lpc21isp files are in the same directory as your main.hex.

11. Wire up your LPC1114.

One last bit I should point out, when “DP24” is connected to ground and then voltage is supplied to the LPC1114, it’ll enter the hardware bootloader. But, if DP24 is open or (preferably) pulled-up with a resistor when voltage is supplied to the LPC1114 then it’ll run whatever code has been uploaded to the flash memory.

“DP24” is actually pin 1 on port 0.

12. Connect your LPC1114’s RX/TX to an serial connector, put it into the bootloader mode by connecting DP24 to ground, then apply power to the LPC1114. Lastly, run the LPC1114_upload.bat file. This should result in the LED connected to “SWDIO” pin to fade on and off.

And that’s what I’ve got. I’m going to start working on coding now, so I’ll trade to add to this write-up as I’ve more to share. I plan to try these steps on my lab machine around June 1st to make sure they work. But if anyone uses them before them, please let me know if there are corrections to be made. As always, I value feedback and critique.

Update: FTDI Mode switching

The lpc21isp allows for automatic mode switching, that is, you can use an FTDI cable as below:

Then replace the line in your LPC1114_upload.bat file with

lpc21isp -wipe -localecho -control -hex main.hex COM3 57600 12000

This will automatically put the LPC1114 into program mode, upload your code, then reset to run your newly uploaded program. Just like Arduino! (Bdk6, you didn’t see that statement, right? :)

Of course, lpc21isp is an agglomeration and had an error(?) that wouldn’t reset the chip after downloading the new code. I simply commented an if-statement and it is now “working.” I’m sure I’ve lost some robustness, but hell, it does what I want with no apparent side-effects. If you would like to know more about how I “broke” lpc21isp check my Github readme on the issue.

Kossel Mini Calibration

This is a continuation of my Robot Metallurgy 101 – AVR Lesson Journal

This is the second part of my Kossel Mini build log

When I made my mind up to build a 3D Printer I knew I was in for a ride. I knew I was going to spend an insane amount of time calibrating the damned thing. Well, my overestimation was nowhere near the truth. I’ve spent literally days calibrating this damned machine. Mind you, a lot of it was because I refused to “RTFM.” But the other part was because there doesn’t to seem to be a manual on calibrating the Kossel Mini. Therefore, I’m going to attempt to present what I’ve learned for delta printer posterity.

Note, this guide will focus on the “holes” other sources of documentation have, more specifically, holes in:

Let’s start with getting the firmware and software.

I mentioned in the physical build of my printer, I bought most of my stuff as a kit from builda3dprinter.eu. I’ve been pleased with the kit. Most of my frustration with the physical build was me not understanding how the pieces work together (for instance, the auto-probe). Anyway, Ardon Camp from B3DP has provided some starting firmware for his kits, which is listed on his “Initial set-up” page

  1. Marlin Arduino firmware for B3DP Kossel Mini kit
  2. Pronterface
  3. KISSlicer

As of now, I switched Proterface out with Repetier and KISSlicer with Slic3r.

  1. Repetier
  2. Slic3r

We should have firmware (Marlin) and a host (Repetier or Pronterface). What now?

Well, hind-sight is 20/20, so here are my suggestions.

1. Get familiar with G-Code

Most 3D printer firmware operates on a standard set of instructions called G-Code, which are sent to the printer via serial connection. There is a code for everything, turning the heater on, going to an end-stop, writting settings to the EEPROM. My recommendation, before you start moving any part of your printer, read through all the G-Codes. This will give you an idea how your software talks to the printer.

2. Check, re-check End-Stops connection before testing motors

Now that we’ve read up on G-Code, we know the code to check and see if the End-stops are triggered is M119. Check this a few times before you attempt moving anything electronically. If everything is connected correctly it should look like this,

No Buttons Pressed:

  1. Y_MAX: Open
  2. X_MAX: Open
  3. Z_Min: Triggered
  4. Z_Max: Open

All Buttons Pressed:

  1. Y_MAX: Triggered
  2. X_MAX: Triggered
  3. Z_Min: Open
  4. Z_Max: Triggered

It is important to have these trigger correctly, otherwise, your hot-end will go crashing into something. For example, if one the end-stops isn’t triggering then the connected carriage will continue trying to pull past the end-stop, which will result in the your belt-link coming apart.

Expect for your links to come apart a few times as you make adjustments.

Being forthright and humble, I made so many mistakes calibrating my Kossel that my links began to stretch out and were unable to hold the belt properly.

I was able to bend them back into place by clamping them with pliers while heating the bottom side with a lighter.

3. Fans

The Kossel Mini has a small 40x40mm fan that blows directly on the hot-end, all the time.

This is required because the hot-end holder is actually a printed part, meaning it is plastic, therefore, if the hot-end exterior isn’t constantly cooled, it will melt the holder and come crashing down on your print plate in a neat heap of defeat.

The fan should operate on 12V. You have several options.You can tie the fan into the PSU itself, which would cause the fan to be on everytime the printer is on. Or, you can tie the fan into the Ramps board.

I chose the Ramps. Don’t ask me, probably because I intuitively find a way to do something through hardest means possible.

Anyway, here is how I have all my fans, (1) on the hotend, (2) cooling my extruder stepper, (3) an 80mm cooling the print bed.

I then connected all these fans to D9.

I’d like to take a sidetrail a moment. Power terminals D8, D9, D10 are simply high-power N-Channel MOSFETs controlled by PWM from the Arduino Mega’s D8, D9, and D10 pins. If you’d like the exact specs, here’s the datasheet.

Ok. Now we have a few things to set in firmware to get the fans to act correctly. First, make sure you are using the option under Configuration.h

  • #define MOTHERBOARD 33

This sets the three power channels on the Ramps to function as the following:

  1. D10 = Extruder Heater (hot-end)
  2. D9 = Fans
  3. D8 = Heated Bed

Now that is setup, then everything should work hunky-dorky, right? Well, kinda.

I was having two problems. First, the fan didn’t come on automatically, I had to send the G-Code command “M106 SXXX” to get it to turn on, the XXX being a number between 0-255 to set the PWM of the fan (also, the command M107 used to be to turn it off, but now we just send “M106 S0”).

Second problem, my fan didn’t like to kick on with PWM. Sometimes it did, sometimes it didn’t. Often, I’d start a print only to find my hot-end melting the effector plastic. Sigh.

Now, some people who know Marlin better than me will probably point out the option under the Configuration_adv.h,

  • #define FAN_KICKSTART_TIME 100

The number is the number of milliseconds to drive the fan at full speed before switching to a temperature based PWM. Now, I tried tweaking this number a bit, but I found my fan would still lock up during times it would slow. Eh. That is one reason I write this, if others have solutions, please add them in comments. :)

What I ended up doing was finding the option to have my D9 channel to run at full power all the time.

Under the Configuration_adv.h file I found the options to define the extruder fan’s behavior. First, I setup the D9 channel as our fan channel by setting

  • #define EXTRUDER_0_AUTO_FAN_PIN 9

Then, I changed the kick-on temperature to -1, meaning the hot-end would need to be below freezing for the fan to turn off. So, a hackish always on switch.

4. Physical Print Calibration

“But I bought a Kossel ‘cause it’s got an Auto-_Probe!” Ya, I’m humble enough to state those words did run through my mind. Yet, I’ve learned, the auto-probe is like many things in electronics, nice to have, but does not replace the ability or the understanding behind it. I’ll go as far as stating, the auto-probe _is meant to keep your physical calibration on track, even after heavy use, rather than compensate for poor calibration_._

Alright, to calibration.

I couldn’t find any Kossel Mini specific guides on how to calibrate the machine, but I found a lot of scattered information in the

After going through many posts I pieced together my own method for calibration. But the standard blog on the issue is:

Before we begin calibration, let’s define and agree on what we will be calibrating.

(Image shamelessly, and maybe illegally? Copied from Blokmer’s Kossel Build guide)

Ok, here we go:

Step #1 – Calibrate ZMax

This takes care. Go to Configuration.h and set,

  • #define MANUAL_Z_HOME_POS 270

This is going to tell your printer you have a build volume larger than you do, but we do this so the firmware wont stop us as we try to move the hot-end as close to the bed as possible. Now, perform the paper-test.

For the sake of brevity, I’m going to define the paper-test once, then simply refer to it as the paper-test.

The idea is eventually you want about a paper’s width space between the hot-end and the printer bed, when the printer is told to go to **Z0. **The paper-test consists of putting a piece of paper on the print bed, then lower your hot-end manually, 10mm steps at first, but as you get closer, 0.1mm steps. At the point the hot-end is putting just enough pressure to create a little drag on the paper, you stop going down. This is the paper-test.

Ok. You lower the hot-end carefully until it passes the paper-test. Then, send the G-Code for getting the Z position.

  • M114

The printer will respond with the current value for the X, Y, Z, and E (extruder). You only want the Z-value you right now. Take the Z-value and subtract it from the 270, this will be your new MANUAL_Z_HOME_POS. That is,

  • MANUAL_Z_HOME_POS = 270 - Z_Value obtained by paper-test.

If my explanation sucks, refer to Blokmer H07

Step #2 – Calibrate Physical Center

Now, there is a way to set the center of your build plate in your Marlin firmware, but it is better only to tweak it there after you have the physical part set pretty damn close to center. This is what I did.

I used Eagle Cad to make a 170mm diameter circle, with exact center marked (provided below). Then, I printed it to scale on a piece of paper. I cut this paper out and centered it on my build plate, then taped it down.

Next, I lowered my hotend until it was near to center.

Using the controls, I attempted to center the hot-end above the circle the best I could. It helps to change your angle several times before each move. Once it is center we are going to take a measurement, but something important to know before we do. The stepper motors will timeout from their held position, going into an idle position. Be careful not to let them timeout on the next two steps, since you’ll lose a little time by needing to start over. To keep them engaged, simply micro step one direction, then right back.

Ok, measure from the top of one of the carriages to the bottom of the plastic on an end-stop, basically, where the end-stop button would be if it was pressed. Also, the end-stop doesn’t matter since our goal is to get them all the same.

Alright, at this part you need a saw that will give you a square cut. I used a speed-square and a circular saw. Also, smaller board, like a piece of trim board. Cut a piece of wood the same length as you measured.

Take the piece of wood to the printer. Lower the hot-end to Z0. Then, re-center using the target-template. Now, take the cut wood and put it between each end-stop and the top of its respective carriage, being careful not to let the motors go idle. If the end-stop is too high, lower it until it is flush against the wood. If the wood will not fit, raise the end-stop until it does, making sure it is flush. In this manner you are assuring each arm is equidistant from the print bed, while maintaining the hot-end centeredness.

After this is complete, you must repeat Step 1. This sets centeredness and Z-Offset.

Now, test this by sending the G-Code:

  • G X0 Y0 Z15

If all worked, the hot-end will magically find its way to the center of the print bed, while staying 15mm above the surface. If that goes well, microstep the hot-end back down to the surface to assure we maintained the correct Z-Offset (aka, print volume).

Step #3 – Flat Print Surface

Even after all this, we still aren’t done. There is another variable to calibrate on the Kossel, the flatness of the plate.

We have already calibrated the Kossel’s print volume height. This means if we send the command G X0 Y0 Z0 then the hotend-should come to rest at the center of the print bed, about .1mm above the surface. But, delta printers have an additional variable of flatness. Consider the two following images:

In this image the blue line is the print surface according to the Marlin firmware.

Do you see how this could create a problem? The center Z offset may be correct, but as the hot-end moves towards the edges, it gradually rises until the hot-end is resting 2-10mm away from the print surface.

Let’s look at the other, possibly more damaging, scenario.

If the print bed, according to firmware, is convex, then the hot-end might be correct when at center, but as you get to the edges, the machine tries burying your hot-end into the glass plate.

This is why Johann’s auto-probe was such a nifty addition to the Kossel build. But let’s not get ahead of ourselves, physical calibration first.

Well, that’s sort of a lie. To correct for flatness we are going to adjust the firmware. The flatness of a Kossel is reliant on the variable DELTA_RADIUS and it is the sum of several variables. So, to adjust DELTA_RADIUS we focus in on either increasing or decreasing one of the variables. I picked DELTA_SMOOTH_ROD_OFFSET at random.

Ok, the adjustment is pretty straight forward, but requres tinkering to get it right. But before we make an adjustment we need to know what direction to go. We can determine this by visually comparing difference between the distance between the hotend and the print surface when the hotend is at the center, and the distance between the hotend and the print surface when near one of the towers. Let’s go back to pictures.

This image is to give you an idea what points we want to compare for flatness. For instance, if Kossel passes the paper-test at point A, then it should at points B, C, and D.

But if the Kossel passes the paper-test at point A, and is too high at B, C, and D then you have a concave print surface.

Likewise, if the Kossel passes the paper-test at point A, and is too low at B, C, and D then you have a convex print surface.

  • B Height > A Height = Concave
  • B Height < A Height = Convex

One more bit, you maybe asking how to find the spots B, C, and D. Well, I used the following calculations

  • Xb = (Build Radius) * COS * (Angle of B tower)
  • Yb = (Build Radius) * SIN * (Angle of B Tower)

Also, know your towers should be at angles: 90, 210, 330

If you have the same build radius as me, 170, then your points should be.

  1. Y70, X0
  2. Y-35, X-60
  3. Y-35, X60.62

But remember, we are really looking that all four points pass the paper-test.

Let’s move on to how to make the adjustment. I will not go into the math explaining how adjusting DELTA_RADIUS affects flatness, mainly because I don’t understand it. But secondly, because we don’t need to understand it to adjust it. Just know the following,

  1. Increasing DELTA_SMOOTH_ROD_OFFSET lowers the hotend.
  2. Decreasing DELTA_SMOOTH_ROD_OFFSET raises the hotend.

Really, it is changing the firmware’s idea of flatness.

Now, make the adjust from the visual information you collected by comparing point A to point B, C, and D. Then, comparing them again, adjust again. Compare, adjust. Ad infinitium.

Please, don’t think your done. Making these last adjustments means you really need to go back and start from Step #1 and work through them a second time, since any adjustment throws the previous adjustments off alittle. So, it is true, adjustment is an infinite process of error reduction and perfection will never be achieved. Be happy with pretty damn close :)

6. Auto-Probe

Physical calibration is done, now let’s examine what makes us Kossel users, our respective auto-probes.

The auto-probe is meant to keep Kossel Mini printing flat. That is, it is meant to adjust for slight inconsistencies in the print bed or minor mechanical disproportions.

Alright, as the rest of this article, I don’t plan to re-hash stuff that has already been covered. Such as setting up the auto-probe. Just refer back to Blokmer, or B3DP. But here are a few things I feel they missed:

#1 – G28 CANCELS G29 DATA

This I feel is the most important omission from the calibration guides. G28 is the G-Code to home the tower end-stops, just know whenever you do this, it will cancel the readings you took from the auto-probe. And beware, Slic3r adds a G28 command before every print.

To remove this from Slic3r,

  1. Go to “Printer Settings”
  2. Under “Start G-Code” delete “G28; home all axes” line.
  3. Under “End G-Code” delete “G28 X0; home X-axis” and replace it with, “G1 X0 Y0 Z220 F5000”

Step number three is just a suggestion, but you do want your hotend to back away from the print when done, so you don’t catch anything on fire. You just don’t want to reset your auto-probe data.

And yes, I spent 20 hours or so adjusting my auto-level and scratching my head everytime my print didn’t adjust respectively. (If it wasn’t for Hoff70, I’d still be scratching my head).

I’m not smart, just obessive.

#2 Finding the X, Y, Z Offset of the Z-probe from Extruder.

The Z-probe doesn’t sit directly over the tip of the hot-end, so we have to adjust for this offset. To find this number, I did the following.

  1. Place and center the paper-template.
  2. Send the command: G X0 Y0 Z10
  3. Put the auto-probe in its active position (as if to take readings).
  4. Using Repetier or Pronterface, move the effector from the hotend being centered, until the tip of the Z-probe is centered.
  5. Then lower the effector until the Z-probe passes the paper-test.
  6. After, send G-Code: M114. The output is our auto-probe offset.

Take your readings and put them into the three defines in Marlin

  • #define X_PROBE_OFFSET_FROM_EXTRUDER
  • #define Y_PROBE_OFFSET_FROM_EXTRUDER
  • #define Z_PROBE_OFFSET_FROM_EXTRUDER

As for directionality, I found if my X or Y numbers were negative, I was telling the firmware my auto-probe was offset into the -X or -Y regions. Of course, the Z-probe offset is always negative, or you’d be in trouble.

#3 – Visualizing Auto-Probe readings

This is another important piece I feel guides leave out. What does the auto-probe data mean?

Don’t ask me, that’d take math. I’d much rather look at pictures. So, how do we turn the data into a picture? Well, there are several methods, but really, any program that will turn a set of points into a plane.

One of the guys from the Delta Google Group wrote this Python script for MATLAB.

Buuut, I don’t have MATLAB and I’m not currently tied to a university, so I had to think of another way. Well, my profession is mental health and I use Excel for a lot of statistical analysis (hey, SPSS costs money, too). Anyway, here are the steps I took to visualize the data in Excel.

1. Run Auto-Probe. Once auto-probe is done, it’ll send back a set of points. Copy them.

2. Paste the points into Excel. It’ll complain about formatting, press OK.

3. If you click on the formating options and select “Text Import Wizard.” You can then select a “Space Delimited” pasting option. Basically, this will cause Excel to translate th

4. Once you have your data in Excel correctly, let’s make a graph. Select your data set then go to the graph type “Surface.”

5. There’s the graph.

6. There are several things you can do with this data, but only if you have a point of orientation. That is, what area on the graph represent the area on the print surface. To find the auto-probe data orientation, I built a lump on my print surface near one of the towers, like this:

Be careful, if your Z-probe doesn’t retract far enough, it’ll knock your lump into the belt.

You can adjust how far your Z-probe retracts between probing in the Marlin firmware. Under Configuration.h adjust,

  • #define Z_RAISE_BETWEEN_PROBING

If all goes well, when you run your auto-probe data you’ll get a nice lump on the graphed surface. This will allow you to make intelligent decisions regarding adjustment.

  1. One last bit I’d like to point out. None of this is going to help if your auto-probe is not mechanically reliable. But how do you tell if it is? Well, until someone corrects me, I did the following.

  2. Ran the auto-probe about twenty times.
  3. After each, I took the mean of the data.
  4. Then, after I had about twenty means, I ran the standard deviation on those means.
  5. This number is a fair indicator of how reliable your auto-probe is mechanically. That is, are the readings it is giving you reliable. The smaller the number, the more reliable.

Of course, I’m not great with math and I’m pure hack, so someone with more understanding of the logic let me know if that is incorrect.

And with that I’ll close by saying: I’m a hack. I wrote this article not to point out everything I know, but rather, what I’ve learned. If anyone finds incorrect information, please comment; I’ll make changes quickly. The last thing I’d like to do is steer someone wrong.

Kossel Mini Build

Originally posted on www.letsmakerobots.com

I thought I should give my Kossel a “Robot” page, since Silas asked what the Kossel was, and I told him, “A 3D Printer,” to which my precocious son replied, “No, it’s a robot.”

A lot of the information here is a copy from my build blog, but I’ve re-thought it’s presentation slightly, since there preexist two build guides for the Kossel.

  1. Blokmer’s Kossel Mini Build Guide
  2. builda3dprinter’s Kossel Build Guide

Both are put together by organizations selling Kossel kits. Blokmer’s guide is much more detailed and slow paced. Of course, I purchased my kit from builda3dprinter (here on referred to as B3DP) and tried to use their guide as much is possible, that said, the B3DP guide has a lot missing information. I wont bitch too much, since I’ve enjoyed their kit, but it does bring me to how I’ll approach the information here.

I’m going to write this guide as a supplement to existing build guides. For example, the Kossel has an auto-level probe that is somewhat problematic to assemble. Both guides did a poor job of explaining several key parts of its assembly. Therefore, I’ll focus primarily on missing information.

Purchasing the Kossel materials:

I sourced a few parts from China and purchased the major parts from www.builda3dprinter.eu.

eBay and Fasttech

3 x NEMA 17 Motors: $42.00

1 x Planetary Stepper: $60.00

12V, 30A Power Supply: $31.39

Ramps and A4988 Drivers: $31.00

Arduino Mega: $15.81

J-head MK-V, 0.4MM Nozzle, 1.75MM: $36.99

For the rest, I bought several “kits” from www.builda3dprinter.eu.

B3DP Kits

Kossel Kit (plastic parts): $55

Nuts and Bolts kit for Kossel: $30

OpenBeam Kit for Kossel: $70

Rails to Wheels conversion kit: $50

The rest: $115

Shipping: ~$50.00

Total for Essentials: $587.19

After purchasing all the essentials I bought a few things I felt would make the build neat.

Scrunchy Wire Wrap: $10.02

Little zip-ties x 100: $3.85

Big zip-ties x 50: $4.85

Colorful heat-shrink x 140: $11.78

Total for Neatness: $30.50

Total Essetials and Neatness: $617.69

Regarding www.builda3dprinter.eu

I need to say I’ve mixed feelings towards B3DP. Being a mental-health worker, when someone has mixed feelings we create a T-Chart of pros and cons. Here’s mine on B3DP kit.

Cons:

  1. Shorted ~20 M3 Nuts.
  2. Six weeks for processing and delivery
  3. No clear documentation on the effector provided
  4. Missing Allen key, springs, and safety pin (for auto-probe). This is not included in their list of what’s not included.
  5. Pin connectors are cheap and not reliable
  6. Huge holes in documentation (Blokmer rocks this one).

Pros:

  1. Plastic part quality is excellent.
  2. Responded to delays by giving me a free borisillicate plate.
  3. Communicate well (they responded quickly to all my questions).
  4. Their kits **do **work well together.

In fairness, I’m not done with the build, but writing this out, I’d say I would buy B3DP kits again.

The bit it’s difficult to put a price on is part precision and synergize. Since the parts are meant to work together, calibration is much simplier (still not easy). For instance, instead of having to measure out the length of rods, carriage offset, etc. B3DP provided a Marlin (firmware for delta) with these measurements already input. In sum, half of the calibration is already done by B3DP.

Purchase “Doh”s!

1. Effector mismatch:

B3DP provided me with a MK V end effector and I bought MK IV J-Head extruder that was advertised as an MK V. Point to you eBay. So far, this hasn’t caused any problems, I simply pulled the brass end off my extruder and pushed it into place. Not sure of the open area between the effector plastic and the PTFE tubing will cause me problems down the road, like filament bunching.

2. Must have a Geared Stepper motor for extruder:

I purchased my stepper motors in a lot of five. I thought, “I’ll use 3 for the X, Y, Z axes and one 1 for the extruder.” Well, this is where I should have done more research. The original design for the Kossel requires a NEMA 17 Geared Stepper Motor. So, I broke down and ordered a geared stepper-motor for the extruder. I was a little under budget and felt it was a better choice rather than struggling trying to get the current motor I had to work with what B3DP sent.

But to be clear the extruder from B3DP is built for a stepper-motor with a 8mm shaft. Actually, the parts are from the original design which called for a geared-stepper motor and a spur-gear with 22 teeth, with a 8mm diameter shaft. The “common” NEMA17 has a 5mm diameter shaft. I’ve seen a few extruder designs that use a regular stepper and a 5mm diamter spur-gear, but that is not what comes with the B3DP kit.

Assembly

Like I stated, I’m no going into a lot of detail about the assembly, since there exist two guides. But I’ll include time-lapse of most of the build (what was easy to film) and notes on stuff not in the exist build-guides.

1. Jig Setup & Traxxas Ends

The Blokemer guide states I should tap and drill the Traxxas ends and the carbon rods. I bought a metric tap and die set from Harbor Freight, but when I examined the pieces I received from B3DP I noticed the headless bolts were too small to catch the inside of the carbon rods. Also, I wasn’t sure how to use my tap and die; this devolved into the realization I had the wrong thread sizes. Makes sense, I was using a US tool and parts from everywhere else but the US.

Well, I lucked out. According to the B3DP manual you don’t need to tap anything. Just screw the headless bolts into the Traxxas ends, then use slow-setting Epoxy to glue the ends into the carbon rods. Screwing the headless bolts in the Traxxas ends went great. Um, gluing was another matter.

Not much to say about setting up the jigs for the carbon rods and Traxxas ends. Just follow the instructions on pages 3-6 of the Blomker guide. I used a square and a speed-square, the square to align the rails flush, then the speed-square to align the machine screws at one end. I’ve read that the arms can deviate from the 180mm outlined by the guide, but they should all be the same length. My goal was to identify rods longer than the others and file them down a little.

Post-build note: I found to “spare” objects in my plastic parts that came from B3DP–I realized they are jig bits. Doh.

2. Gluing Traxxas Ends (and a big F’up)

I bought some cheap slow setting epoxy from Harbor Freight. I mixed it with a chop-stick (a favorite tool) and began to apply it to the Traxxas ends. Then, I f’ed up.

I dropped one of the Traxxas ends into the epoxy. I tried cleaning it in alcohol and acetone. But there was still some residue that prevented the ball-joint from moving as freely as I wanted. Sigh. I went ahead and ordered more Traxxas heads, so, if anyone needs an extra because they dropped it in epoxy, just let me know. I’ll have eleven.

One more note, be sure to wipe excess epoxy from the Traxxas end and rod joint. I was worried about an improper seal between the two and left the globulated extra. It leaked into the crevices of the 1515 Beam. Of course, I thought, “I’ll just make sure to turn the yucky part inside when I put the pieces together so it’s not noticeable.” Well, the nuts bolting it to the plastic pieces are also on the inside. In short, it caused a lot of problems. I’d wipe them off before setting them in place on the jigs if I could do it over.

3. Bottom Triforce Assembly

I didn’t like the name “Bottom Assembly” so, I renamed this step: Bottom Triforce assembly. For the most part, smooth sailing. Just make sure you barely screw the nuts on. If they are too tight you can’t get the plastic lips to close around them. Also, they have a top and bottom.

Adding the shafts to the bottom Triforce was a little tricky. First, it should be noted, there is an “up” and a “down” to the Triforce pieces:

The little circular tabs on the bottom Triforce assembly are for printing purposes and may be removed with a sharp knife and steady hand. In the absence of a steady hand, a lot of blood and an emergency-room visit will suffice.

Also, don’t screw any bolts down too tight until you press all pieces together. I had reviewed the section in the Blokmer guide, pages 28-32, but I realized the need for give from all sides was greater than expected. You’ll notice towards the end of my video I was struggling not to look like a complete idiot trying to push all the pieces together.

Of course, I didn’t realize this until I already had bolted the bottom Triforce down and started trying to shove the first shaft in place. I quickly pulled the bottom apart, flipped the odd piece I had so all my plastic pieces had the two-prong guide at the “top.”

Now, I’ve seen half-dozen different ways to press the 1515 into printed plastic. I tried my heat gun, but was really wary I’d deform a piece and I would have to wait 6 weeks to get another from B3DP. I ended up using the following tools:

To press the rods in, I started the rod into the first nut. Then, when it started to get tight, I put a little bike oil (the green bottle) around the edges, flipped over the assembly, and put it in my lap. I pressed the end of the rod I had started against the tile floor and beat on the receiving end (assembly) with a balled fist.

Well, this worked great. A little too great. The rod slipped past being flush. This is where the screwdriver and hammer came in. I simply left the assembly in my lap, but raised the rod off the floor. Then with the tip of the screwdriver against the end of the 1515 rod, I tapped against the screwdriver with the hammer. This allowed me to align the 1515 rod flush with the bottom plastic of the Triforce assembly.

4. Carriage Assembly

Carriages assembly went pretty well. I had to tap the holes for most of the bolts on the carriages, since there was printer-webs still in the holes. But after the holes were clear it was pretty straight forward. I followed the guide from B3DP.

A few notes: If you haven’t sorted your bolts, might be a good idea to do it now. If all your bolts are lumped together digital-calipers are a godsend. You just measure from directly under the head, to the end of the shaft.

There are three nuts that will need to be pressed into the plastic of the carriage assembly. I used a heat gut to soften the plastic of the intended holes, then pressed the nut slightly in place by placing the tip of a flat-head screwdriver over the nut and tapping it with a hammer. This method worked well. One exception, there are three nuts, but two of the bolts are 25mm and one is 16mm. The 16mm bolt is not long enough to catch the threads of the nut unless you tap it deep into its hole. I hope this picture makes it clear:

5. Motors and Endstops

Bottom endstops and motors went smooth.

Only bits of advice on the motors are: Make sure you tap the holes in the plastic to prevent any plastic shards from misaligning your bolt as you try to screw it into the motor hole.

Also, don’t tighten any bolts down until all your bolts are started correctly. I found they often were misthreading, which I attributed to such a harsh angle.

Oh, one more bit, purchase a long 2mm Balled Allen Key for this process. As you may notice at the beginning of my video I tried with a short, balless Allen key to no avail.

6. Carriage Arms and Effector Assembly

A couple notes,

The carriage assembly is pretty straight forward, just make sure you follow the instructions and don’t get in a hurry. But the effector I had a little difficulty putting together. Mainly, the round part of the J-head wouldn’t fit into the hole. I’ve tried to avoid using a heatgun as much as possible, but here I used it to warm the plastic enough and pressed the J-head into place.

7. Top Triforce, PSU, Ramps 1.4, and Attaching Effector

Here I become a little peeved at B3DP. First, there are three parts they do not include in “The Rest” kit, but also don’t mention in the “What’s not included” section. They are the spring, safety pin, and Allen-key for the auto-level.

The auto-level bit is a little tricky to put together. You will need to source three parts: The safety pin, Allen-key, and springs. I ordered an Allen-key off eBay. The safety pin I “borrowed” from my wife’s things. And the springs I pulled from some old pins. After much fiddling I was able to piece something together.

Now, I need to state, in my original blog I was a little unfair to B3DP. I bitched about them sending a button-switch for the auto-probe. The problem was they provided a button switch instead of an button and arm switch.

Arm and Button

Button Switch

This should not have bothered me too much, since the three end-stops worked. But when it came to the auto-level, the Allen-key crook was supposed to catch the metal arm of the above shown switches, guiding it down to the button. Well, I found when the Allen-key came to sit on the button, instead of pressing it down it would slide either to the left or right. And it didn’t seem to matter how much tweaking I did, I couldn’t get it to sit right. In the end, I bought the “appropriate” switch at Radio Shack for $3.

Here is what my auto-level looked like after tweaking. When I tested it unmounted it worked.

But, when I mounted the auto-probe and started using it, I found the arm would catch underneath the safety-pin bolt. Hmm.

Therefore, I feel I owe B3DP half an apology.

I ended up using the switch I was sent, effectively, and I apologize for bitching about the wrong switch. But, to get the switch I was sent to work properly, I had to layer heatshrink, over, and over. This builds the arm up to the point it can’t help but catch the button. And the heatshrink has some natural resistance to it. This necessary modification probably needs to make it into the B3DP guide.

Regarding the power-supply.

I tried buying a cheap computer-power cord from eBay. But after I sliced the end off and found less copper than in telephone wire. I sacrificed one of my old computer power cords. The powercord wasn’t as long as I’d like, but it had enough copper to pull the possible 30A the PSU could source.

To wire the PSU,

  • Green <—> Ground
  • White <—> N(eutral)
  • Black <—> L(ive)

Also, if you are using that fasttech.com PSU, I noticed it came to me with the 240v as default. If you’re in the states make sure you flip the switch on the side.

After wiring my PSU to the Ramps I turned it on and looked for blue-smoke. Nothing. Waahoo!

But I had another problem. The Mega underneath wasn’t getting power. Well, I scratched my head for a bit and then actually read the Ramps manual. Apparently the diode that had been taped to the underbelly of my Ramps is what enabled it to be powered from a 12V PSU. I soldered it in place.

After soldering the diode everything appeared to be working. I continued to wire everything else up like proper.

12V to Arduino Mega Diode placement

Here, I switched gears and put the top Triforce together.

One note I’ll make. Again, the top Triforce has a “bottom” and a “top.” It has to do with the tensioner bolt, it must angle from the top-outside to the bottom-inside. Like this,

After, I got a hankering to actually put the top on and the belts in place. It took a little courage, since B3DP sent my timing belts in one role. I had to make cuts and was worried they had given me just enough belt and if I made a cut that was a little off would have to wait on another belt. But it was in vain, I had enough.

To cut the belts I just strung them up as shown and left about four rubber-teeth past the end of the linker groove. The little extra room can be adjusted when the top Triforce is put on. There are three tension bolts for this purpose.

This is what the belt should look like in place, except the should go below the carriage or it will knock into the end-stops before carriage.

(Sidenote, from here on I’m using a lot of pictures, since the Kossel is a little difficult to video given its physical size)

I then tightened the top Triforce and quickly hooked up the Ramps. I uploaded the Marlin firmware and was able to get the motors to respond to one direction. The problem came when I tried to hook the cooling fan to the Ramps. Two of the three FETs were putting out 0Vs. Waaa-waaah.

Apparently, the power control FETs on the Ramps were bad?

I found out later (Brassfly and Bdk6 actually figured it out) that it was not bad FETs. It was a trace-short somewhere on the first 12V power rail. Oh well. I ordered another Ramps board for $14 and took a break from the build for 18 days while it found its way to me.

8. It’s Alive!

The evening I received the new Ramps board I wired everything up. Sure enough, I powered the thing on and all the blue-fairies stayined in their Silicon homes. I then ran the Blink sketch to check the power FETs on pins 8, 9, 10. They all powered on like expected, spitting out 12Vs.

Next, I uploaded Blokmer’s Marlin sketch. Big mistake.

Blokmer and B3DP both provide a Marlin sketch with “typical” measurements already plugged into the Configuration.cpp. I didn’t know this. I had essentially put diesel into a gasoline engine.

  1. Blokmer’s Marlin Firmware Specific to Blokmer’s Kossel, Pronterface, and Slicer (.zip; for Windows)
  2. B3DP’s Setup Page. It links to Marlin Firmware specific to B3DP Kossel, Pronterface, and KISSlice.

Of course, I pulled a lot of my hair out using Blokmer’s firmware with a B3DP build. In the end, I downloaded B3DP’s Marlin and Blokmer’s zip file. That is, I used the appropriate Marlin with Pronterface and Slicer.

Before I move on though, I’d like to go over wiring.

Here is the B3DP wiring chart:

Of course, my stepper-motors had different color wires, but I guessed and got it right. Really, I figure they would either move up or down, then I could switch them if needed. A word of caution, make sure you wire each stepper to its corresponding end-stop. If not, when you home the end-stops for the first time one or two of the motors will stop, but the other two or one will continue because their end stop hasn’t been triggered, resulting in your belt(s) coming loose. E.g., motor X will hit end-stop Z, but not turn off because the X end-stop hasn’t been switched. And the X end-stop wont switch off because motor Z has stopped because its end-stop has be triggered.

Clear as mud? Just make sure each end-stop is wired to the appropriate motor.

Regarding the thermistor, it is non-polarized. Just plug it in.

Ok. I’m going to consider the “Mechanical” section of this build complete. Now, I’ll begin working on the hard stuff: Calibration.