Creating 3D models is hard

3D printing is easy. You can buy a 3D printer off the shelf for a few hundred of your Earth pounds, download patterns from thingiverse and be printing solid stuff straight away. Creating your own 3D models is harder, and it seems to me that this is now the bottleneck (at least, if you don’t want to spend a lot of money). There are several options. You can scan a real item, if you have a 3D scanner, and then use really awkward tools to manipulate the mesh. You can persuade powerful and confusing tools for animation and modelling like Blender to create models. You can use infuriatingly limited free versions of commercial tools like Sketchup. Or if you have really deep pockets, you can buy a proper CAD system.

I don’t like any of the above. I’m a programmer, and have a mechanical engineering background. I want to create precise, preferably parametric, models of components which I can then print out and fit together with other components to make machines. Up till now, I’ve been using OpenSCAD, and it’s been pretty good. OpenSCAD allows you to define shapes precisely using numbers, and combine them exactly (wrong word, I know) to create useful things. I love it. But it’s always had one major flaw (and a few little ones, but that’s another story). Building a model in OpenSCAD is like writing a program: it supports functions and loops, but it doesn’t support variables. At least not variable variables. You can assign a value to a variable and use it later, but that value cannot change. This is a bit of a pain, and it limits what you can do. Now there is an alternative, and that makes me happy.

The new kid on the block

OpenJSCAD is an entirely browser-based (yes, you read that right) editor and renderer for 3D models. It uses a language quite similar to OpenSCAD (indeed, it can import OpenSCAD files), but more powerful and a bit like C. And it supports proper variables. Hurrah! Here’s a screenshot of a little something I knocked up in it:

screenshot_4

Try doing that in OpenSCAD. I did, and the spiral ramp was not easy. Here’s an assembly of a few of them, printed out and stacked together. A ball bearing runs around them very nicely:

ball chute

Try OpenJSCAD. If you don’t like it, I’ll give you your money back.

Here’s my .jscad file which created the ball chute. You can simply cut the text and paste it into OpenJSCAD if you want to try it.

// title: Spiral ball bearing chute
// author: Peter Robinson
// license: None.  Free for all.
// description: A stackable spiral chute for ball bearings.

var radius = 50;
var slotwidth=6;
var wallthickness=1;


function main(params) {

    var a=2;
    return union(
        section(),
        section().translate([0,0,20]).rotateZ(90),
        section().translate([0,0,40]).rotateZ(180),
        section().translate([0,0,60]).rotateZ(270)
        );

}

function section(){
    return union(
        ramp(1,11,radius-4,radius-4,4),
        ramp(6,11,radius-3,radius-3,1),
        ramp(1,11,radius+3,radius+3,6),
        hub()
        );

}

function hub(){
    return  difference(
        union(
            CSG.cylinder({
            start:[0,0,0],
            end:[0,0,10],
            radius: 10,
            resolution:36
            }),
            CSG.cylinder({
            start:[0,0,10],
            end:[0,0,15],
            radiusStart: 8,
            radiusEnd: 7,
            resolution:36
            }),
            spoke().rotateZ(-27.5),
            spoke().rotateZ(-27.5-45).scale([1,1,0.5])
        ),
        union(
            CSG.cylinder({
            start:[0,0,-1],
            end:[0,0,17],
            radius: 6,
            resolution:36
            }),
            CSG.cylinder({
            start:[0,0,-0.5],
            end:[0,0,5.5],
            radiusStart: 7.9,
            radiusEnd: 6.9,
            resolution:36
            })
        )

    );
}

function spoke(){
    return CSG.cube()
        .scale([radius/2-slotwidth/2,1,5])
        .translate([-radius/2,0,5]);
}

function spiral(){
    var hex = CSG.Polygon.createFromPoints([
            [0,slotwidth/2, 0],
            [0,-slotwidth/2, 0],
            [0,-slotwidth/2, radius],
            [0,slotwidth/2, radius]
    ]).setColor(
        [0, 0.8, 0]
    );
    var angle = 5;
    return hex.solidFromSlices({
        numslices: 365 / angle,
        callback: function(t, slice) {
            var coef = 1 - t * 0.8;
            return this.
            translate([0 , radius, t*10]).
            rotateZ(angle * slice);
        }
    });

}

function ramp(slotwidth,climb,innerradius_start,innerradius_end,basethickness){
    var hex = CSG.Polygon.createFromPoints([
            [0,0, 0],
            [0,slotwidth, 0],
            [0,slotwidth, 1],
            [0,0, 1]
    ]).setColor(
        [0, 0.8, 0]
    );

    var base = CSG.Polygon.createFromPoints([
            [0,0, 0],
            [0,slotwidth, 0],
            [0,slotwidth, 1],
            [0,0, 1]
    ]).setColor(
        [0, 0.8, 0]
    );
    var angle = 5;
    var radiuschange = innerradius_end-innerradius_start

    var bottom = base.solidFromSlices({
        numslices: 95 / angle,
        callback: function(t, slice) {
            return this.
            translate([0 , innerradius_start +t*radiuschange, 0]).
            scale([1,1,basethickness]).
            rotateZ(angle * slice);
        }
    });

    var spiral = 
        hex.solidFromSlices({
        numslices: 95 / angle,
        callback: function(t, slice) {
            return this.
            translate([0 , innerradius_start +t*radiuschange, 0]).
            scale([1,1,climb*(0.1+t*0.9)]).
            rotateZ(angle * slice);
        }
    });


    return union(
        bottom,
        spiral.translate([0,0,basethickness])
    );

}

