More than just bricks… http://thinkbricks.net LEGO MINDSTORMS EV3 robots, LEGO projects, building instructions and programming cool robots. Wed, 14 Sep 2016 16:48:12 +0000 en-GB hourly 1 New project: a Giant Calculator! http://thinkbricks.net/progress-on-my-giant-calculator/ http://thinkbricks.net/progress-on-my-giant-calculator/#respond Sun, 11 Sep 2016 13:02:00 +0000 http://thinkbricks.net/?p=1307

My latest project is to build a giant working calculator out of Lego. This is by far the most ambitious project I’ve taken on, and I’ll be blogging about my progress over the coming months. Why do I call it a ‘giant’ calculator? Because it’s going to be BIG! I estimate it’s at least one metre per side, if not larger.

Why a calculator?

I saw a video online of a 7 segment display made out of Lego. It had a wonderfully simple mechanism, and was hypnotic to watch in action. As I watched I realised that I could put the 7-segment display to good use, and build a calculator!

What’s a 7 segment display you ask? It’s a display device commonly used in simple calculators, where 7 individual segments are used to make digits from 0 to 9, and even some simple capital letters.

 

Mechanical 7 segment displays

Most of the existing designs for Lego 7 segment displays use a sequential counting mechanism, typically using a barrel rotating to toggle each segment changing. This type of design is fun to watch, but can only count sequentially from 0 to 9 and back to 0 again. See this picture for an example of a barrel mechanism; very ingenious in its own way.

 

Source aeh brickshelf

This design is ingenious, but doesn’t lend itself to a calculator display which needs to update quickly each time a key is pressed. I set my mind to devising a better way to update the digits, one that was fast enough to be used as practical display.

I also wanted to have a full calculator keyboard, so people could press the keys, see (and hear) the display update in real time, and do useful calculations.

My Goals

  • 8 full-size digits, with decimal points
  • Working keyboard with basic operators, memory, and some advanced maths functions
  • Keys are large enough that they can be pressed by hand
  • Calculator actually works and can do arithmetic
  • Display is fast to update once a key is pressed.
  • Uses only official Lego parts; no Arduino or third-party sensors.
  • Big! I want it to be visually impressive and fun to use!

Over the next few months I’ll be blogging my progress on this project. I’ve been working on prototypes for the display digits and keyboard, trying out lots of ideas and throwing them away almost as fast. It’s a very iterative process of discovery!

]]>
http://thinkbricks.net/progress-on-my-giant-calculator/feed/ 0
Fun build – Lego Compact clock http://thinkbricks.net/fun-build-lego-compact-clock/ http://thinkbricks.net/fun-build-lego-compact-clock/#respond Wed, 24 Aug 2016 19:58:08 +0000 http://thinkbricks.net/?p=1262 This was a fun build I did over a weekend. I wanted a little challenge to tackle, something new I hadn’t tried before. I really like Nathanael Kuipers supercars, which he posts on his new website http://www.nkubate.com. But I also noticed he had a design for a compact LEGO clock. What appealed to me was the simplicity of the design, and how densely he packed the gears into the body. So challenge accepted!

Nathanael usually posts building instructions for his models, but in this case he had shared some pictures of the final model. I was left to puzzle out exactly how it all came together, and also which parts were not shown in the pictures. It was a 3D puzzle, with a lot of hidden moves!

The clock hour and minute hand run together from a single drive axle, so I started by building that. Then I worked on the lower gearbox, which was a lot more challenging. The difficulty was in figuring out exactly how the geartrain came together. It took some trial and error but once built it was very tight. I like how the white clutch gear was used to allow the black bevel gear to rotate and change the hand position, and hence set the time.

2016-08-22 09.29.17 2016-08-22 09.28.51 2016-08-22 09.28.32 2016-08-22 09.28.12

 

]]>
http://thinkbricks.net/fun-build-lego-compact-clock/feed/ 0
Using a serial LCD with the Raspberry Pi http://thinkbricks.net/using-a-serial-lcd-with-raspberry-pi-2/ http://thinkbricks.net/using-a-serial-lcd-with-raspberry-pi-2/#respond Sun, 13 Mar 2016 13:42:35 +0000 http://thinkbricks.net/?p=1245

In this little project I use a serial LCD connected to the Rasp Pi serial output to print the current time and IP address for the Pi. It’s a fun little project as it puts together a few pieces; using the Adafruit T-Cobbler Plus, making an inverter circuit and controlling the serial LCD.

 

There are already some good tutorials online on how to use a standard (non-serial) LCD with the Pi. For example, Adafruit has a great tutorial on driving an LCD using the Pi. However I had a BPI-216N serial LCD from Scott Edwards Electronics which uses a simple single-line serial link running at 2400 or 9600 baud to send data from the Pi to the display. Amazingly I bought this unit in 1998 and have had it sitting in a drawer ever since – and it still works perfectly!

 

Using the serial port on the Rasp Pi

The first thing you need to do is disable the serial port console on the Rasp Pi. Why? By default the Pi boots up and creates a serial console on the Rx and Tx lines running at 115200 baud. This is great if you need to log into a Pi that has no screen attached, but we want to use this serial port to send data to the LCD.

The serial console is configured in /boot/cmdline.txt and you simply need to remove the text that says console=ttyAMA0,115200 and save the cmdline.txt file.

