Browsed by
Category: Technical

The failure of Coin and why gadget ventures often fail

The failure of Coin and why gadget ventures often fail

Ben Einstein does an excellent analysis of the failure of many smart gadget companies.

His analysis breaks down like this:

First generation products are always plagued with bugs, fail whales, and even the occasional mass-recall – most companies can bounce back from these setbacks. But other companies do not. It boils down to risk.

Technical Risk and Product Risk

When it comes to hardware startups, there are two types of risk. They are manageable on their own, but together often spell failure. These risks are: technical risk and product risk.

Technical risk is the chance you can’t deliver a product due to an engineering or manufacturing constraint. Examples from Coin: getting an e-Ink screen, Bluetooth antenna, battery, and microprocessor all working in a 0.76mm thick PVC card.

Product risk, however, is the risk that many overlook. Most products have low product risk. They routinely fail in small ways, but those failures are viewed as mere annoyances. A pop top that breaks off once every 1000 cans of Coke, the Roomba that occasionally misses a spot, an Alexa that mistranslates your command and you try again. Not big deals. But an automated door lock that fails might leave one stranded outside at 2am in a bad part of town or opens the door to robbers, a website that exposes your address and bank accounts for emptying, or your sole payment method that fails you at a fancy dinner are another matter.

You likely have high product risk if any of these are true:

  1. If a small number (one or two) of failures over the lifetime of your product create a negative interaction (like door locks or sole payment methods).
  2. If users would pay significantly more for a product that is guaranteed to work 100% of the time (like wireless routers).
  3. If users rely on your product for critical business operations (like point-of-sale systems).
  4. If failure could wreak massive havoc on personal security or safety (like home security systems or cars).

The Goal:

Your goal then is to only have high risk in one of the two risk classifications. Very few companies that have both kinds of risk survive. Tesla and SpaceX are notable exceptions, which should give you an idea of the efforts you will need to go to in order to overcome these risks. The other method is to reduce your feature set to minimize technical complexity or lower user expectations in case of product failure.

VNC-ing into Ubuntu 14.04

VNC-ing into Ubuntu 14.04

Some VNC functionality was broken in Ubuntu 14.04 due to Vino, but fortunately, it’s fixable:

 

Using a combination of clues from http://discourse.ubuntu.com/t/remote-desktop-sharing-in-ubuntu-14-04/1640 (which is all about VNC access) and https://bugs.launchpad.net/ubuntu/+source/vino/+bug/1281250 (which discusses the bug introduced into Vino) I have managed to resolve the matter.

Essentially you have to disable encryption on remote desktop access in Gnome due to a bug that has come to surface in Vino. However, some threads tell you to uncheck it in the wrong place. Follow these guidelines and you should be able to resolve it quickly.

Specifically it’s

dconf > org > gnome > desktop > remote-access > require-encryption – uncheck

and NOT

dconf > desktop > gnome > remote-access > enabled – uncheck

Here is how you do it:

  1. First make sure Desktop Sharing is set up properly.
  2. Download dconf-tools by typing in Terminal sudo apt-get install dconf-tools
  3. Run dconf-Editor
  4. Expand org
  5. Expand gnome
  6. Expand Desktop
  7. Select Remote Access
  8. Uncheck Require Encryption (don’t click on Set to Default as it rechecks it)
  9. Exit dconf-Editor

It should now work. Tested through a reboot and all good.

Hope it helps.

(I have got a screen shot of dconf but don’t have enough points on here to post it – I am sure everyone can work it out for themselves though! 🙂 )

If data was used like this in the 90’s – imagine how it’s used today…

If data was used like this in the 90’s – imagine how it’s used today…

The Lion King video game has a notoriously difficult level. Known simply as ‘the monkey level’, some consider it one of the hardest levels in gaming. But did you know there’s a story behind its legendary difficulty?

In the 90’s, Blockbusters started to rent out video games in addition to films. However, unlike film studios, who got paid every time their films were rented, video game developers didn’t get a cut of the profits. So, a lot of the video game industry hated the rental industry and wanted to make sure their games could not be beaten in the rental period.

