Robo-Creator Training sheet

Page 1

Robo-Creator ฉบับ AT-BOT


รายละเอียดการอบรม 9.00-10.00

10.00-11.00 11.00-12.00 12.00-13.00 13.00-14.00

14.00-15.00 15.00-16.30

แนะนาให้ ร้ ูจักหุ่นยนต์ Robo-Creator แนะนาซอฟต์ แวร์ Wiring การติดตัง้ ซอฟต์ แวร์ ขัน้ ตอนการดาวน์ โหลดโปรแกรมไปยังหุ่นยนต์ การแสดงผลข้ อมูลที่หน้ าจอ LCD การสร้ างเสียงออกลาโพง การใช้ งานสวิตช์ กดและตัวต้ านทานปรับค่ าได้ พักกลางวัน การขับเคลื่อนหุ่นยนต์ เบือ้ งต้ น เดินหน้ า ถอยหลัง เลีย้ วซ้ าย เลีย้ วขวา เขียนโปรแกรมให้ ห่ ุนยนต์ เดินวนเป็ นรูปสี่เหลี่ยม การใช้ งานเซนเซอร์ สวิตช์ การควบคุมหุ่นยนต์ ด้วยเซนเซอร์ สวิตช์ การใช้ งานเซนเซอร์ ตรวจจับการสะท้ อน การเคลื่อนที่ตามเส้ นอย่ างง่ าย การเคลื่อนที่ตามเส้ นแบบตรวจสอบทางแยก


Robot-Mindmap


แผงวงจรหลัก บอร์ด ATX


1) ขับเคลื่อนด้วยมอเตอร์ไฟตรงที่มีชุดเฟื องทดอัตรา 48:1 ทัง้ 4 ล้อ


2) ต่ อมอเตอร์ ไฟตรง 6 ตัว

1

2 3 4 5

6


3) ขับเซอร์โวมอเตอร์ได้สูงสุด 6 ตัว


4) ล้อขับเคลื่อนเป็ นแบบล้อยางมีปมุ่


4) จุดต่อเซนเซอร์อะนาลอกและดิจิตอล I2C สื่อสารอนุกรม


5) กาเนิดเสียงผ่านลาโพงเปี ยโซ

ลาโพงเปี ยโซ


สรุป


การนาบอร์ดประยุกต์ใช้งาน


ติ ดตัง้ Gripper ด้านหน้ า


ติ ดตัง้ เซนเซอร์เพื่อเคลื่อนที่ตามเส้น


ติ ดตัง้ เซนเซอร์เพื่อตรวจจับการชน


ติ ดตัง้ เซนเซอร์วดั ระยะทางเพื่อค้นหาเส้นทาง


ปรับเปลี่ยนโครงสร้างเป็ นล้อสายพาน


เปลี่ยนล้อขับเคลื่อนเป็ นเซอร์โวมอเตอร์แบบหมุนได้รอบตัว


เปลี่ยนล้อขับเคลื่อนเป็ นล้อแบบ Omni เคลื่อนที่ได้หลายทิศทาง


เปลี่ยนการขับเคลื่อนเป็ นแบบขา โดยใช้เซอร์โวมอเตอร์ 3 ตัว


รูปทรงมาตรฐานที่ใช้ในการอบรม


รายละเอียดบนตัวบอร์ ด ATX


ซอฟต์แวร์สาหรับเขียนโปรแกรม

ทาอะไรได้ บ้าง

http://wiring.org.co


ติดตัง้ ซอฟต์ แวร์

ดับเบิล้ คลิกเพื่อติดตัง้


ขัน้ ตอนการติดตัง้

ติดตัง้ Wiring และไดรเวอร์ ของ USB


ทดสอบเปิ ดโปรแกรม Wiring

ชุดพัฒนาโปรแกรมภาษา C/C++ สาหรับไมโครคอนโทรลเลอร์ AVR แบบ Open Source ชื่อ Wiring สามารถนามาใช้ งานได้ โดยไม่ มีค่าใช้ จ่าย


ใส่ ถ่านขนาด AA 5 ก้ อน

ถ่ านชาร์ จหรื ออัลคาไลน์


เชื่อมต่อสาย USB กับคอมพิวเตอร์และ AT-BOT


ตรวจสอบพอร์ตอนุกรมของคอมพิวเตอร์