The second step is to display the init process in Linux from attempting to connect a tty to the serial console. In older releases of Raspbian the procedure is to edit /etc/inittab, but in the later releases Raspbian has moved to a new way of starting boot services. The command to remove the serial console tty starting is:

sudo systemctl stop serial-betty@ttyAMA0.service

Reboot your Pi and then the serial console is disabled.

Inverting the signal to the LCD

The interesting (or challenging) part about the serial LCD is that it expects inverted TTL as it expects to be connected to an RS232 port, which inverts the polarity of the signal by default. What does this mean? Well if you want to send the letter ‘a’ (decimal character code 97, binary 0110 0001) then you need to flip each bit and send the value 1001 1110 or 158. This is painful to do in software, so the simple solution is to put an inverter between the TxD pin on the GPIO header and the serial input on the LCD.

I did a quick search online and found this schematic for a single-transistor simple inverter made using one transistor and two resistors. I used 1K resistors and a 2N2222 transistor, mainly because I had them sitting on my desk! Note that this circuit does not do level shifting! The Pi GPIO pins operate at 3.3V but most serial devices use 5V. This isn’t a problem for this project as we’re sending data to the LCD so a level shift isn’t needed.

Wiring it all together looks as follows (yes my breadboard work won’t win any prizes!)

 

 

Python Code to print to the LCD

Finally we get to the code itself. It’s actually pretty simple as the serial port does the bulk of the work and the transistor inverter takes care of the logic signals. I set my LCD to work at 9600 baud. I cheated a little to get the IP address by running the hostname command and parsing the output; not pretty but it works.

To learn more about the commands accepted by the LCD read the programmers guide.

# Show the current IP address and date and time
# on the serial LCD attached to the serial port
#
# Mark Crosbie mark@mastincrosbie.com 12/3/16
# http://thinkbricks.net
import serial
 from time import sleep, strftime
 from datetime import datetime
 import commands
ser = serial.Serial(port='/dev/ttyAMA0', baudrate=9600)
 cls = bytearray([254, 1])
 ip_addr = commands.getoutput("hostname -I").split(" ")[0]
def clearscreen():
 ser.write(cls) # clear and reset screen
 sleep(0.01)
def moveTo(line, col):
 pos = line*192 + col
 b = bytearray([254, pos])
 ser.write(b)
 sleep(0.01)
if ser.isOpen():
 while 1:
 clearscreen()
 ser.write(ip_addr)
 moveTo(1,0)
 ser.write(datetime.now().strftime('%d %b %H:%M:%S'))
 sleep(1.0)
]]>
http://thinkbricks.net/using-a-serial-lcd-with-raspberry-pi-2/feed/ 0
Triangular tracked wheel http://thinkbricks.net/triangular-tracked-wheel/ http://thinkbricks.net/triangular-tracked-wheel/#respond Sat, 30 Jan 2016 21:43:00 +0000 http://thinkbricks.net/?p=1240 A small design study for making a triangular wide-tracked wheel driven by a Lego Mindstorms EV3 large servo motor. Two of these on wither side of a robot chassis gives a very cool effect! I also created building instructions as a test of using LDCad.

You can download the building instructions here in PDF format.

The LDraw file is available here.

Here are a few images.

]]>
http://thinkbricks.net/triangular-tracked-wheel/feed/ 0
Face tracking on EV3 using leJOS 0.9.1 http://thinkbricks.net/face-tracking-on-ev3-using-lejos-0-9-1/ http://thinkbricks.net/face-tracking-on-ev3-using-lejos-0-9-1/#respond Sun, 29 Nov 2015 10:54:51 +0000 https://thinkbricks.net/?p=1228 The leJOS 0.9.1 release added the OpenCV vision processing library. What better way to test it than build a face-detecting robot! First step is to figure out how to use the OpenCV libraries on EV3 to detect a face in an image.

It turns out this is really hard to do in practice. Lighting is one of the problems; any strong reflections or highlights in the image and OpenCV will fail to detect the face. The other issue is the processing speed of the EV3; face detection is a CPU-heavy task! The EV3 has a fast processor, but it struggles to do reliable face detection in almost real-time to control a robot. 

Let’s start with a simple example, using the webcam capture code from https://lejosnews.wordpress.com/2015/09/26/opencv-web-streaming/ as a basis to build on. I’m going to assume that you:

How does face-detection work?

First of all, this code will detect a face-shaped object in an image stream, but it won’t distinguish who it is. That is termed face recognition and is a lot harder to do (trust me – I built these systems for a living!) How does OpenCV detect a face? It takes an image and then appliers a series of ‘classifiers’ to it to extract face-like features from the image. If the image contains enough evidence of face-like features then the OpenCV code returns the coordinates of the bounding rectangle around what it thinks is the face.

OpenCV in leJOS 0.9.1 has two types of face classifiers available: Haar classifiers and LBP feature classifiers. The Haar classifiers are slow but more accurate. In my tests the Haar classifier could reliably detect multiple faces against a bright background, but it was slow! So slow that I was seeing detection times of the order of 1 second per frame (i.e. a frame-rate of 1 fps). This is too slow to reliably control a robot’s motion. The LBP feature classifiers are faster, but less accurate. With an LBP feature classifier I can get on the order of 8-10 fps on the EV3 on a 160×120 image from a webcam. The problem is face detection is very unreliable at this frame-rate, with faces rarely detected even when perfectly lit.