Disney, in particular, had studies and metrics. They determined that most players would not buy a game if they could beat some large percentage of it in a rental period. Disney told the developer of the Lion King, Westwood studios, to put some giant difficulty spike early in the game to intentionally halt player’s progress. The game was nearly complete and the final deadline was fast approaching. The monkey puzzle was the only thing they could quickly implement on such short notice.

Here’s a developer’s commentary on how it went down:

Amazing Ford car crib

Amazing Ford car crib

Putting the baby in a car and going for a drive has long been known to put even the most restless child to sleep. So, Ford made a crib that you connect to a smartphone app and can then record/playback journeys you take. It reproduces sounds, passing lights, and the very motion of the journey.  So now, your child can take your commute home each day with you.

Bonus points for the Castilian Spanish.

Tanya’s plan to avoid the fallacies of crunching and bad work habits

Tanya’s plan to avoid the fallacies of crunching and bad work habits

Tanya Short gave one of the best talks I’ve heard in a long time about the fallacies of crunching and bad work habits many people have. The video is now up for free at the GDCVault. Her talk starts at 6:00 :
http://gdcvault.com/play/1024174/Indie

Summary of her points:

When trying to hit deadlines, she starts out by observing that most of the time we think ‘getting X done’ is our highest priority. It’s not. It’s actually #3:

Your real priorities:

  1. Don’t burn out (i.e. don’t die)
  2. Always keep in mind you’re going to do another – and you should be excited to do the next one even better.
  3. Get it done

That sounds great, but it also sounds a bit idealistic. She says it is not easy, but lays out these points.

Step-by-step roadmap to not dying:

  1. Believe it is possible to hold those priorities in that order
    Many great studios work and ship games without crunch. It can be done, she does it. You just have to be disciplined.
  2. Stop working ‘all the time’. Set work hours.
    It is a fallacy to think working all the time is better. Especially in creative fields. Creative work and creative problem solving require a relaxed mind to do it. Time away from work helps us be more productive. So set work hours and stick to them.
  3. Prioritize your tasks and re-prioritize as often as needed.
    In order to hit your deadlines, you need to know what you’re working on RIGHT NOW is important, not just urgent. If you focus just on the ‘urgent’ emails/tasks/etc, then you’ll never get into the steady workflow that is what makes your work great.
  4. Estimate your tasks. Re-estimate when needed.
    When you finish your task, ask if it took the time you thought it would take. You should do that with every task. It helps you get better at estimating.
  5. Cut the scope before you bleed out.
    If you’re 3 weeks out and realize you won’t make it, don’t immediately think about working more/harder/longer. 3 or more 60 hour weeks is scientifically less productive than 3 or more weeks of 40 hour weeks. You are doing worse work. Even if you think you are a special exception. Why can she say that? A study was done on 100 people that claimed they needed less than 7 hours of sleep. Only 5 out of the 100 could actually do it.
  6. Don’t give up – iterate steps 1-5 again and again
    These steps (production) is a skill. Skills can be developed. Skill development requires practice. So congratulate yourself when you do it pretty well, forgive and be kind to yourself when you don’t treat yourself as you deserve.
    We are primates. Primates need to be taken care of in a way computers and games don’t, so don’t act like that towards yourself. It’s not about how many hours you spend because everyone is different.

Other quotables:
A few long nights won’t kill you, but a few long months might. Especially if combined with other health and life factors.

Burnout is the feeling of being dulled as layer after layer of exhaustion accumulates. Burnout is the void left behind where your career could have been.

Then she has a real Benedictine moment: The moment right now will never come again. Every one of us will die. No matter what we create, all we have is right now. Don’t use up that joy, love, and creative energy you have by burning yourself out.

Keep death always before your eyes.
—St. Benedict: The Rules: Chapter 4.47


She doesn’t cite the studies, but I found some:

http://lifehacker.com/working-over-40-hours-a-week-makes-you-less-productive-1725646811

Set up VNC on Ubuntu 14.04

Set up VNC on Ubuntu 14.04

