Thursday, October 15, 2015

BBB: use tftp for remote boot

Once Kernel is built wrong, it can't boot up,  or you delete /bin/ some files by accident, nothing can run, even ls command, DON'T BE panic.. You can use tftp to reboot from other PC.

First you have one Linux PC which tftp is installed and enabled.
Then you can put compiled Kernel and root file system to Linux PC, BBB board can boot from this PC with Kernel and root file system.

After BBB board is powered on, press enter key quickly, it will enter u-boot mode, you need to set BBB board local IP address, Linux PC server IP address and tftp boot command. Something like:

Linux PC IP address:
setenv serverip 192.168.2.99

BBB board IP address
setenv ipaddr 192.168.2.97

Linux Kernel, you need to put Kernel uImage file at /tftpboot
tftp 0x80200000 uImage-dtb.am335x-boneblack

u-boot will download Kernel image to BBB board.

Set root file system, nfs service is installed and enabled at Linux PC
setenv bootargs console=ttyO0,115200n8 root=/dev/nfs rw nfsroot=192.168.2.99:/home/bsang/sang/robot/bbb/rootfs ip=192.168.2.97:::::eth0

boot BBB board
bootm 80200000

Congratulation! Your BBB board is still working. You can new Kernel to BBB or you can upgrade root file system. Your life is saved.

Sunday, September 20, 2015

NezaRobot H/W: Power supply

NezaRobot Power supply:
1) Input: +12VDC
2) Output:
a: +3.3V (ez430 board, CAN bus)

b: +5.0V (BBB board)

c: +6.0V (Servos)

d: +12.0V (Motors)



Monday, September 14, 2015

NezaRobot H/W: ez430 - CAN bus board


Figure 1: CAN Bus of ez430 schematic
As showed above figure, MCP2515 is a stand-alone CAN controller with SPI interface. ez430 connects to MCP2515 through SPI interface to put in CAN bus devices to send and receive command to/from BBB board. MCP2515 supports CAN V2.0B at 1Mb/s.

MCP2515 output is TTL (+3.3V) level, a transceiver is required to convert TTL level to CAN bus standard. I use SN65HVD230, it is 3.3V CAN transceivers.





Figure 2: ez430 and CAN Bus board
ez430 board is used to control 2 motors, speed and direction through CAN bus connected to BBB board.



Sunday, September 13, 2015

NezaRobot HW: BBB board connection

In NezaRobot, I only use BBB to control 6 servos and 1 CAN bus and USB WIFI.
6 PWM: 
ehrpwm0A-0B, 1A-1B, 2A-2B, 3 groups PWM timer. 

1 CAN Bus:
CAN bus needs a converter to convert +3.3V level to CAN bus standard.

1 serial port:
It is for debugging

Other pins are not used.
I use KiCAD for draw electronic schematics. It is open source and free.




From above figure, BBB has +5.0VDC connector, 1 USB WIFI, Serial port, CAN Bus, 6 PWM servo controllers.


Thursday, September 10, 2015

BBB: Kernel - CAN Bus support

BBB board has two CAN bus, can0 is enabled by default. For NezaRobot, one CAN bus is enough. It is used to communicate to ez430 board to send out motor control command.

Oscillator of BBB CAN bus clock used is 20MHz, but I can't find the same frequency oscillator, before I have one board from other project which oscillator is 12.288MHz, no matter what register to configure, it is very difficult to match with 20MHz, communication sometimes is lost, finally I found one 24MHz oscillator from my old video card. Then configure CAN bus register, both are exactly matched.

#enable CAN device
echo BB-DCAN1 > /sys/devices/bone_capemgr.9/slots

#configure bitrate to be 300Kbps
./canconfig can0 bitrate 300000

#network up
ifconfig can0 up

Wednesday, September 9, 2015

NezaRobot H/W: H-Bridge motor control

H-bridge is a standard method to control DC motor. P4 controls direction, and P10 is PWM from microchip to control motor speed.

Thursday, September 3, 2015

NezaRobot: Demo





Home Page

BBB: Kernel - USB WIFI support