For a great overview of OpenCV and tutorials (in C++) of many functions take a look here: http://opencvexamples.blogspot.com/2013/10/face-detection-using-haar-cascade.html

Reading from the webcam

I’m using a cheap webcam plugged into a USB hub plugged into the host port on the EV3. leJOS has native support for webcams since the 0.9.0 release, and with OpenCV that support is now present in the OpenCV library too. 

We start by initialising and opening the camera device. You’ll have to set the image width and height here too. I set it to a very small size of 160×120 pixels. The camera can return larger images, but the bigger the image the slower it is to process on the EV3!

VideoCapture vid = new VideoCapture(0);

vid.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, 160);

vid.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, 120);

vid.open(0);

System.out.println(“Camera open”);   

 

Once the camera has been opened reading from it is as simple as:

Mat frame = new Mat();

vid.read(frame);     

if (!frame.empty()) {

}

A Mat is an OpenCV data structure akin to a matrix – it is like a ‘magic bucket’ that you can store almost any data in for OpenCV to process. 

Detecting faces

The OpenCV library in Java provides the detectMultiScale() function to detect face images. It takes a number of parameters, and you’ll have to play around with the parameters to get it to work reliably. Face detection is more of an art than a science!

The first thing we want to do is convert the colour image from the webcam into a grayscale image, and then equalise the histogram of the image. While OpenCV can process colour images it seems you’ll get more reliable results from a grayscale image.

Mat mRgba=new Mat();  

Mat mGrey=new Mat();  

frame.copyTo(mRgba);  

frame.copyTo(mGrey);  

Imgproc.cvtColor( mRgba, mGrey, Imgproc.COLOR_BGR2GRAY);  

Imgproc.equalizeHist( mGrey, mGrey );                  

 

Then we can actually do the face detection. Drum roll please….

private final String features = “/lbpcascade_frontalface.xml”;

MatOfRect faces = new MatOfRect();

faceDetector = new CascadeClassifier(getClass().getResource(features).getPath());

faceDetector.detectMultiScale(

        mGrey

        faces,

        scaleFactor,

        minNeighbours,

        flags,

        minSize,

        maxSize);

 

I’m using the lbpcascade face detector for this example because it runs quickly on the EV3 CPU and gives reasonable (but not great) accuracy. You will need to copy the file lbpcascade_frontalface.xml from the opencv/data/lbpcascades directory into the same directory on the EV3 as the jar file you are running (usually into /home/lejos/programs).

That’s a lot of parameters. So what do they all mean?

  • mGrey: This is the input frame that we want to detect a face in. In this case it’s the grayscale image.
  • faces: A matrix of rectangles; OpenCV returns each face as a rectangle as the bounding box around where it thinks the face is located. 
  • scaleFactor: how much scaling is applied to the image. The lower the number the more accurate the detection, but as a consequence the slower it goes. I started with a value of 2.0 for scale factor, and then reduced it down to 1.8 to get better accuracy but a reasonable detection time.
  • minNeighbours: controls accuracy. I just leave this at 2
  • flags: leave this at 0
  • minSize: the minimum size for a face. I set this to 20×20 to allow small faces to be detected. 
  • maxSize: the maximum size for a face. I set it to 160×120 in case the face takes up the whole image.

Interpreting the output and Drawing faces

Once you’ve run detectMultiScale() you’ll need to find the faces, if any were detected. But how? Recall the output is stored in the faces matrix, so we convert that into an array and see if it has any elements in it. If it does we iterate over each element, which is a rectangle, and then draw a rectangle on the image frame so we can display it in a web browser.

int numFaces = faces.toArray().length;
if(numFaces > 0) {
  System.out.println(String.format("+++ Detected %s faces", numFaces));
 
  // each rectangle in faces is a face
  Rect[] facesArray = faces.toArray();
  for (int i = 0; i < facesArray.length; i++) {
     Rect rect = facesArray[i];
Point center= new Point(rect.x + rect.width*0.5, rect.y + rect.height*0.5 );   
Core.rectangle(frame, rect.tl(), rect.br(), new Scalar(0, 255, 0, 255), 2);
  }

What does the output look like?

I opened up a web browser and connected to my EV3 on the wifi. The images look look like this (yes I usually look like that as I’m trying to watch the screen while holding my head still 🙂

Bounding rectangle on face capture

As I mentioned face detection is very sensitive to lighting and background in an image. In this case I had to move the camera so the skylight above my head wasn’t in the image. At night I found that the lights in the room were creating highlights which confused the camera. An ideal lighting setup is to have a dull matt background with soft lights coming from behind the camera at your face.

Putting it all together

As always you can get the source code on my github account: https://github.com/markcrosbie/lejos_projects/tree/master/OpenCVTesting/src. I’ve added a quick way to play around with the minNeighbours, scaleFactor and classifier type parameters on the command line. You can run the code as 

jrun -cp HTTPFaceDetect.jar HTTPFaceDetect <minNeighbours> <scale> <l/h>
for example
jrun -cp HTTPFaceDetect.jar HTTPFaceDetect 1 2 l

Will give very fast but not accurate detection, whereas:

jrun -cp HTTPFaceDetect.jar HTTPFaceDetect 1 1.1 h

Will be very accurate using a Haar classifier, but will be very (very) slow on the EV3. Experiment and see what works for you.

]]>
http://thinkbricks.net/face-tracking-on-ev3-using-lejos-0-9-1/feed/ 0
Time-lapse video using EV3 and webcam http://thinkbricks.net/time-lapse-video-using-ev3-and-webcam/ http://thinkbricks.net/time-lapse-video-using-ev3-and-webcam/#respond Tue, 07 Jul 2015 13:33:01 +0000 http://thinkbricks.net/?p=1215