แสดงข้อความพบฮาร์ดแวร์ใหม่และพร้อมใช้

คลิ กเมาส์ขวา เลือก Properties

Device Manager


ตรวจสอบพอร์ตอนุกรมของคอมพิวเตอร์


กาหนดค่าที่โปรแกรม Wirring ให้ตรงกัน


กาหนดชื่อของบอร์ดเป็ น Robo-Creator R1


ทดลองเขียนโปรแกรมตามตัวอย่าง


คอมไพล์โปรแกรมที่เขียน ปุ่ มคอมไพล์ คียล์ ดั Ctrl+R

โปรแกรมแจ้งว่าไม่มี ERROR


เตรียมหุ่นยนต์เข้าสู่โหมดอัพโหลด


อัพโหลดโปรแกรม คียล์ ดั Ctrl+U กดปุ่ มเพื่ออัพโหลด


ผลลัพธ์ หน้ าจอแสดงข้อความ


ไลบรารี่สาหรับหุ่นยนต์ AT-BOT

เมื่อเรียก atx.h จะเรียกไลบรารี่เหล่านี้ #include <motor.h> #include <sleep.h> #include <in_out.h> #include <lcd.h> #include <analog.h> #include <servoMotor.h> #include <sound.h> #include <serial.h>

ขับมอเตอร์ หน่ วงเวลา อินพุตเอาต์พตุ ดิจิตอล ติดต่อจอ LCD อ่านค่าจากเซนเซอร์ ใช้งานเซอร์โวมอเตอร์ กาเนิดเสียง สื่อสารอนุกรม


รูปแบบการเขียนโปรแกรม #include <atx.h> void setup() { } void loop() { } atx.h คือไลบรารีหลักในการพัฒนาหุ่นยนต์ AT-BOT setup คือฟังก์ชนที ั ่ ่จะทางานเพียงครังเดี ้ ยวหลังจากโปรแกรมเริ่มทางาน loop คือฟังก์ชนที ั ่ ่จะทางานวนซา้ ต่อเนื่ อง โดยจะเริ่มทางานหลังจากทางาน ในฟังก์ชนั ่ setup เสร็จ


รูปแบบการแสดงผลที่หน้ าจอ LCD

แสดงผลตัว 16 ตัวอักษร 2 บรรทัด


ไลบรารี่ควบคุมการแสดงผลที่โมดูล LCD รู ปแบบฟั งก์ ชัน void lcd(char *p,…);

พารามิเตอร์ p ใช้ กาหนดรู ปแบบการแสดงผลที่โมดูล LCD โดยสามารถ กาหนดรู ปแบบการแทรกสัญลักษณ์ พเิ ศษเพื่อร่ วมแสดงผลค่ า ข้ อมูลตัวเลขชนิดต่ างๆได้


ตัวอย่างที่ 1 #include <atx.h> void setup() { lcd("Hello AT-BOT"); }

void loop() { }


ตัวอย่างที่ 2 #include <atx.h> void setup() { lcd("abcdefghijklmnopqrstuvwxyz"); } void loop() { }

เมื่อตัวอักขระติดกันเกิน 16 ตัวอักษร จะตัดขึน้ บรรทัดใหม่ให้


คาสังพ ่ ิ เศษ รหัสบังคับ %d หรือ %D %f หรือ %F #c #n

การทางาน แสดงผลตัวเลขช่ วง -32 32,,768 ถึง +32 32,,767 แสดงผลตัวเลขจานวนจริงทศนิยม 3 หลัก เคลียร์ หน้ าจอ นาข้ อความแสดงที่บรรทัดที่ 2


ตัวอย่างที่ 3 #include <atx.h> int x=158; ก าหนดค่ า ตั ว แปร void setup() { lcd("Value: %d ",x); } void loop() {

}

การนาค่าตัวเลขมาแสดง โดยเริ่มต้นอยู่ในรูปแบบของตัวแปร


ตัวอย่างที่ 4 #include <atx.h> int i=0; void setup() { ตัวแปร } void loop() { lcd("Count: %d ",i); sleep(1000); i++; เพิ่มค่าตัวแปรขึน้ ทีละ 1 }

โปรแกรมนับค่ าเพิ่มขึน้ ทีละ 1ทุกๆ 1 วินาที