Setting up VNC on Ubuntu used to be pretty painless. But recent changes in Ubuntu and X have left it kind of a mess. It took me way longer to set up VNC than it should have, and finding the documentation wasn’t super-easy either. There were lots of broken guides. So, here’s what you need to do:

  • Follow these setup instructions first:
    https://www.howtoforge.com/how-to-install-vnc-server-on-ubuntu-14.04
  • When completed, however, a known issue means the screen will come up blue-grey and have few desktop controls if you try to connect to it. This is because (near as I can tell) the X manager currently used for Ubuntu doesn’t work over VNC anymore. You need to set VNC up to use an older desktop manager that
  • To fix that problem, you need to fix things according to this guide:
    http://onkea.com/ubuntu-vnc-grey-screen/
  • On your client, start the vncserver and connect to it by matching the final digit of the port number to the :X number you used to create it.
    • Example:
      host: vncserver :4 –geometry 800×600 (to create the server)
      client should use the ip: 10.23.47.150:5904
  • If you get an error starting the vncserver, increment the :2 to :3 or :4 and so forth until you find one not in use by some other user on the server.

OpenGL ES 2.0/3.0 Offscreen rendering with glRenderbuffer

OpenGL ES 2.0/3.0 Offscreen rendering with glRenderbuffer

Rendering to offscreen surfaces is a key component to any graphics pipeline. Post-processing effects, deferred rendering, and newer global illumination strategies all use it. Unfortunately, implementing offscreen rendering on OpenGL ES is not well documented. OpenGL ES is often used on embedded/mobile devices, and until recently, these devices haven’t typically had the graphics bandwidth to keep up with new rendering techniques. Compound this with the fact that many mobile games have simple gameplay/small screens that do not need such complex lighting models, many people now use off the shelf engines for their games, and that there is still a good amount of mobile hardware out there that doesn’t even support render to offscreen surfaces, and it is no surprise that few people use the technique and it’s not well discussed.

In implementing offscreen rendering for OpenGL ES, I turned to the very good OpenGL ES Programming book as it has a whole chapter on framebuffer objects. When I tried the samples in the book, however, I was having a lot of difficulty getting it working on my linux-based mobile device. A lot of the implementation examples use a technique of creating framebuffer objects using textures, but you can also use framebuffer objects via something called render buffers. One reason this is good to know is because many hardware vendors support very few render-to-texture formats. You can often find yourself struggling with your implementation not working because the output formats aren’t supported.

Thankfully, I found this article and thought I’d copy the information here since it’s the only place I’ve seen working code that demonstrated the technique. It also includes the very important step of reading the output format and uses glReadPixels() so you can validate that you were writing correctly to the offscreen renderbuffer surface.