I wanted to try making a home surveillance project using my webcam and EV3 sending images into Dropbox. But how to put the obvious time and date stamp on the images? It turns out this is really easy to do using the Graphics2D Java class! A short tutorial on how to do this…

Java provides the Graphics2D class to do simple image manipulation natively. The nice thing about working with leJOS is that you can take advantage of all the existing Java classes in your code that runs on the EV3.

I used my previous code and added a call to the Graphics2D library to overlay the date and time. The thing to remember here is that you have to account for the font size when choosing the x,y location to place the text.

/**
    * Add overlay text with the current UTC date and battery voltage level onto the image
    * Text colour, font and size can be adjusted below
    * 
    * @param old Original image captured from the camera
    * @return new BufferedImage that contains the original image with text overlay
    */
   private BufferedImage addTextOverlay(BufferedImage old) {
       int w = old.getWidth();
       int h = old.getHeight();
       BufferedImage img = new BufferedImage(
               w, h, BufferedImage.TYPE_INT_RGB);
       Graphics2D g2d = img.createGraphics();
       g2d.drawImage(old, 0, 0, null);
       g2d.setPaint(Color.red);
       g2d.setFont(new Font("Serif", Font.BOLD, 15));
       
       // Get the current system date and time in UTC
       Date d = new Date(System.currentTimeMillis());
       String s = "" + d.toString();
       FontMetrics fm = g2d.getFontMetrics();
       int x = img.getWidth() - fm.stringWidth(s) - 5;
       int y = fm.getHeight();
       g2d.drawString(s, x, y);

       // Get the current battery level in mV
       s = "B: " + Battery.getVoltageMilliVolt() + " mV";
       x = img.getWidth() - fm.stringWidth(s) - 5;
       g2d.drawString(s, x, h - y - 5);
       
       g2d.dispose();
       return img;
   }

 

The full code is here: https://github.com/markcrosbie/lejos_projects/tree/0eb43b00e9d8b0bab6bd985ff6d663d02907db3b/SurveillanceCam

I pointed the webcam out of a window in the morning and left the EV3 running on battery power for the day. I was curious how long the battery would last for! It turns out about 7 hours is the answer. After running for that long I had over 2500 images in my Dropbox directory, which I then stitched together into a timelapse video. Cool!

]]>
http://thinkbricks.net/time-lapse-video-using-ev3-and-webcam/feed/ 0
Webcam + leJOS + Dropbox = wow! http://thinkbricks.net/webcam-lejos-dropbox-wow/ http://thinkbricks.net/webcam-lejos-dropbox-wow/#comments Sat, 25 Apr 2015 15:29:43 +0000 https://thinkbricks.net/?p=1204

Now that we have my EV3 connected to Dropbox, let’s have some fun. In this project I use a cheap webcam connected to the EV3 to take a photo and upload it into my Dropbox account. It’s a wireless digital camera using the EV3 and Dropbox!

2015-04-25 16.08.27

I recently bought a cheap webcam and USB hub at Frys electronics. This particular webcam (it cost me about $6) uses the RealTek chipset. leJOS 0.9.0 adds webcam support, and you can read more about it in Lawrie’s tutorial here: https://lejosnews.wordpress.com/2014/09/04/webcam-streaming/

I figured I could do one better, and capture files from the webcam, convert them to JPG and then use the Dropbox Core API to upload them into my Dropbox account. Let’s see how to do it!

I’m assuming you’ve connected your EV3 to your Dropbox as I explained in this tutorial.

Accessing the webcam

LeJOS 0.9.0 release added basic webcam support; only one webcam is supported and the images are returned in YUYV format. But that’s enough to have some fun with.  This little program will capture an image from the webcam and convert it to JPG format and then save it into the directory snapshots/with an incrementing filename. For fun you’ll also get a live image preview (in black and white) on the EV3 screen as well!

NewImage

Here I ran the Snapshot.jar from the command line. It reads the access-token.json file we created in the previous tutorial and uses that to authorise access to my Dropbox folder. When I press the ENTER button the code converts the YUYV format into JPG format, saves it to the EV3 SDcard and then uploads to Dropbox using the Dropbox API. The basics of uploading files in Dropbox is explained here: https://www.dropbox.com/developers/core/start/java

NewImage

The picture above shows what the output is – as you capture images they are uploaded into Dropbox and appear in Finder on my Mac always instantly. The images are at a 160×120 resolution as that is the size of the EV3 screen, but the camera supports much higher res images. Behold The Power of the Cloud!

The Code

The Java code is a combination of the leJOS webcam streaming tutorial code and the Dropbox Java tutorial code. Not the prettiest I’ll admit…

import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Locale;

import javax.imageio.ImageIO;

import lejos.hardware.BrickFinder;
import lejos.hardware.Button;
import lejos.hardware.Sound;
import lejos.hardware.ev3.EV3;
import lejos.hardware.lcd.GraphicsLCD;
import lejos.hardware.lcd.LCD;
import lejos.hardware.video.Video;
import lejos.hardware.video.YUYVImage;