ตัวอย่างที่ 5 #include <atx.h> void setup() { } void loop() { lcd("Sawaddee#nThailand"); }

อักขระพิเศษ แสดงตัวอักษร “Thailand” ในบรรทัดที่ 2


สร้างเสียงออกลาโพงเปี ยโซ

ลาโพงเปี ยโซ


ไลบรารี่ Sound สาหรับกาเนิดเสียง ฟั งก์ ช่ ัน beep()

กาเนิดเสียง 500 Hz นาน 0.1 วินาที

void beep(void);

ฟั งก์ ช่ ัน sound () กาเนิดเสียงตามความถี่และเวลาที่กาหนด void sound(int freq,int time);

โดย

freq time

คือค่ าความถี่เสียง ช่ วงเวลาหน่ วยมิ ยมิลลิวินาที


ตัวอย่างที่ 6 #include <atx.h> void setup() { } void loop() { beep(); sleep(1000); }

สร้ างเสียงบี๊ปทุกๆ 1 วินาที

ส่งเสียง


ตัวอย่างที่ 7 #include <atx.h> void setup() { } void loop() { sound(1200,500); sleep(1000); }

เสียงความถี่ 1200 Hz ดังนาน 0.5 วินาที

สร้ างสัญญาณเสียงความถี่ 1200 Hz ดังนาน 0.5 วินาที โดยเว้ น ห้ วงทุกๆ 1 วินาที


ทดสอบใช้สวิตช์บนตัวบอร์ด ATX

SW1

SW2


ไลบรารี่ in_out กับฟังก์ชนั ตรวจสอบสถานะการกดสวิตช์ sw1 sw 1 ตรวจสอบการ ตรวจสอบการกดสวิ กดสวิตช์ SW SW11

sw2 sw 2 ตรวจสอบการ ตรวจสอบการกดสวิ กดสวิตช์ SW SW22

รู ปแบบ char sw sw1 1(void); char sw sw2 2(void);

การคืนค่ า เมื่อสวิตช์ ถูกกดจะคืนค่ าเป็ น 0 แต่ ถ้าไม่ ถูกกด จะคืนค่ าเป็ น 1


ไลบรารี่ in_out กับฟังก์ชนั รอจนกว่ากดสวิตช์ sw1 sw 1_press : รอจนกระทั่งมีการกดสวิตช์ SW SW11

sw2 sw 2_press : รอจนกระทั่งมีการกดสวิตช์ SW SW22

รู ปแบบ void sw sw1 1_press(void); void sw sw2 2_press(void _press(void); );

จะเป็ นการรอที่บรรทัดนีไ้ ปจนกว่ าจะมีการกดสวิตช์ จึงกระโดดไปทา บรรทัดถัดไป


ตัวอย่างที่ 8 #include <atx.h> int i=0; void setup(){ sw1_press(); } void loop(){ lcd("Count: %d ",i); sleep(1000); i++; }

ต้ องกดสวิตช์ SW1 จอ LCD จึงค่ อยเริ่มนับ


ตัวอย่างที่ 9 #include <atx.h> int i=10; void setup(){} void loop(){ lcd("Count: %d ",i); if(sw1()==0){ i++; sleep(200); } if(sw2()==0){ i--; sleep(200); } }

เพิ่มค่ าเมื่อกด SW1 ลดค่ าเมื่อกด SW2


ทดสอบใช้ KNOB (ตัวต้านทานปรับค่าได้)

KNOB


ไลบรารี่ analog กับฟังก์ชนั knob เพื่ออ่านค่า 0-1023 รู ปแบบ unsigned int knob();

การคืนค่ า

คืนค่ าข้ อมูลจากการหมุน 0-1023 ซ้ ายสุด = 0 ขวาสุด = 1023


ตัวอย่างที่ 10 #include <atx.h> void setup() { } void loop() { lcd("KNOB: %d sleep(100); }

",knob());

นาค่ าที่ปรั บแสดงผลที่หน้ าจอ LCD


ตัวอย่างที่ 11 หมุน Knob ด้านซ้ายนับลง , ขวานับขึ้น #include <atx.h> int i=100; // ค่าเริม่ ต้น int k; void setup(){} void loop(){ lcd("Count: %d ",i); k = knob(); if(k>512){ i++; lcd("#nCount Up "); } else{ i--; lcd("#nCount Down "); } sleep(1000); }


