ChibiDuino RoboCar

From MalaWiki
Jump to: navigation, search

Reference and kit: ちっちゃいものくらぶ (Tiny Things Club)

Assuming you already have soldered all the parts and use the provided usb-to-serial connector, here is how to set up your Debian GNU/Linux (or any other distribution for that matters) workstation to interface with the hardware.

On the positive side you don't have to install anything extra, stock Linux kernel and all Debian packaged tools work just fine.

First things first, install Arduino IDE and all dependencies:

sudo apt-get install arduino

Contents

USB-to-Serial

The driver for CH341 chip apparently landed in Linux mainline back in 2007:

commit 6ce76104781a10554129791dc62c3104424f6d48
Author: Frank A Kingswood <frank@kingswood-consulting.co.uk>
Date:   Wed Aug 22 20:48:58 2007 +0100

    USB: Driver for CH341 USB-serial adaptor

    This patch implements a USB serial port driver for the Winchiphead
    CH341 USB-RS232 Converter. This chip also implements an IEEE 1284
    parallel port, I2C and SPI, but that is not supported by the driver.

    Signed-off-by: Frank A Kingswood <frank@kingswood-consulting.co.uk>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

You don't have to compile the vendor driver, just ensure that you have

CONFIG_USB_SERIAL=m
CONFIG_USB_SERIAL_CH341=m

rebuild your kernel if necessary and plug the adapter into your computer:

[153278.478715] usb 1-1: new full-speed USB device number 17 using xhci_hcd
[153278.608187] usb 1-1: New USB device found, idVendor=1a86, idProduct=7523
[153278.608198] usb 1-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[153278.608203] usb 1-1: Product: USB2.0-Serial
[153278.608880] ch341 1-1:1.0: ch341-uart converter detected
[153278.609850] usb 1-1: ch341-uart converter now attached to ttyUSB0

I tried using the vendor driver and found several problems:

  1. it doesn't compile right away with recent kernels (3.15 in my case), the patch below is required
  2. this driver seems to have some weird timing issues once attached to the ChibiDuino board, uploading code with avrdude sometimes doesn't synchronize (one workaround is to enable verbose execution to slow down avrdude)
    avrdude: stk500_getsync(): not in sync: resp=0×00

Patch for out-of-tree ch341.c

The version that was available from here when I tried it, didn't compile against 3.15, this patch just forward port the driver to linux-3.15. Use at your own risk:

--- CH341SER_LINUX.orig/ch34x.c	2013-08-09 00:00:00.000000000 +0900
+++ CH341SER_LINUX/ch34x.c	2014-06-29 09:54:49.665595749 +0900
@@ -381,7 +381,7 @@ static void ch34x_set_termios( struct us
 	unsigned short value = 0;
 	unsigned short index = 0;
 
-	dbg_ch34x("%s - port:%d", __func__, port->number);
+	dbg_ch34x("%s - port:%d", __func__, port->port_number);
 	
 	spin_lock_irqsave( &priv->lock, flags );
 	if( !priv->termios_initialized ) {
@@ -402,7 +402,7 @@ static void ch34x_set_termios( struct us
 		return;
 
 	cflag = termios->c_cflag;
-	dbg_ch34x("%s (%d) cflag=0x%x\n", __func__, port->number, cflag );
+	dbg_ch34x("%s (%d) cflag=0x%x\n", __func__, port->port_number, cflag );
 
 	// Get the byte size
 	switch( cflag & CSIZE )
@@ -509,7 +509,7 @@ static int ch34x_tiocmget( struct usb_se
 	/*unsigned int msr;*/
 	unsigned int retval;
 
-	dbg_ch34x("%s - port:%d", __func__, port->number);
+	dbg_ch34x("%s - port:%d", __func__, port->port_number);
 
 	if( !usb_get_intfdata( port->serial->interface) ) 
 		return -ENODEV;
@@ -552,7 +552,7 @@ static void ch34x_close( struct usb_seri
 	long timeout;
 	wait_queue_t wait;
 
-	dbg_ch34x("%s - port:%d", __func__, port->number);
+	dbg_ch34x("%s - port:%d", __func__, port->port_number);
 	
 	// wait for data do drain from the buffer
 	spin_lock_irqsave( &priv->lock, flags );
@@ -623,7 +623,7 @@ static int ch34x_open( struct usb_serial
 	struct usb_serial *serial = port->serial;
 	int retval;
 
-	dbg_ch34x("%s - port:%d", __func__, port->number );
+	dbg_ch34x("%s - port:%d", __func__, port->port_number );
 
 	usb_clear_halt( serial->dev, port->write_urb->pipe );
 	usb_clear_halt( serial->dev, port->read_urb->pipe );
@@ -694,7 +694,7 @@ static int ch34x_tiocmset( struct usb_se
 	/*unsigned int mcr = priv->line_control;*/
 	u8 control;
 
-	dbg_ch34x("%s - port:%d", __func__, port->number);
+	dbg_ch34x("%s - port:%d", __func__, port->port_number);
 
 	if( !usb_get_intfdata(port->serial->interface) ) 
 		return -ENODEV;
@@ -723,17 +723,18 @@ static int wait_modem_info( struct usb_s
 	unsigned int status;
 	unsigned int changed;
 
-	dbg_ch34x("%s -port:%d", __func__, port->number);
+	dbg_ch34x("%s -port:%d", __func__, port->port_number);
 
 	spin_lock_irqsave( &priv->lock, flags );
 	prevstatus = priv->line_status;
 	spin_unlock_irqrestore( &priv->lock, flags );
 
 	while(1) {
-		interruptible_sleep_on( &priv->delta_msr_wait );
+		int r = wait_event_interruptible( priv->delta_msr_wait,
+				signal_pending(current) );
 		// see if a signal did it
-		if( signal_pending(current) ) 
-			return -ERESTARTSYS;
+		if( !r )
+			return r;
 
 		spin_lock_irqsave( &priv->lock, flags );
 		status = priv->line_status;
@@ -770,13 +771,13 @@ static int ch34x_ioctl( struct usb_seria
 {
 	//struct usb_serial_port *port = tty->driver_data;
 #endif
-	dbg_ch34x("%s - port:%d, cmd=0x%04x", __func__, port->number, cmd);
+	dbg_ch34x("%s - port:%d, cmd=0x%04x", __func__, port->port_number, cmd);
 
 	switch(cmd)
 	{
 		// Note here 
 		case TIOCMIWAIT:
-			dbg_ch34x("%s - port:%d TIOCMIWAIT", __func__, port->number);
+			dbg_ch34x("%s - port:%d TIOCMIWAIT", __func__, port->port_number);
 			return wait_modem_info(port, arg);
 		default:
 			dbg_ch34x("%s not supported=0x%04x", __func__, cmd);
@@ -793,7 +794,7 @@ static void ch34x_send( struct usb_seria
 	struct ch34x_private *priv = usb_get_serial_port_data( port );
 	unsigned long flags;
 
-	dbg_ch34x("%s - port:%d", __func__, port->number );
+	dbg_ch34x("%s - port:%d", __func__, port->port_number );
 
 	spin_lock_irqsave( &priv->lock, flags );
 	if( priv->write_urb_in_use ) {
@@ -843,7 +844,7 @@ static int ch34x_write( struct usb_seria
 	struct ch34x_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
 
-	dbg_ch34x("%s - port:%d, %d bytes", __func__, port->number, count);
+	dbg_ch34x("%s - port:%d, %d bytes", __func__, port->port_number, count);
 
 	if( !count )
 		return count;
@@ -869,7 +870,7 @@ static int ch34x_write_room( struct usb_
 	int room = 0;
 	unsigned long flags;
 
-	dbg_ch34x("%s - port:%d", __func__, port->number );
+	dbg_ch34x("%s - port:%d", __func__, port->port_number );
 
 	spin_lock_irqsave( &priv->lock, flags );
 	room = ch34x_buf_space_avail( priv->buf );
@@ -891,7 +892,7 @@ static int ch34x_chars_in_buffer( struct
 	int chars = 0;
 	unsigned long flags;
 
-	dbg_ch34x("%s - port:%d", __func__, port->number );
+	dbg_ch34x("%s - port:%d", __func__, port->port_number );
 
 	spin_lock_irqsave( &priv->lock, flags );
 	chars = ch34x_buf_data_avail( priv->buf );
@@ -997,7 +998,7 @@ static void ch34x_read_int_callback( str
 	int status = urb->status;
 	int retval;
 
-	dbg_ch34x("%s port:%d", __func__, port->number );
+	dbg_ch34x("%s port:%d", __func__, port->port_number );
 
 	switch( status ) {
 		case 0: //success
@@ -1042,7 +1043,7 @@ static void ch34x_read_bulk_callback( st
 	u8 line_status;
 	char tty_flag;
 
-	dbg_ch34x("%s - port:%d", __func__, port->number );
+	dbg_ch34x("%s - port:%d", __func__, port->port_number );
 	if( status ) {
 		dbg_ch34x("%s - urb status=%d", __func__, status );
 		if( status == -EPROTO ) {
@@ -1144,7 +1145,7 @@ static void ch34x_write_bulk_callback( s
 	int retval;
 	int status = urb->status;
 
-	dbg_ch34x("%s - port:%d", __func__, port->number );
+	dbg_ch34x("%s - port:%d", __func__, port->port_number );
 
 	switch( status ) {
 		case 0: //success

Board configuration for Arduino IDE

You have two options, none of them is optimal in my opinion:

  1. add the configuration below to /usr/share/arduino/hardware/arduino/boards.txt
  2. copy /usr/share/arduino/hardware/arduino/boards.txt to your sketchbook/hardware/arduino/ directory and add the board definition there

The downsides are:

  1. with this solution, every upgrade of the Arduino IDE package will wipe your configuration to a new one
  2. with this solution, every board added with an upgrade of the Arduino IDE package will not be available to you until you update your local copy of the boards.txt file

From: http://tiisai.dip.jp/?p=2491

####################################################
atmega8o83.name=chibiDuino pro ATmega8 38400 optiboot

atmega8o83.upload.protocol=arduino
atmega8o83.upload.maximum_size=7680
atmega8o83.upload.speed=38400

atmega8o83.bootloader.low_fuses=0×94
atmega8o83.bootloader.high_fuses=0xDC
atmega8o83.bootloader.path=optiboot
atmega8o83.bootloader.file=optiboot_cp83.hex
atmega8o83.bootloader.unlock_bits=0×3F
atmega8o83.bootloader.lock_bits=0×0F

atmega8o83.build.mcu=atmega8
atmega8o83.build.f_cpu=8000000L
atmega8o83.build.core=arduino
atmega8o83.build.variant=standard

###################################################

My maze solving project

Requires the Ultra library to get an easy interface on the Ultrasonic sensor: http://playground.arduino.cc/Main/LibraryList#Sensors

Probably works also with the more advanced NewPing library, I haven't tried yet.

#include <Ultra.h>

#define WHEEL_OFF  0
#define WHEEL_FW   1
#define WHEEL_BK   2

// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led          = 13;

int rwheel_1    =  7;
int rwheel_2    =  8;
int lwheel_1    =  9;
int lwheel_2    = 10;

Ultra sonar(6, 5);

void operate_wheel(int pin_fw, int pin_bk, int dir) {
  if (dir == WHEEL_FW) {
    digitalWrite(pin_fw, HIGH);
    digitalWrite(pin_bk, LOW);
  }
  else if (dir == WHEEL_BK) {
    digitalWrite(pin_fw, LOW);
    digitalWrite(pin_bk, HIGH);
  }
  else { // (dir == WHEEL_OFF)
    digitalWrite(pin_fw, LOW);
    digitalWrite(pin_bk, LOW);
  }
}
 
void right(int dir) {
  operate_wheel(rwheel_1, rwheel_2, dir);
}

void left(int dir) {
  operate_wheel(lwheel_1, lwheel_2, dir);
}

void stop() {
  right(WHEEL_OFF);
  left(WHEEL_OFF);
}

void setup() {
  // initialize digital pins as outputs
  pinMode(led, OUTPUT);
  // right wheel
  pinMode(rwheel_1, OUTPUT);
  pinMode(rwheel_2, OUTPUT);
  pinMode(lwheel_1, OUTPUT);
  pinMode(lwheel_2, OUTPUT);
  stop();
  randomSeed(sonar.Range());
}

int needs_turn = 0;
void loop() {
  int dist = sonar.Range();
  if (dist < 5 && dist > 0) {
    right(WHEEL_BK);
    left(WHEEL_BK);
    digitalWrite(led, HIGH);
    delay(random(200, 700));
    needs_turn = 1;
  } else {
    if (needs_turn) {
      if (random(1)) {
        right(WHEEL_BK);
        left(WHEEL_FW);
      } else {
        right(WHEEL_FW);
        left(WHEEL_BK);
      }
      delay(random(200, 700));
      needs_turn = 0;
    }
    right(WHEEL_FW);
    left(WHEEL_FW);
    digitalWrite(led, LOW);
  }
}
Personal tools