In my case, on an Intel graphics part, I found that the format (which is also the most recommended one) that worked  was GL_RGB/GL_UNSIGNED_SHORT_5_6_5. Steps 1-8 is standard OpenGL ES setup code that is included so you can verify your setup. Step 9 is where the glFrameBuffer and glRenderBuffer objects are created.

 

    #define CONTEXT_ES20

    #ifdef CONTEXT_ES20
        EGLint ai32ContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
    #endif

    // Step 1 - Get the default display.
    EGLDisplay eglDisplay = eglGetDisplay((EGLNativeDisplayType)0);

    // Step 2 - Initialize EGL.
    eglInitialize(eglDisplay, 0, 0);

    #ifdef CONTEXT_ES20
    // Step 3 - Make OpenGL ES the current API.
    eglBindAPI(EGL_OPENGL_ES_API);

    // Step 4 - Specify the required configuration attributes.
    EGLint pi32ConfigAttribs[5];
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
    pi32ConfigAttribs[2] = EGL_RENDERABLE_TYPE;
    pi32ConfigAttribs[3] = EGL_OPENGL_ES2_BIT;
    pi32ConfigAttribs[4] = EGL_NONE;
    #else
    EGLint pi32ConfigAttribs[3];
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE;
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT;
    pi32ConfigAttribs[2] = EGL_NONE;
    #endif

    // Step 5 - Find a config that matches all requirements.
    int iConfigs;
    EGLConfig eglConfig;
    eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1,
                                                    &iConfigs);

    if (iConfigs != 1) {
        printf("Error: eglChooseConfig(): config not found.n");
        exit(-1);
    }

    // Step 6 - Create a surface to draw to.
    EGLSurface eglSurface;
    eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig,
                                  (EGLNativeWindowType)NULL, NULL);

    // Step 7 - Create a context.
    EGLContext eglContext;
    #ifdef CONTEXT_ES20
        eglContext = eglCreateContext(eglDisplay, eglConfig, NULL,
                                               ai32ContextAttribs);
    #else
        eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, NULL);
    #endif

    // Step 8 - Bind the context to the current thread
    eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
    // end of standard gl context setup

    // Step 9 - create framebuffer object
    GLuint fboId = 0;
    GLuint renderBufferWidth = 1280;
    GLuint renderBufferHeight = 720;

    // create a framebuffer object
    glGenFramebuffers(1, &fboId);
    glBindFramebuffer(GL_FRAMEBUFFER, fboId);

    // create a texture object
    // note that this is commented out/not used in this case but is
    // included for completeness/as example
    /*  GLuint textureId;
     glGenTextures(1, &textureId);
     glBindTexture(GL_TEXTURE_2D, textureId);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);                             
     //GL_LINEAR_MIPMAP_LINEAR
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_HINT, GL_TRUE); // automatic mipmap
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, renderBufferWidth, renderBufferHeight, 0,
                  GL_RGB, GL_UNSIGNED_BYTE, 0);
     glBindTexture(GL_TEXTURE_2D, 0);
     // attach the texture to FBO color attachment point
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                         GL_TEXTURE_2D, textureId, 0);
     */
     qDebug() << glGetError();
     GLuint renderBuffer;
     glGenRenderbuffers(1, &renderBuffer);
     glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
     qDebug() << glGetError();
     glRenderbufferStorage(GL_RENDERBUFFER,
                           GL_RGB565,
                           renderBufferWidth,
                           renderBufferHeight);
     qDebug() << glGetError();
     glFramebufferRenderbuffer(GL_FRAMEBUFFER,
                               GL_COLOR_ATTACHMENT0,
                               GL_RENDERBUFFER,
                               renderBuffer);

      qDebug() << glGetError();
      GLuint depthRenderbuffer;
      glGenRenderbuffers(1, &depthRenderbuffer);
      glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
      glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,     renderBufferWidth, renderBufferHeight);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);

      // check FBO status
      GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
      if(status != GL_FRAMEBUFFER_COMPLETE) {
          printf("Problem with OpenGL framebuffer after specifying color render buffer: n%xn", status);
      } else {
          printf("FBO creation succeddedn");
  }

  // check the output format
  // This is critical to knowing what surface format just got created
  // ES only supports 5-6-5 and other limited formats and the driver
  // might have picked another format
  GLint format = 0, type = 0;
  glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format);
  glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);

  // clear the offscreen buffer
  glClearColor(1.0,0.0,1.0,1.0);
  glClear(GL_COLOR_BUFFER_BIT);

  // commit the clear to the offscreen surface
  eglSwapBuffers(eglDisplay, eglSurface);

  // You should put your own calculation code here based on format/type
  // you discovered above
  int size = 2 * renderBufferHeight * renderBufferWidth;
  unsigned char *data = new unsigned char[size];
  printf("size %d", size);

  // in my case, I got back a buffer that was RGB565
  glReadPixels(0,0,renderBufferWidth,renderBufferHeight,GL_RGB, GL_RGB565, data);

  // Check output buffer to make sure you cleared it properly.
  // In 5-6-5 format, clearing to clearcolor=(1, 0, 1, 1)
  // you get 1111100000011111b = 0xF81F in hex
  if( (data[0] != 0x1F) || (data[1] != 0xF8))
      printf("Error rendering to offscreen buffern");

  QImage image(data2, renderBufferWidth,  renderBufferHeight,renderBufferWidth*2, QImage::Format_RGB16);
  image.save("result.png");