0-100 ค่า i นับขึน้ 101--300 ค่า i นับขึน้ เร็วสองเท่า 101

301--500 ค่า i หยุดอยูก่ บั ที่ 301 501--700 ค่า i นับลง 501 701--1023 ค่า i นับลงเร็ 701 ลงเร็วสองเท่า


#include <atx.h> int i=100; // ค่าเริ่ มต้น int k; void setup(){} void loop(){ k = knob(); lcd("Count: %d #nKnob=%d",i,k); if(k<100){ i++; sleep(500); } else if(k>100 && k<300){ i++; sleep(250); } else if(k>300 && k<500){ sleep(200); } else if (k>500&& k<700){ i--; sleep(500); } else{ i--; sleep(250); } }


ขับมอเตอร์ไฟตรง ช่ องของมอเตอร์ 0 1

2 3 4

5


ไลบรารี่ motor สาหรับฟังก์ชนควบคุ ั่ มมอเตอร์ ฟังก์ชนั ่ motor

รู ปแบบ void motor(char ch,int pow)

โดย ch บอกตาแหน่ งของมอเตอร์ ตั้งแต่ 0-5 pow ใช้ กาหนดกาลังขับมีค่า -100 ถึง 100 ค่ าบวกทิศทางเดินหน้ า ค่ าลบทิศทางถอยหลัง


ฟังก์ชนั motor_stop() หยุดมอเตอร์ รู ปแบบ void motor_stop(char ch)

โดย ch บอกตาแหน่ งของมอเตอร์ ตั้งแต่ 0-5 หรือ ALL ใช้ ALL ถ้ าต้ องการหยุดมอเตอร์ ทุกตัวพร้ อมกัน ใช้ ao() เป็ นตัวย่ อแทน motor_stop(ALL) ได้


เสียบสายมอเตอร์ โดยอ้างอิงทิศทางดังนี้

Motor0

Motor3

Motor1

Motor2

หมุนล้อไปหน้ า ไฟติดสีเขียว

หมุนล้อถอยหน้ า ไฟติดสีแดง


ตัวอย่างที่ 12 ทดสอบขับมอเตอร์อย่างง่าย #include <atx.h> void setup() { lcd(“SW1 Press!”); sw1_press(); } void loop() { motor(0,70); motor(1,70); motor(2,70); motor(3,70); sleep(3000); motor_stop(ALL); sleep(2000); }

หุ่นยนต์ไปข้างหน้ า 3 วินาทีและหยุดนิ่ง 2 วินาทีสลับกัน


ตัวอย่างที่ 13 เคลื่อนที่ไปและกลับ #include <atx.h> void setup(){} void loop() { motor(0,70); motor(1,70); motor(2,70); motor(3,70); sleep(3000);

}

motor(0,-70); motor(1,-70); motor(2,-70); motor(3,-70); sleep(3000);

การเคลื่อนที่ไปและกลับ


หลักการขับเคลื่อนหุ่นยนต์ เบือ้ งต้ น และ การสร้ างฟั งก์ ช่ นั ขับเคลื่อนหุ่นยนต์


ฟังก์ชนั ่ forward เคลื่อนที่ไปหน้ า void FD(unsigned int speed) { motor(0,speed); motor(1,speed); motor(2,speed); motor(3,speed); }


ฟังก์ชนั ่ backward เคลื่อนที่ถอยหลัง void BK(unsigned int speed) { motor(0,-speed); motor(1,-speed); motor(2,-speed); motor(3,-speed); }


ฟังก์ชนั ่ spin_right เลี้ยวขวา void SR(unsigned int speed) { motor(0,speed); motor(1,speed); motor(2,-speed); motor(3,-speed); }


ฟังก์ชนั ่ spin_left เลี้ยวซ้าย void SL(unsigned int speed) { motor(0,-speed); motor(1,-speed); motor(2,speed); motor(3,speed); }


ฟังก์ชนหยุ ั ่ ดขับเคลื่อนให้ใช้ ao() ao();

Motor_stop(ALL);

มอเตอร์ทงั ้ 4 ตัวหยุดทางานพร้อมกัน


ทดสอบให้ห่นุ ยนต์เดินวนเป็ นรูปสี่เหลี่ยม