import com.dropbox.core.*;
import com.dropbox.core.json.JsonReader;
import com.dropbox.core.util.IOUtil;

/**
 * Use a cheap webcam to take a snapshot and send the image to Dropbox.
 * Requires a Dropbox authorisation token to be created
 * EV3 needs to be connected to the wifi and the webcam connected too.
 * Requires leJOS 0.9.0 release and some setup. 
 * See http://thinkbricks.net/set-up-dropbox-in-lejos-on-the-ev3 for Dropbox-leJOS setup
 * 
 * Press ENTER button to take a photo. You should see it appear in your Dropbox folder
 * 
 * @author mcrosbie
 * http://thinkbricks.net
 * April 2015
 */

public class Snapshot {
   private static final int WIDTH = 160;
   private static final int HEIGHT = 120;
   private static int NUM_PIXELS = WIDTH * HEIGHT;
   private static int FRAME_SIZE = NUM_PIXELS * 2;
   private static final String AUTHFILENAME = "./access-token.json";
   private static final String FILENAME = "snapshots/snapshot_";

   public static void main(String args[]) throws IOException, DbxException {
	   int ret = _main(args);
	   System.exit(ret);
   }
   
   public static int _main(String[] args) throws IOException, DbxException  {
       int frames = 0;
       int threshold;
              
       // Default to access token file if not on cmd line
       String argAuthFile;
	   if (args.length != 1) {
		   argAuthFile = AUTHFILENAME;
	   } else {
		   argAuthFile = args[0];
	   }

       System.out.println("Reading auth info file " + argAuthFile);
       // Read auth info file.
       DbxAuthInfo authInfo;
       try {
           authInfo = DbxAuthInfo.Reader.readFromFile(argAuthFile);
       } catch (JsonReader.FileLoadException ex) {
         System.err.println("Error loading <auth-file>: " + ex.getMessage());
         return 1;
       }
       
       System.out.println("Creating Dropbox client...");

       // Create a DbxClient to make API calls.
       String userLocale = Locale.getDefault().toString();
       DbxRequestConfig requestConfig = new DbxRequestConfig("Snapshot", userLocale);
       DbxClient dbxClient = new DbxClient(requestConfig, authInfo.accessToken, authInfo.host);
 
       System.out.println("Open video camera...");
       // Get the video device and open the stream
       Video video = BrickFinder.getDefault().getVideo();
       video.open(WIDTH, HEIGHT);
     
       // Create the frame buffer to hold the image in
       byte[] frame = video.createFrame();
       BufferedImage img = new BufferedImage(WIDTH, HEIGHT,BufferedImage.TYPE_INT_RGB);
       YUYVImage yuyvImg = new YUYVImage(frame, video.getWidth(), video.getHeight());

       GraphicsLCD g = BrickFinder.getDefault().getGraphicsLCD();

       // Keep displaying an image. 
       // Save a file to storage when enter is pressed
       // Escape to exit
       g.clear();
       System.out.println("Starting main capture loop...");
       while (!Button.ESCAPE.isDown()) {
    	   try {
               video.grabFrame(frame);
               
               // Display on the EV3 screen
               threshold = yuyvImg.getMeanY();
               yuyvImg.display(g, 0, 0, threshold);
               
              if (Button.ENTER.isDown()) {
            	  Sound.playTone(500, 100);
                  for(int i=0;i<FRAME_SIZE;i+=4) {
                      int y1 = frame[i] & 0xFF;
                      int y2 = frame[i+2] & 0xFF;
                      int u = frame[i+1] & 0xFF;
                      int v = frame[i+3] & 0xFF;
                      int rgb1 = convertYUVtoARGB(y1,u,v);
                      int rgb2 = convertYUVtoARGB(y2,u,v);
                      img.setRGB((i % (WIDTH * 2)) / 2, i / (WIDTH * 2), rgb1);
                      img.setRGB((i % (WIDTH * 2)) / 2 + 1, i / (WIDTH * 2), rgb2);
                  }
                  
                  // Convert the RGB image into a jpg format
                  ByteArrayOutputStream baos = new ByteArrayOutputStream();
                  ImageIO.write(img, "jpg", baos);
                  byte[] jpgImageBytes = baos.toByteArray();

                  String filename = FILENAME+frames+".jpg";
                  System.out.println("Saving image to " + filename);
                  saveImageToFile(baos.toByteArray(), filename);
                  
                  System.out.println("Saving to Dropbox");
                  writeImageToDropbox(dbxClient, baos.toByteArray(), "/"+filename);
                  System.out.println("Done");
                  Sound.beepSequenceUp();
                  
            	  frames++;
              }
              
    	   } catch (IOException ioe) {
	           ioe.printStackTrace();
	           System.out.println("Driver exception: " + ioe.getMessage());
	           Sound.buzz();
	           return 1;
	      }
       }
      video.close();
      g.clear();
      return 0;
   }
   
    /**
    * Save an image file from the webcam to disk
    * 
    * @param img - image byte buffer
    * @param filename - file to store to
    */
   public static void saveImageToFile(byte[] img, String filename) {
	   try {
		   FileOutputStream fos = new FileOutputStream(filename);
		   fos.write(img);
		   fos.close();
	   } catch(IOException ioe) {
           ioe.printStackTrace();
           System.out.println("Driver exception: " + ioe.getMessage());		   
	   }
   }
   