At NezaRobot, BBB will communicate with smart phone to receive object detection information, such as ball and goal location.
BBB has one USB port, I insert it with a USB Wifi, it happens to be rt2800 which Kernel support this.
After compile Kernel and driver, you can copy following drivers and install them after reboot.  You can put following commands into one script.

#install all necessary drivers
insmod rfkill.ko
insmod cfg80211.ko
insmod mac80211.ko
insmod lib80211.ko
insmod rt2x00lib.ko
insmod rt2800lib.ko
insmod rt2x00usb.ko
insmod rt2800usb.ko

#like eth0 is ethernet, wlan0 is for Wifi
ip link set wlan0 up

#turn off power save, otherwise it is not stable
iw dev wlan0 set power_save off

#read configure file and set user name, password to your home Wifi server
wpa_supplicant -B -D wext -i wlan0 -c /etc/wpa_supplicant.conf

#you can scan your Wifi server now
#iw dev wlan0 scan | grep SSID

#ip addr show wlan0
#ip link show wlan0

iw dev wlan0 link

#my home router is 192.168.2.1
ifconfig wlan0 192.168.2.77 up

configure file:
vi /etc/wpa_supplicant.conf


ctrl_interface=/var/run/wpa_supplicant
network={
    ssid="BELL647"
    proto=WPA2
    pairwise=CCMP
    group=CCMP
    key_mgmt=WPA-PSK
    #psk="password"
    psk=generated 64 hex
}
psk is generated by wpa_passphrase tool. For example, my router ssid is BELL647, password is 12345678

wpa_passphrase BELL647 12345678

network={
        ssid="BELL647"
        #psk="12345678"
        psk=ab2c7c0b8e0d9abe8c28418fd47365b7efb834fafd9d4c21986c648b39a0e0a2
}

so /etc/wpa_supplicant.conf should be:
ctrl_interface=/var/run/wpa_supplicant
network={
        ssid="BELL647"
        proto=WPA2
        pairwise=CCMP
        group=CCMP
        key_mgmt=WPA-PSK
        #psk="12345678"
        psk=ab2c7c0b8e0d9abe8c28418fd47365b7efb834fafd9d4c21986c648b39a0e0a2
}

Save file, reboot, run above script, Wifi should work.

ifconfig:
root@beaglebone:~# ifconfig
can0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
          UP RUNNING NOARP  MTU:16  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:10
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
          Interrupt:71

eth0      Link encap:Ethernet  HWaddr C8:A0:30:AC:87:22
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
          Interrupt:56

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:20 errors:0 dropped:0 overruns:0 frame:0
          TX packets:20 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1760 (1.7 KiB)  TX bytes:1760 (1.7 KiB)

wlan0     Link encap:Ethernet  HWaddr 00:87:34:1D:96:BA
          inet addr:192.168.2.77  Bcast:192.168.2.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2 errors:0 dropped:0 overruns:0 frame:0
          TX packets:35 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:282 (282.0 B)  TX bytes:3534 (3.4 KiB)

Congratulation! Now you can ping to and from 192.168.2.77
For wpa_supplicant please refer to:
WPA supplicant

Wednesday, September 2, 2015

BBB: Kernel - Servo PWM support


Above figure is about servo control signal, period is about 20ms, adjust duration to set servo position. It can be controlled by BBB timers. BBB has 6 timers to output PWM signal. That means it can control 6 servos at same time. But default Kernel doesn't support 20ms period.
By default, Linux Kernel timer period can't be changed, it is hardcoded to be 500000. That is 500K ps = 0.5ms. To control servo,  period must set to about 20ms, so this value should be 20000000 = 20 ms. All servos shares this same period value.

You need to modify Kernel source code to set it. Another thing is, PWM timer is enabled by default, servo will start to work as soon as power is on. It is not expected behaviour. If you have 6 servos, all servos will consume current at same time, they move to initial positions together, it may break power supply. You need to modify pwm dts file to disable PWM output, then let application to enable it when necessary. 