More tiny WiFi success

As I have posted before, I have been playing with the super-cheap WI07C WiFi module based on the ESP8266 chip. I’ve now had sufficient success with it that I can publish a post on a working project. This simple setup uses an Arduino nano to read temperatures from to 18BS20 sensors, formats the data as JSON and then sends it over WiFi to a server on my home network. It’s cheap and simple. Here’s the fritzing diagram:

WI07C_bb

You may notice the Adafruit level shifter board in there too. That’s because the digital IO from the arduino is 5V, but the WiFi module needs 3.3V. The Adafruit module is a dead easy way of joining the two. The temperature sensors use a three-wire protocol which allows you to connect many in parallel and address each one individually. there’s a software library which takes care of this.

Here’s the Arduino sketch. It uses Miles Burton’s temperature control library to read from the sensors, so you’ll need to download that. NB: this code is not a shining exaple of style or completeness. It’s a quick hack to get something working. It does no error checking or reconnection if there are problems. You may find yourself pressing the reset button a lot.

You might also note that the hardware serial port is required for the WiFi module, which needs 115200 baud. This means that you can’t upload a new sketch to the arduino while it’s connected to the WiFi module. I just whip out the wires to the TXD and RXD pins on the arduino while I’m uploading, and all is well.

The sketch tries to join the WiFi network, and then tries to establish a simple TCP connection to a server IP address and port of your choice. Once the connection is established, it checks the temperature sensors every 10 seconds or so and sends the temperatures to the server in JSON format, thus: {"temp":[22.63,22.81]}. That’s all it does. You’ll need a TCP server listening on your chosen IP address and port, of course. It seems to work quite reliably for me.

#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define SSID        "MyHomeSSID"
#define PASS        "MyPassword"
#define TARGET_IP   "192.168.1.xx"
#define TARGET_PORT 5000
#define TEMPERATURE_PIN 9

SoftwareSerial dbgSerial(10,11); // RX,TX
OneWire wire(TEMPERATURE_PIN);
DallasTemperature sensors(&wire);