ทดสอบหุ่นยนต์เดินเป็ นวงกลม


ฟังก์ชนั ่ forward เคลื่อนที่ไปหน้ า แบบ 2 Speed void FD2(unsigned int speed1,unsigned int speed2)

{ motor(0,speed1); motor(1,speed1); motor(2,speed2); motor(3,speed2); }


ฟังก์ชนั ่ backward เคลื่อนที่ถอยหลัง แบบ 2 Speed void BK2(unsigned int speed1,unsigned int speed2) { motor(0,-speed1); motor(1,-speed1); motor(2,-speed2); motor(3,-speed2); }


ZX-SWITCH สวิตช์กด

เมื่อกดอ่านค่าได้เป็ น “0” เมื่อไม่กดอ่านค่าได้เป็ น “1”


ฟังก์ชนั in สาหรับการอ่านค่าสวิตช์ (ดิจิตอล) รู ปแบบ char in(char _bit);

โดย _bit ใช้ กาหนดช่ องที่ต้ต้องการติดต่ อ การคืนค่ า ฟั งก์ ช่ ันจะทาการคืนค่ าสถานะของช่ อง มีค่าเป็ น 0 หรื อ 1 เท่ านัน้


ตัวอย่างที่ 14 กดสวิตช์ควบคุมมอเตอร์ ต่อสวิตช์เข้าช่อง 40


ตัวอย่างที่ 14 กดสวิตช์ควบคุมมอเตอร์ #include <atx.h> void setup(){} void loop(){ if (in(40)==0){ SL(60); } else{ ao(); } }


ต่อสวิตช์เข้ากับช่อง 40 และ 41


ตัวอย่างที่ 15 รถบังคับจากสวิตช์ 2 ตัว #include <atx.h> void setup(){} void loop(){ if(in(40)==0&&in(41)==0){ FD(60); } else if (in(40)==0){ SL(60); } else if(in(41)==0){ SR(60); } else { ao(); หมายเหตุ ต้ องแทรกฟั งก์ ชันขับ } มอเตอร์ ไว้ ก่อนหน้ านี ้ }


หลบหลีกสิ่งกีดขวางจากการชนสวิตช์

ต่อสวิตช์เข้าที่ด้านหน้ าของหุ่นยนต์ในตาแหน่ งดังรูป


โมดูล GP2D120

ทางานที่ไฟเลีย้ ง 5 โวลต์ วัดระยะทางใช่วงตัง้ แต่ 4 ถึง 32 เซนติเมตร


โมดูล GP2D120


ไลบรารี่ gp2d120_lib ฟังก์ชนั ่ getdist : อ่านค่าระยะทางจาก GP2D120 ซึ่ง 4 ถึง 32 เซนติเมตร

รูปแบบ unsigned int getdist(char adc_ch) โดย adc_ch ใช้กาหนดขาพอร์ต 0 ถึง 6 จาก ADC0 ถึง ADC6 ตามลาดับ การคืนค่า คืนค่าข้อมูลระยะทางในหน่ วยเซนติเมตร


ต่อ GP2D120 เข้าช่อง ADC3


ตัวอย่างที่ 16 อ่านค่าจาก GP2D120 โชว์ที่หน้ าจอ LCD #include <atx.h> #include <gp2d120_lib.h> unsigned int dist; void setup(){} void loop(){ dist = getdist(3); if(dist>=4 && dist<=32){ lcd("Distance: %d cm ",dist); } else{ lcd("Out of Range!"); } sleep(100); }


หุ่นยนต์หลบหลีกสิ่งกีดขวางด้วย GP2D120

ติดตัง้ เซนเซอร์ ด้านหน้ าหุ่นยนต์


ตัวอย่างที่ 17 หุ่นยนต์ หลบหลีกสิ่ งกีดขวางด้ วย GP2D120 #include <atx.h> #include <gp2d120_lib.h> unsigned int dist; void setup(){ lcd("SW1 Press!");sw1_press(); } void loop(){ dist = getdist(3); if(dist>=4 && dist<15){ BK(80);sleep(500); SL(80);sleep(500); } else { FD(80); } }


แผงวงจรตรวจจับการสะท้อน ZX-03R


ผลการสะท้อนแสง