pwm dts file looks like bone_pwm_P8(or 9)_xx-00A0.dts, they are located at kernel\kernel\firmware\capes\
For example, 
kernel\kernel\firmware\capes\bone_pwm_P9_31-00A0.dts

/*
 * Copyright (C) 2013 CircuitCo
 * Copyright (C) 2013 Texas Instruments
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
/dts-v1/;
/plugin/;

/ {
compatible = "ti,beaglebone", "ti,beaglebone-black";

/* identification */
part-number = "bone_pwm_P9_31";
version = "00A0";

/* state the resources this cape uses */
exclusive-use =
/* the pin header uses */
"P9.31", /* pwm: ehrpwm0A */
/* the hardware IP uses */
"ehrpwm0A";

fragment@0 {
target = <&am33xx_pinmux>;
__overlay__ {
pwm_P9_31: pinmux_pwm_P9_31_pins {
pinctrl-single,pins = <0x190  0x1>; /* P9_31 (ZCZ ball A13) | MODE 1 */
};
};
};

fragment@1 {
target = <&ocp>;
__overlay__ {
pwm_test_P9_31 {
compatible = "pwm_test";
pwms = <&ehrpwm0 0 500000 1>;
pwm-names = "PWM_P9_31";
   pinctrl-names = "default";
   pinctrl-0 = <&pwm_P9_31>;
enabled = <1>;
duty = <0>;
status = "okay";
};
};
};
};


Modify:
pwms = <&ehrpwm0 0 500000 1>;
to
pwms = <&ehrpwm0 0 20000000 1>;

Modify:
enabled = <1>;
to
enabled = <0>;

Then compile kernel and update image file. DTS files are embedded into Kernel image.

You need to install pwm_test driver which enabled pwm for servo after boot.

insmod pwm_test.ko

Some PWM pins are shared with HDMI tx, to use these pins, disable HDMI tx by edit uEnv.txt file.

more /media/BEAGLEBONE/uEnv.txt
optargs=quiet drm.debug=7 capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN
capemgr.enable_partno=am33xx_pwm,bone_pwm_P9_31

Add following code in start-up script to enable all 6 PWM timers.

echo am33xx_pwm > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P9_31 > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P9_29 > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P8_36 > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P8_34 > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P8_45 > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P8_46 > /sys/devices/bone_capemgr.9/slots

For example to control PWM P9_31:
start PWM P9_31
echo 1 > /sys/devices/ocp.3/pwm_test_P9_31.12/run

set polarity of duty to be 0, must be 0
echo 0 > /sys/devices/ocp.3/pwm_test_P9_31.12/polarity

set duty to control servo position
echo 50000 > /sys/devices/ocp.3/pwm_test_P9_31.12/duty


BBB: Kernel - Source code and Cross Compiling

BBB Linux Kernel:
1) Download tool chain
Arm GCC build tool: Linaro
https://wiki.linaro.org/WorkingGroups/ToolChain

2) Download kernel for beagleboard
git clone git://github.com/beagleboard/kernel.git

3) Cross compiling

cd kernel
git checkout 3.8
./patch.sh

cp configs/beaglebone kernel/arch/arm/configs/beaglebone_defconfig

wget http://arago-project.org/git/projects/?p=am33x-cm3.git\;a=blob_plain\;f=bin/am335x-pm-firmware.bin\;hb=HEAD -O kernel/firmware/am335x-pm-firmware.bin

cd kernel
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- beaglebone_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage dtbs
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage-dtb.am335x-boneblack
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules


Android: Visual Soccer and Goal Detection



Soccer is pingpang ball, since it is semi-transparent and has black letter on it, it is very hard to filter colour under OpenCV, so I painted it with water colour. 
Same with goal, to easy distinguish, painted it with blue water colour.

OpenCV is very powerful, it has plenty of functions for object detection. The main idea is, with smart phone camera, convert image to grey under HSV space, then filter colour, blur it then detect circle for soccer and rectangle for goal.  

Following is source code for visual soccer and goal detection under Android with JNI c code.

Using OpenCV library under Android, ball is coloured to red and net is coloured to blue.