void setup()
{
   // WiFi module needs fast serial, so must use the hardware port which is also used for
   // uploading sketches
   Serial.begin(115200);
   Serial.setTimeout(5000);

   // For debugging, we therefore need a software serial port.  This can be much slower.
   dbgSerial.begin(9600);
   dbgSerial.println("Starting");

  delay(1000);

  // Connect to the wirelsess network
  dbgSerial.println("Joining network...");
  Serial.print("AT+CWJAP="");
  Serial.print(SSID);  
  Serial.print("","");
  Serial.print(PASS);
  Serial.println(""");
  receive();

  // Just check that the WiFi module is joined to the network
  dbgSerial.println("Check connection...");
  Serial.println("AT+CWJAP?");
  receive();

  dbgSerial.println("Initialising sensors...");
  sensors.begin();


  dbgSerial.println("Connecting to server...");
  Serial.print("AT+CIPSTART="TCP","");
  Serial.print(TARGET_IP);
  Serial.print("",");
  Serial.print(TARGET_PORT);
  receive();
  delay(5000);

  dbgSerial.println("Ready to rumble!");
}

int incomingByte=0;
bool echoLocal = true;

// Get the data from the WiFi module and send it to the debug serial port
void receive(){
  delay(500);
  while (Serial.available() >0) {
    incomingByte = Serial.read();
    dbgSerial.write(incomingByte);
  }
  dbgSerial.println();
}

char temp1[10];
char temp2[10];

void loop()
{

  // call sensors.requestTemperatures() to issue a global temperature
  // request to all devices on the bus
  dbgSerial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  dbgSerial.println("DONE");

  dtostrf(sensors.getTempCByIndex(0),1,2,temp1);
  dtostrf(sensors.getTempCByIndex(1),1,2,temp2);  

  String json="{"temp":[" + String(temp1) + "," + String(temp2) + "]}";
  dbgSerial.print("Sending ");
  dbgSerial.println(json);

  // Send the data to the WiFi module
  Serial.print("AT+CIPSEND=");
  Serial.println(json.length());
  delay(500);
  Serial.print(json);
  receive();


  delay(10000);
}

This is a work in progress. I’ll be updating it soon. But for now, I’m very pleased with the simplicity of the WiFi modules, and even more pleased with their low cost (I am a Yorkshireman, after all).

Wifi success, for a change!

I’m actually having success in connecting the super-cheap WI07C wifi module to my home network, so that an arduino can send data anywhere.

WI07C module featuring esp8266 chipset

WI07C module featuring esp8266 chipset

I can now reliably establish a TCP connection and send data back and forth. It works rather well, with some limitations. It helps that I came across some slightly better documentation, sourced from this esp8266.com forum post which lists a few more AT commands and some more illuminating explanations.

AT+CIPMODE

AT+CIPMODE=1 or 0 (1 is default) sets the data receiving mode of the socket. If it’s 0, received data is simply sent to the serial port. If it’s 1, data gets “+IPD,c,n,” prepended to it, where c is the channel number and n is the number of bytes received. c is omitted if you are in single-channel mode. If you have multiple connections going in, this mode is logical. If you have only one, it may be simpler to use the transparent mode (AT+CIPMODE=0). But see AT+CIPSEND below, because this is affected by AT+CIPMODE!

AT+CIPSEND

The usual documentation about this is a bit pants. Here’s how it works. When you issue an AT+CIPSEND command, you normally tell it the channel you want to send it over (the chip can keep four IP connections going at once) and the number of bytes you want to send (call it n). The module then responds with a “>” character. It will then take the next n bytes you give it and send them over the TCP link. Then it responds with “SEND OK” and returns to normal, waiting for your next command. There are three variants of the AT+CIPSEND command, however:

AT+CIPSEND=channel,length is used if you have multiple connections open (AT+CIPMUX=1)
AT+CIPSEND=length is used for a single channel (if you have previously issued AT+CIPMUX=0 to tell it that you will only use one connection at a time)
AT+CIPSEND can be used without any parameters if you are using a single channel and transparent data mode (AT+CIPMODE=0). Note that there is no channel or length specified in this variant. After you issue the command, it will simply send every byte you throw at it directly to the receiving socket. This includes AT+ commands. Note that I have as yet found no way of exiting this mode other than resetting the module.

Also note that if you are in transparent data mode (AT+CIPMODE=0) and you try to use the variant of AT+CIPSEND which uses a length value, it won’t just fail or ignore it, it will actually reboot the module.

Lesser known AT commands not in other documentation

AT+GMR

AT+GMR retrieves the firmware ID of the module. There are at least two versions in the wild.

AT+CIPSTO

AT+CIPSTO=60 Sets the socket timeout period to 60 seconds
AT+CIPSTO? gets the current timeout value
You might want to change this value because if the server closes the socket, and your timeout value is too high, there appears to be nothing you can do from the client end other than do a hardware reset. I’m thinking it’s probably going to be necessary to tie the CH_PD line of the module to an output from the arduino, as I’m bound to want to reset from software at some point.

It’s good to make some progress. I’m going to look at the using the module as a server next.

WiFi for less than a fiver

Last week, the excellent hackaday ran a story about a new WiFi module (the Wi07c) based on the ESP8266 chip. It is eminently suitable for attaching to an arduino or similar, but it only costs $5. As I’ve been whining for some time about the high cost of WiFi shields for arduino, this piqued my interest. I bought a couple from the electrodragon store and have now had a bit of time to play with them. It seems that for once I’m a little ahead of the game – other people seem to be waiting a long time to receive theirs. The documentation is a little sparse, but enough to be going on with. There are three main sources, mostly community-supported: electrodragon, a hackaday.io project and nurdspace. The device is serial-driven, using a limited set of AT commands which will feel familiar to anyone who has worked with GPRS modems.

I’ve connected one of the modules to an arduino, and done some testing. I’ve also driven it directly from a serial terminal on my PC. These are my findings so far:

  1. The module runs at 3.3V, not 5V. The 3.3V available from an arduino can’t provide enough current to power it (though it may seem to). The WiFi module won’t even respond to commands without a separate power supply. Powering it from one of these works fine.
  2. In the version of the module I have, you must connect the CH_PD pin to +3.3V. Don’t be put off by the suggestion in the diagrams on Nurdspace.com that the four pins in the middle of the connector are not connected to anything. CH_PD is the pin next to the TXD pin.
  3. The AT commands mostly work. AT+CWLAP briskly returns a list of visible access points. AT+CWJAP connects to my home router (or claims to). Beyond that, things get flaky. Actually setting up a TCP connection to a running server does not seem to work. Nor does sending UDP. both allow me to get to the point of sending data, but then simply respond ‘busy’ to any further command or data until the device is rebooted (by unplugging it from the power supply). I’m not convinced that the device is ever genuinely connected to my router: the router doesn’t show it in the list of active clients.

I’ll keep experimenting with it, but I’m frustrated. It seems so close to being functional, but isn’t quite there yet. It feels like the firmware is missing some useful commands and diagnostic information. Or maybe it’s the documentation. Perhaps if my Chinese was better…