   private static void writeImageToDropbox(DbxClient dbxClient, byte[] img, String dbFilename) 
		   throws DbxException, IOException {
       // Make the API call to upload the file.
       DbxEntry.File metadata;
       try {
    	   metadata = dbxClient.uploadFile(dbFilename, DbxWriteMode.add(), img.length, 
    			   new ByteArrayInputStream(img));
    	   System.out.println("Metadata: " + metadata.toStringMultiline());
       } catch (DbxException ex) {
               System.out.println("Error uploading to Dropbox: " + ex.getMessage());
       }
   }
    
   private static int convertYUVtoARGB(int y, int u, int v) {
       int c = y - 16;
       int d = u - 128;
       int e = v - 128;
       int r = (298*c+409*e+128)/256;
       int g = (298*c-100*d-208*e+128)/256;
       int b = (298*c+516*d+128)/256;
       r = r>255? 255 : r<0 ? 0 : r;
       g = g>255? 255 : g<0 ? 0 : g;
       b = b>255? 255 : b<0 ? 0 : b;
       return 0xff000000 | (r<<16) | (g<<8) | b;
   }

 }
]]>
http://thinkbricks.net/webcam-lejos-dropbox-wow/feed/ 4
Set up Dropbox in leJOS on the EV3 http://thinkbricks.net/set-up-dropbox-in-lejos-on-the-ev3/ http://thinkbricks.net/set-up-dropbox-in-lejos-on-the-ev3/#comments Sat, 25 Apr 2015 14:34:25 +0000 https://thinkbricks.net/?p=1188

NewImage.pngHere’s a quick tutorial to add Dropbox support into a Java program in leJOS 0.9.0. It turned out to be far easier than I thought! Read on to discover how you can easily upload and download files to and from your Dropbox account from the EV3 in leJOS.

Dropbox? On the EV3?

The first thing to realise is that I’m not going to show you how to install the Dropbox helper on your EV3. Instead we’re going to use the Dropbox Core Java SDK to connect our EV3 to your existing Dropbox account (free or pro, doesn’t matter) and then upload and download files into the account.

Dropbox is well known as a cloud file-sync service that ‘just works’. I’ve been using it for years, both as a pro and business user, and the software runs in the background, never complains and just gets on with the business of keeping all of your files in sync. Luckily Dropbox have extended the same simplicity to their SDK; I was amazing at just how easy it is to use the Java SDK in leJOs 0.9.0 to upload images captured from a webcam to my Dropbox account.

The Dropbox team have done a great job explaining how to use the Java SDK in a series of tutorials here: https://www.dropbox.com/developers/core/start/java
Getting ready
There are a few steps to get everything set up, but once you’ve done the setup you won’t have to repeat it. I’m assuming that these things are in place:
  1. You have a Dropbox account
  2. You have Eclipse installed and leJOS plugin installed
  3. You have a wifi equipped EV3 connected onto your home wifi
  4. You are comfortable logging into your EV3 using ssh in the terminal; you’ll need to run a program on the command line to authorise your EV3 to talk to Dropbox.
The basic flow is to import the Dropbox Java SDK into Eclipse, and then use the Dropbox API to creation an authorisation key that allows the EV3 to talk to your Dropbox account.

Step 1: Download the Dropbox Core API

The Java SDK is here: https://www.dropbox.com/developers/core. Download the Zip file and extract it into a folder on your laptop.
NewImage

Step 2: Create a new leJOS project in Eclipse

I’m assuming you have a working leJOS installation and the leJOS Eclipse plugin installed. If not, go to the leJOS website and follow the instructions on the wiki to get everything set up. Let’s call it DropboxSetup for now.

Step 3: Import the Dropbox Jar files from the SDK into your project

Right click on the DropboxDigitalCamera project, select Properties and then choose ‘Java Build Path’. Click ‘Add External JARs…” and navigate to the two JAR files in the dropbox-sdk/lib folder. Import them into the project and your build path should look something like this:
NewImage

Step 4: Create a new Dropbox app

Log into your Dropbox account and then go to the https://www.dropbox.com/developers/apps page and create a new Dropbox app. Make sure you create a Dropbox API app, and give it a name. The name you choose here will be used in your Dropbox/Apps folder when the EV3 uploads and downloads files. This is safer than giving your EV3 access to the all of the files in your Dropbox account.
NewImage

Step 5: Get the app key and app secret

Dropbox uses an app key and secret assigned to your app to create an access token. The access token is what you need to store on the EV3 so that it can authenticate itself to Dropbox and get access to files in your account.
If you click on the app from Step 4 in the App Console, you’ll see the App key and App secret displayed. Copy these values (obviously I’ve blurred the App key for my Dropbox account here).
NewImage

Step 6: Copy the Dropbox JARs onto the EV3

The Dropbox JARs need to be copied onto the EV3. The easiest way to do this is with your file browser, or scp them from your computer to the EV3. I placed the JARs in /home/lejos/programs/lib.

Step 7: Authorise the EV3 to Dropbox, get the auth token

The last step is to log into the EV3 and run a small Java program to connect the EV3 to your Dropbox account and get the authorisation token. The auth token is saved locally on the SDcard in the EV3 and used by all subsequent programs that need to talk to Dropbox.
The code you need to run is based off the Dropbox tutorial. Copy the App key and secret into the code below and then upload it from Eclipse onto the EV3. ssh into your EV3 and run the code below on the command line as follows:
jrun -cp /home/lejos/programs/lib/dropbox-core-sdk-1.7.7.jar:/home/lejos/programs/lib/jackson-core-2.2.4.jar:GetAccessToken.jar GetAccessToken