ไลบรารี่ analog ฟังก์ชนั ่ analog สาหรับอ่านค่าจากเซนเซอร์อะนาลอก

รูปแบบ unsigned char analog(unsigned char channel);

โดย channel ใช้กาหนดขาพอร์ต 0 ถึง 6 จาก ADC0 ถึง ADC6 การคืนค่า คืนค่ าข้ อมูลที่ตงั ้ แต่ 0 ถึง 1023 (ค่ าความละเอียด 10 บิต)


ติดตัง้ เซนเซอร์ด้านล่างตัวหุ่นยนต์ ดังรูป


ทดสอบอ่านค่าพื้นผิวสีขาวและดา ประมาณ 800-1000

ประมาณ 100-200


นาค่าที่ได้มาหาค่ากึ่งกลาง

สีดาอ่ านได้ ประมาณ 200 สีขาวอ่ านได้ ประมาณ 800 ดังนั้น ค่ าเฉลี่ยในการเปรี ยบเทียบ (200+800)/2 = 500


เซนเซอร์สองตัวคร่อมอยู่บนเส้น

1

if(L ขาว&& R ขาว){ FD(); } L

R


เซนเซอร์ซ้ายพบเส้น

2

if(L ดา&& R ขาว){ SL(); } L

R


เซนเซอร์ขวาพบเส้น

3

if(L ขาว&& R ดา){ SR(); }


เซนเซอร์สองตัวเจอสีดา

4

if(L ดา&& R ดา){ FD(); } L

R


สนามรูปแบบที่ 1


ตัวอย่างที่ 18 เคลื่อนที่ตามเส้ นอย่ างง่ ายที่สุด #include <atx.h> int L,R; void setup(){ lcd("Press Start"); sw1_press(); } void loop() { L=analog(4);R=analog(6); if(L>500&&R>500){ FD(60); } else if(L<500){ SL(60); } else if(R<500){ SR(60); } }


สนามรูปแบบที่ 2 เพิ่มเส้นตัด (ให้เดินตรง)


ตัวอย่างที่ 19 เจอเส้นตัดส่งเสียงออกลาโพง #include <atx.h> int L,R; void setup(){ lcd("Press Start"); sw1_press(); } void loop() { L=analog(4);R=analog(6); if (L<500&&R<500){ FD(60); sound(1200,500); } else if(L>500&&R>500){ FD(60); } else if(L<500){ SL(60); } else if(R<500){ SR(60); } }


สนามรูปแบบที่ 3 เจอเส้นตัดเลี้ยวขวา


สร้างฟังก์ชนั L90() เพื่อการเลีย้ วที่แม่นยา

ตรวจพบทางแยก

เดินเลยไปก่อน

หมุนตัวจน เซนเซอร์ซ้าย เจอเส้น


สร้างฟังก์ชนั L90() เพื่อการเลีย้ วที่แม่นยา

หมุนต่อจน หลุดเส้นดา

หลุดเส้นดา

เดินตรงต่อไป


ตัวอย่างที่ 20 ฟังก์ชนั เลี้ยวซ้าย 90 องศา void L90(){ FD(60); sound(1500,100); while(analog(4)>500){ SL(60); } while(analog(4)<500){ SL(60); } }


ตัวอย่างที่ 21 ฟังก์ชนั เลี้ยวขวา 90 องศา void R90(){ FD(60); sound(1500,100); while(analog(6)>500){ SR(60); } while(analog(6)<500){ SR(60); } }


สนามรูปแบบที่ 4 แยกที่ 3 เลี้ยวขวา

5

4

3

2

1

6


ตัวอย่างที่ 22 แยกที่ 3 เลี้ยวขวา int L,R,x=0; void R90(){ FD(60); sound(1500,100); while(analog(1)>500) { SR(60); } while(analog(1)<500) { SR(60); } } void L90(){ FD(60); sound(1500,100); while(analog(0)>500) { SL(60); } while(analog(0)<500) { SL(60); } } void setup(){ lcd("Press Start");sw1_press(); } void loop(){ L=analog(0); R=analog(1); if (L<500&&R<500){ if(x==6) { x=0; } x++; if (x==3) { R90(); } else { L90(); } } else if(L>500&&R>500) { FD(60); } else if(L<500) { SL(60); sleep(20); } else if(R<500) { SR(60); sleep(20); }


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.