int detectDoor(Mat & img_rgba, int & door_x, int & door_y)
{
Mat img_temp;
Mat img_work;
Mat img_gray;
int sel_id;
int max_area;

Mat img_3;
Mat kernel_ero = getStructuringElement(MORPH_RECT, Size(2,2));

int h;
int s;
int v;

door_x = 0;
door_y = 0;

h = 237/2;
s = 100*2 + 55;
v = 25*2 + 55;

cv::cvtColor(img_rgba, img_temp, CV_RGB2HSV); // convert to HSV
  inRange(img_temp, Scalar(266/2-20, 0, 0), Scalar(266/2+20, 255, 255), img_work); // filter color
  cv::blur(img_work, img_gray, Size(30, 30));

threshold(img_gray, img_gray, 100, 255, CV_THRESH_BINARY);
  erode(img_gray, img_gray, kernel_ero);

Size sz;
vector<vector<Point> > contours;
    vector<vector<Point> > contours0;
    vector<Vec4i> hierarchy;

    findContours( img_gray, contours0, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
    int idx = 0;

    sel_id = 0;
    max_area = 0;
    for( idx = 0; idx < contours0.size(); idx++ )
    {
    Rect r = boundingRect(contours0[idx]);
        Scalar color( 255, 0, 0 );
        if(hierarchy[idx][2] < 0) //Check if there is a child contour
           rectangle(img_rgba,Point(r.x-10,r.y-10), Point(r.x+r.width+10,r.y+r.height+10), Scalar(0,0,255),2,8,0); //Opened contour
         else
           rectangle(img_rgba,Point(r.x-10,r.y-10), Point(r.x+r.width+10,r.y+r.height+10), Scalar(0,255,0),2,8,0); //closed contour

        if( max_area < r.width * r.height)
        {
        max_area = r.width * r.height;
        sel_id = idx;
        }
    }
// choose area > 400
    if( max_area > 400 )
    {
    Rect r = boundingRect(contours0[sel_id]);
    door_x = r.x + r.width/2;
    door_y = r.y + r.height/2;
        circle(img_rgba,Point(door_x,door_y),20, Scalar(255,0,0), 3, 8, 0); //closed contour
    }
return 0;
}

JNIEXPORT jintArray JNICALL Java_com_example_balltrace_BallTrace_BallDetect(JNIEnv* env, jobject thiz,
jint width, jint height, jlong yuv, jlong rgba, jlong outPtr)
{
jint outArray[5];
Mat mGray = *((Mat*)yuv);
Mat mRgba = *((Mat*)rgba); // original camera image

int door_x = 0;
int door_y = 0;

Mat hsv_frame;

outArray[0] = 0;
outArray[1] = 0;
outArray[2] = 0;
outArray[3] = -1; // door rect center X
outArray[4] = -1; // door rect center y

detectDoor(mRgba, door_x, door_y);

outArray[3] = door_x;
outArray[4] = door_y;

//Mat thresholded;
cv::Mat* thresholded = new cv::Mat(cv::Size(width, height), CV_8UC1);
cv::Rect roi( cv::Point( 0, 0 ), Size(width, height) );
    CvSize size = cvSize(width, height);
    cvtColor(mRgba, hsv_frame, CV_RGB2HSV);

    inRange(hsv_frame, Scalar(1, 80, 80), Scalar(7, 250, 250), *thresholded);

    GaussianBlur(*thresholded, *thresholded, Size(9,9), 0, 0);
    vector<Vec3f> circles;
    HoughCircles(*thresholded, circles, CV_HOUGH_GRADIENT,1.5, height/4, 100, 40, 15, 80 );

    for( size_t i = 0; i < circles.size(); i++ )
    {
    Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
        int radius = cvRound(circles[i][2]);

        if( radius < 5 )
        continue;
        // draw the circle center
        circle( mRgba, center, 3, Scalar(0,255,0), -1, 8, 0 );
        // draw the circle outline
        circle( mRgba, center, radius, Scalar(0,0,255), 3, 8, 0 );
        outArray[0] = cvRound(circles[i][0]);
        outArray[1] = cvRound(circles[i][1]);
        outArray[2] = radius;
        break;
    }

    delete thresholded;

    jintArray retArray = env->NewIntArray(5);
    env->SetIntArrayRegion(retArray, 0 , 5, outArray);

    return retArray;
}


Robot Hardware


1. Smart phone Nexus 5


CPU: Qualcomm SnapdragonTM 800, 2.26GHz
RAM: 2 GB
Sensors: GPS, Gyroscope, Accelerometer, Compass, Proximity/Ambient, Light, Pressure, Hall Effect
Android 4.4

This smart phone is very powerful. It has everything for image recognition, fast CPU, huge DRAM, open-source OS Android. It can detect ball and net very quickly at real time. So the Robot can respond as fast as possible. In addition, embedded sensors can give the Robot enough information for accurate position control.
Since it is Android system, plenty of free samples and free source code can be found in open source world. Unlike iPhone, Nexus 5 is free to program on it. User can get free development environment tools from internet.
OpenCV is open source and standard image recognition software, it has reach functions for object detection and widely used by commercial field. It is powerful but simple for programmer.

2. BeagleBone Black Development Board


CPU: 1GHz AM3359 Sitara ARM Cortex-A8
RAM: 512MB DDR3
CAN Bus
Wifi
6 Timers
It is ARM9 CPU, running Linux OS. With its WI-FI, it can communicate with smart phone through TCP/IP protocol. <br>
Six Timers IO control 6 servos, 4 of them for arm and 2 for smart phone panning and tilting control.
CAN BUS is for eZ430 board communication to control 2 rear wheels DC motors.
With process programming, it can search ball by head servos panning and tilting, moving arm to kick and grab ball and driving the Robot.

3. TI micro controller


eZ430-RF2500 Development Board
CAN Bus
Timer 2 - for Motor control
It has two GPIO and two timers to control 2 DC motors.
CAN bus is used to communicate with BBB board.

4. Power Supply
+12VDC -> +6.0VDC for Servo
+12VDC -> +5.0VDC for CAN Bus and BBB board
+12VDC -> +3.3VDC for eZ430

5. Motor control
H-Bridge
PWM
Direction
Rear wheel drive

6. Servo control
PWM
Position

7. CAN BUS

Robot System



1. Goal
This Robot system shall detect ball and net, kick ball to net, talk, listen and dance. 

2. Components
Arm: one arm which has 4 servos, that it is 4 free degree, can kick and grab ball.
Eye: one smart phone camera, with OpenCV, it can detect object and image recognition.
Leg: Two rear wheel drive.
Head: Smart phone - Nexus 5 + Arm9 + microcontroller

3. Communication
Wifi + CAN BUS
Three components need to communicate with each other. Smart phone will send ball and net position to BBB through WIFI at home router, BBB sends motors control command to eZ430 by industry CAN BUS. 

4. Design
The most difficult part is object detection at software point of view. At initial design, using a desk PC as image processing, but it will require an extra camera, in now days, smart phone is very powerful, cheaper and easy for programming, it is a very good idea to use smart phone as eye and I just have a Nexus 5.
To search ball and net, smart phone panning and tilting is a must, so two servos are needed, plus one arm has 4 servos, totally 6 servos are required.
Nexus 5 has many sensors which is very useful for speed, direction and position control and feedback.
And it contains voice recognition and speech on text. With it, the robot can listen command and talk, singing, etc.
BeagleBone Black board has one ARM9 CPU which running Linux OS, it has 6 timers, WIFI, CAN BUS, everything. And very important, it is cheap--only $45 when I bought it, now price is up to $55.
eZ430 is TI small board which has one microcontroller, it is used to control H-Bridge two motors for rear wheel drive. With two motors, the robot can move forward, backward, tune left and right. 
Arm has 4 servos, so it can kick and grab ball. To reduce cost, only one arm is installed.<br>
Single +12VDC power input, output +3.3VDC, +5.0VDC, +6.0VDC and +12VDC. +6.0VDC is for servos, +12VDC is for two motors. +3.3VDC and +5.0VD is for controllers.