NewImage

Here is a screenshot of me running the code on my EV3. I’ve blurred out the app key and secret, and the returned authorisation code!

Step 8: You’re done!

That’s it – your EV3 is now authorised to talk to your Dropbox account, and the authorisation token is stored in the file access-token.json on the  EV3. If you lose this file it’s easy to run this program again and re-create it. But don’t share it with anyone, otherwise they can access your Dropbox account!

The code

Here's the code you need.

import com.dropbox.core.*;
import com.dropbox.core.json.JsonReader;

import java.io.*;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;

import lejos.hardware.lcd.LCD;

/**
 * An example command-line application that runs through the web-based OAuth
 * flow (using {@link DbxWebAuth}).
 * 
 * By Mark Crosbie http://thinkbricks.net
 * Modified from the Dropbox tutorial code
 */
public class GetAccessToken {
	
	// The access token is saved in this file on the EV3 SDcard
	public static final String accessTokenFilename = "./access-token.json";
	
    public static void main(String[] args) throws IOException {
    	
    	LCD.clear();
    	
    	System.out.println("-- Get Dropbox auth token --");
    	System.out.println("1. Log into Dropbox and go to the App Console in your account");
    	System.out.println("2. Click on the app you created for the EV3");
    	System.out.print("3. Enter the App key value here: ");
        String appKey = new BufferedReader(new InputStreamReader(System.in)).readLine();
        if (appKey == null) {
            System.exit(1); return;
        }
        appKey = appKey.trim();
        
        System.out.println("");
        System.out.print("4. Enter the App secret value here: ");
        String appSecret = new BufferedReader(new InputStreamReader(System.in)).readLine();
        if (appSecret == null) {
            System.exit(1); return;
        }
        appSecret = appSecret.trim();
        System.out.println("");
        
    	System.out.println("5. Starting Dropbox auth flow");
    	DbxAppInfo appInfo = new DbxAppInfo(appKey, appSecret);

        String userLocale = Locale.getDefault().toString();
        DbxRequestConfig config = new DbxRequestConfig("JavaTutorial/1.0", userLocale);
        DbxWebAuthNoRedirect webAuth = new DbxWebAuthNoRedirect(config, appInfo);

        // Run through Dropbox API authorization process
        String authorizeUrl = webAuth.start();
        System.out.println("6. Go to " + authorizeUrl);
        System.out.println("7. Click \"Allow\" (you might have to log in first).");
        System.out.println("8. Copy the authorization code.");
        System.out.print("9. Enter the authorization code here: ");

        String code = new BufferedReader(new InputStreamReader(System.in)).readLine();
        if (code == null) {
            System.exit(1); return;
        }
        code = code.trim();

        DbxAuthFinish authFinish;
        try {
            authFinish = webAuth.finish(code);
        }
        catch (DbxException ex) {
            System.err.println("Error in DbxWebAuth.start: " + ex.getMessage());
            System.exit(1); return;
        }

        System.out.println("10. Authorization complete.");
        System.out.println("- User ID: " + authFinish.userId);
        System.out.println("- Access Token: " + authFinish.accessToken);

        // Save auth information to output file.
        DbxAuthInfo authInfo = new DbxAuthInfo(authFinish.accessToken, appInfo.host);
        try {
            DbxAuthInfo.Writer.writeToFile(authInfo, accessTokenFilename);
            System.out.println("Saved authorization information to \"" + accessTokenFilename + "\".");
        }
        catch (IOException ex) {
            System.err.println("Error saving to : " + ex.getMessage());
            System.err.println("Dumping to stderr instead:");
            DbxAuthInfo.Writer.writeToStream(authInfo, System.err);
            System.exit(1); return;
        }
    }
}
]]>
http://thinkbricks.net/set-up-dropbox-in-lejos-on-the-ev3/feed/ 1
Book review: Lego Mindstorms EV3 Essentials eBook http://thinkbricks.net/book-review-lego-mindstorms-ev3-essentials-ebook/ http://thinkbricks.net/book-review-lego-mindstorms-ev3-essentials-ebook/#respond Wed, 21 Jan 2015 14:38:20 +0000 http://thinkbricks.net/?p=1176

I received a review electronic copy of Packt Publishing’s ‘Lego Mindstorms EV3 Essentials’ book. This book covers Java and leJOS programming on the EV3, so it differs from most other books on the market in that it choose a 3rd party environment rather than relying on the Lego-supplied one. It also requires a Linux environment as you will be typing a lot of commands in the terminal. The review copy I received is in electronic format so I can’t comment on the final print quality.

The challenge with writing a book based on an evolving open-source program is that you will be forever behind the curve. Despite being a relatively new publication this book is based on the 0.8.1 release of leJOS, which has been superseded by the 0.9.0 release. The leJOS team are constantly improving the platform and making it easier to install and program, so this book has already fallen out-of-date.

Chapter 2 of the ebook opens with coverage of the Lego Mindstorms EV3, and a survey of the sensors, motors and EV3 programmable brick. While it is welcome to have this in the book the content is nothing new; multiple pictures of the major pieces with some descriptive text. You can get this from Lego’s official website, and spending the first 40 pages of the book covering it again was not needed.

In Chapter 3 the on-brick programming functions of the EV3 brick area covered. Now this is where I started to get confused; wasn’t this book meant to be about leJOS programming and more advanced topics? Chapter 3 spends 30 pages covering on-brick programming, before finally we get to…

Chapter 4: leJOS – at last! This chapter introduces the leJOS Java environment for the EV3. Now the first problem is that the instructions given here are very Linux specific, so if you have a Windows or Mac then you are out of luck. Don’t worry though; Windows users have a graphical installer available to them from the official lejos.org website.

Chapter 5 discusses various ways to connect to the EV3. If you have a wifi dongle your EV3 can connect to your wifi hub and then you can simply ssh into it (or better yet, connect via the Eclipse plugin). If you don’t have a wifi dongle then you can use the USB cable and ssh to 10.0.1.1, which is the address the EV3 appears as to your PC or Mac.

This chapter spends a lot of time discussing how to configure the wifi password on the EV3 by editing the /etc/wpa_supplicant.conf file. Now this is certainly the hard-core Linux way to solve this problem, but by far the easier approach is to use the built-in wifi configuration screen on the EV3 to type in your wifi passphrase and connect automatically. This is covered in better detail at the leJOS website.

Chapter 6: this chapter covers programming the EV3 in Java, and it’s where I have a big issues with the book. It leaps into a discussion of the Gradle Java build environment. However all of the guidance on the lejos.org website is around using Eclipse to do your development, with ant build files. There’s no problem in choosing an alternate build environment but I think that an introductory book should have just stuck to the standard IDE suggested by the leJOS project. Another problem in the text is that once you have compiled your program the book suggests that you remove the SDcard from the EV3 and insert it into the computer to manually copy the .class files over. But we just spent the whole last chapter configuring our wifi and setting up ssh keys to avoid this! Very confusing.

Chapter 7 covers the basic operation of moving the motor and using the touch sensor. This is so basic that it really doesn’t require a whole chapter; one program to make the motor go forwards and another to wait for a press of the touch sensor.

Chapter 8, 9 and 10 discuss building a line-follower robot (your read that right; three chapters to cover one of the most basic robots). I was disappointed to find that the code in this chapter re-invented the wheel. It built a very simple differential-drive line follower robot that used simple rotations to try and find the line. The logic of the line-follower program uses a narrow sweep to find the line and if that fails it performs a wider sweep. This is the classic single sensor approach to line-following.

The author spends 60 pages over three chapters creating the line-follower code. This is the longest treatment of a line-follower robot I have ever read. I would suggest instead presenting the final program first and then explaining the parts step-by-step. I found it very difficult to follow all of the modifications made to the source code over three chapters.

Avoiding re-inventing code is critical to bug-free programming, but the sample line-follower robot reinvents the DifferentialPilot class from leJOS. There is little point in choosing the leJOS environment if you are not going to show users how to get the most advantage from using the class library!

The code also failed to perform one of the most basic tasks of a line-following robot; calibrating the colour sensor to the line and non-line parts of the floor! It assumes that you can specify the colour of the line absolutely in the code, and there will be no interference from ambient light or noise. As anyone who has built a line-follower knows this is far from true!

So now we’ve built a basic line-follower robot and…the book is complete! Appendix A explains how to use Make in great detail (why?) and Appendix B gives two pages over to the various IDEs available for Java (again, why?)

This book does not contain building instructions, and it contains one programming project; a very simple line-following robot.

Conclusion: I’d avoid buying this book and instead use the tutorials available for free on the lejos.org website. It was very disappointing, spending more time on introductory concepts instead of creating advanced projects in Java and leJOS.

]]>
http://thinkbricks.net/book-review-lego-mindstorms-ev3-essentials-ebook/feed/ 0
Red Racer – a power functions racing car http://thinkbricks.net/red-racer-a-power-functions-racing-car/ http://thinkbricks.net/red-racer-a-power-functions-racing-car/#respond Sun, 21 Dec 2014 17:53:15 +0000 http://thinkbricks.net/?p=1139

Sometimes it’s fun to just build something different for a change. Red Racer is my version of Sunsky’s lovely Snow White Racing Machine  which I updated to use the new power functions servo for steering and medium motor for drive. I also styled it in red.

I came across the Show White racing machine a few years ago and had saved it for a future date to build. I really liked the clean and simple lines and compact design of the original, and decided to take advantage of the Christmas holiday to build my own version.

My first challenge was that I didn’t have any of the steering parts used in the original racer! Time for some thinking…if I was going to change how the steering worked I may as well upgrade the steering to use the new power functions servo motor.

Luckily Sunsky’s post on the original design had presented detailed disassembly instructions so I was able to build an initial version of the racer, and then modify it to use the new Power Functions motor and servo. I had to widen the chassis by one stud so that everything would fit, and increase the length too so the servo would fit.

The original car was styled in white, but I chose red as I did not have enough white pieces. One thing I learned from this build; I’ve a lot to learn about designing bodies for cars!

2014-12-20 23.39.36 HDR 2014-12-20 23.46.19 HDR 2014-12-20 23.46.08 HDR 2014-12-20 23.45.55 HDR 2014-12-20 23.45.35 HDR 2014-12-20 23.45.17 HDR 2014-12-20 23.45.05 HDR 2014-12-20 23.45.00 HDR 2014-12-20 23.44.43

]]>
http://thinkbricks.net/red-racer-a-power-functions-racing-car/feed/ 0