当前位置: 首页 > news >正文

机器人制作开源方案 | 送餐机器人

作者:赖志彩、曹柳洲、王恩开、李雪儿、杨玉凯

单位:华北科技学院

指导老师:张伟杰、罗建国

一、作品简介

1. 场景调研

1.1项目目的

      近年来,全国多地疫情频发,且其传染性极高,食品接触是传播途径之一。疫情防控需要大量人员投入,常常出现人力紧张的情况,物资配送已经成为一大焦点问题。当前尚未有专门用于疫情送餐的机器人,因此开发一款自动化、智能化的送餐机器人,减少人员之间的接触,不仅可以提高工作效率、减轻人工劳动强度,而且可以有效减少交叉感染。

      在高校校园,学生外卖配送非常常见,但校门口琳琅满目的外卖往往被摊放在路边,甚至占用道路,造成交通混乱,因此急需一款高效便捷的送餐机器人来缓解这种情况。下图为校园人工送餐场景及外卖摊放情况。

疫情下校园送餐场景、学生点外卖场景

1.2市场调研

      我国送餐机器人行业发展起步较晚,大致经历了探索、起步、成长、爆发四个阶段。目前餐厅机器人距离真正意义上的智能化还存在技术门槛,在公共餐厅这种应用场景中,常规性的送餐、配菜需求机器人基本可以满足,但是功能比较单一。2020年疫情爆发之后,人们对于送餐机器人的需求很快上升,市场认可度不断上升,我国送餐机器人行业进入高速增长期,现在国内外疫情依然严重,送餐机器人的市场会还将不断提升扩大。

1.3项目意义

      减少人与人之间的接触是防止疫情扩散的有效手段,用机器人代替人工送餐,不仅可以代替耗时耗力的流程化作业,而且还可以避免工作人员在送餐过程中被感染的可能。而送餐机器人可以满足无接触送餐问题。

      送餐机器人开启了餐饮经营新模式,相较于传统的送餐方式,送餐机器人在疫情下减少人员接触,大大降低新冠传播率,提高食物配送效率,同时也可缓解因外卖造成的交通压力;送餐机器人对于餐厅价值有了很大的自主发挥空间,超越了传统餐饮消费的定义。

2. 创新点

2.1双工作模式

① 正常模式

      点餐者在与送餐机器人进行匹配的外卖App点餐后,送餐机器人到达指定地点,自助装取食物后,正常模式下灰度循迹传感器处于关闭状态,此时的机器人只基于终端路径来行进,利用超声波与红外避障对途中行人与障碍物避障,实现自助送餐。到达指定送餐地点后,当车身人体红外模块检测到点餐者接近时,解除安全锁定状态,装载食物的升降平台从保温箱中升起,点餐者取餐,完成一次送餐任务。

② 疫情模式

      在疫情爆发,学校处于静默期间时,送餐机器人可以通过灰度循迹传感器沿着工作人员设置的黑色送餐路径行走。送餐机器人利用超声波、红外避障等进行循迹与避障。到达指定送餐地点后,升降平台从保温装置升起食物,机械臂自动将食物放置在隔离人员房间门口,减少人员接触。

2.2高阻热保温箱

      采用质量轻、加工性好、致密度高、保温隔热效果好的聚氨酯泡沫包裹整个升降平台,达到阻热效果。保持食物原有温度,保证食物口感。

2.3数据实时显示

      机器人工作状态将在液晶显示屏右下角实时显示。小车底盘运行、机械臂与升降平台工作状态分别编号为1、2、3,正常工作状态分别为#,待机状态为*。与障碍物之间的距离间隔一秒在屏幕左下角显示。

      送餐信息实时显示在屏幕上方,时间为12:38时从A地向B地执行送餐任务,收餐者手机尾号为4404。送餐机器人在前方56厘米处有障碍物,底盘正在工作,机械臂与升降平台处于待机状态。送餐机器人整体工作正常,无异常情况出现(如下图所示)。

显示屏工作数据记录

3. 难点及解决方案

3.1转向不流畅且稳定性差

      原有机器人在循迹时因固定差速转弯时,难以适应不同转弯半径,常常因转弯半径过大导致左侧灰度传感器读取右侧灰度传感器或者右侧灰度传感器读取左侧灰度传感器,容易因为传感器数据冲突导致整体不断抖动。

      解决方案:在初步的代码基础上,利用蓝牙外加不断进行速度差调试,同时将实时速度差利用显示屏显示出来,找出最适宜的转向速度,在程序内部进行优化。并将车轮间距进行缩小,减小机器人转弯半径;在此基础之上,加入PID算法,使得速度差根据不同转弯半径不断自行调整差速。

3.2循迹时容易撞上前方或侧方障碍物

      解决方案:利用舵机搭载超声波模块,实现送餐机器人前方210度范围障碍物探测,同时每隔三秒将信号返回值(前方障碍物距离)显示在显示屏上,同时侧方和前方搭载红外避障模块,与超声波共同构成完善的避障系统。在避障程序的编译中,设置了两种代码,根据各模块运动情况实施精准避障,连续避障,合理在小车行进中添加各种采集点、定位点,实现各种不同程度的行走及障碍躲避。

      在机器人四周也加上了红外测距模块,将这些传感器与车身其他专用模块相结合,辅助机器小车在拾取点位更精准,寻迹运动更精确,对四周障碍物做出灵敏的避障。

3.3机械臂稳定性差

      原有机器人的四轴机械臂工作时因延展太长,工作时稳定性较差,容易抖动。

      解决方案:调整机械臂的结构,将原有机械臂两段式结构缩短至一段;并将驱动机械臂工作的四个舵机的偏移量设置为3,大大提高机械臂的稳定性。

3.4循迹稳定性较差

      由于对机器人的初期调试全部在室内完成,使得送餐机器人在室外工作时因光线因素造成灰度传感器的返回值产生误差。

      解决方案:通过多次对室内外机器人循迹时灰度传感器的返回值进行串口读取并记录,不断调整灰度传感的高度的间距,使其因光线差造成的返回值误差降到最低。

3.5机器人工作时重心靠前

      初期建模与组装时未考虑到机械臂工作时伸展及重量问题,导致机械臂工作时,机器人整体重心过于靠前,容易侧翻。

      解决方案:通过solidwork进行运动算例分析,调整机械臂的位置与高度并将车身适当加长(如下图所示)。

修改前后对比

4. 未来前景展望及应用

      与校园或外卖等进行合作试点,不断优化调整,尽快投入市场;改善应用方面,不再局限于送餐,增加功能通过搭载多频段红外传感器、热成像传感器、GPS定位系统等传感器,将校园及周边环境信息导入机器人信息库,辅以语音识别和检索系统,送餐机器人将在校园送餐方面为消费者提供更加个性化、智能化的服务。

送餐机器人整体图

 二、本体设计

 1. 机械结构

      首先利用solidwork建模软件开展机器人结构设计和建模,然后根据建模图样进行组装;在机构设计过程中为了保证机械结构设计合理,使其拥有更加强大的承载力、拥有更大的内部空间,本小组事先对重要机械零件(步进电机底座)进行了应力分析(如下图所示),通过不断对模型的改进和优化设计,最后得到了承载能力强且结构合理的模型。

零件应力分析

送餐机器人整体构造图

1.1底盘

      采用舵机转向、电机驱动的四轮组合结构。利用各种板块零件组合成三角稳定结构制作底盘。这种组合底盘具有稳固和灵敏两个特点:一是对路况的适应能力强,在各种复杂的路况下都可进行基本运动;二是底盘结构稳固灵敏,不限制舵机操控四轮转向位置,也为其它机械结构运转提供了充足空间。底盘及所用电机如下图所示:

送餐机器人底盘和电机

1.2机械臂

      机械臂抓取装置为四轴机械臂,抓取更加灵活,同时在机械爪端部搭配热塑性弹性橡胶,增大机械抓端部抓取餐盒时的摩擦力。

结构如下图所示:

送餐机器人机械臂装置

1.3升降平台

      用于放置餐盒(或餐包)的平台(如下图所示),利用步进电机控制其沿丝杆导轨的升降动作,机械臂将食物放置在平台上后将食物降落到保温装置内,当到达目的地后将食物从保温装置内升起,让机械臂抓取,对其要求是位置精准。

      保温装置布置在升降平台的四周,由聚氨酯泡沫包裹而成,其质量轻、可加工性好、致密度高、保温隔热效果的特点,对放入其中的食物起到保温功能。

送餐机器人升降平台与保温装置

1.4传感器与其它

      送餐机器人除车身主体与底盘外,还搭载超声波模块、红外避障模块、蓝牙模块、人体红外探测模块等多种传感器与模块,各模块与车身之间有防护板材,并进行多重加固,增强了车身的稳定性。

2. 电路控制与设备调试

2.1循迹避障

      循迹避障功能需要用超声波模块、灰度传感器、近红外传感器三者共同作用实现。

如下图所示:

超声波测距模块
红外避障模块
灰度模块

      在舵机的驱动下,超声波模块实现对车头前210度范围进行实时探测,将前方障碍物距离传给单片机,再通过内部蚁群规划算法,规划出合理的避障路线。

      当灰度传感器未识别黑线返回值为0,识别黑线后返回值为1,将返回值传回机器人内部程序,并进行判断。送餐机器人搭载四个灰度传感器,当返回值为0000,机器人前进;只要有一个传感器返回值为1时,通过PID算法对直流电机转速进行调整,控制机器左右转进而实现循迹功能。

      车头与车身两侧搭载了近红外传感器,当监测到机器附近有人通过或存在障碍物,则返回值为0,控制送餐机器人停车。

      红外探测模块探测范围为10cm,超声波模块探测距离为3m-7m。

2.2警示装置

      警示装置由蜂鸣器、车灯、显示屏三部分构成。

      送餐机器人正常工作时,显示屏显示“正常工作”字样,车头指示灯显示绿色;当超声波传感器测到障碍物距离值<50cm时,显示屏显示“行人请注意”字样,同时蜂鸣器间隔性发出“滴滴”声,车前指示灯进行闪烁,提醒路人进行避让;若距离值<16cm时,车灯加快闪烁,蜂鸣器持续发出“滴滴”声,最大程度提醒行人注意避让;当送餐机器人左右转向时,对应方向指示灯也会闪烁;运行停止时,车灯均变为红色;机械臂与升降平台旁分别接一个工作指示灯,配合显示屏使用,工作状态下显示为绿色,待机状态下为红色。

      所用蜂鸣器和指示灯如下图所示:

蜂鸣器模块
工作指示灯

2.3机械臂的运动控制

      机械臂的运动包括旋转、上下移动、机械爪的张合。

      为了实现机械臂的精准夹取与放置,使用了五个舵机控制。底部舵机控制机械臂的左右旋转,中间三个舵机控制机械臂上下移动,末端舵机控制机械爪的张合(如下图所示)。在程序中设定偏移量为3度,即舵机每次以3度转动,减少了机械臂因为惯性所产生的误差,保证了机械臂的平稳运行,使精确性大大提高。

机械臂舵机位置与运动方向

2.4升降平台的控制

      步进电机通过动力传输零件驱动丝杠旋转,丝杠带动平台上的螺母移动,移动过程中通过平台上的卡扣限制平台只能沿上下移动,进而实现平台的升降功能。

      卡扣装置与平台结构如下图所示:

升降平台卡扣装置
升降平台装置

2.5人体红外感应

      送餐机器人到达指定地点后,通过人体红外检测模块,检测人体后返回值为1,升降平台开始运行。将送餐机器人携带的人体红外感应模块设置为可重复模式,并且探测范围设定为3米内,只要在探测范围内取餐者在活动,其信号返回值始终为1。

人体红外探测传感器

2.6蓝牙无线通讯

      基于蓝牙HC-05模块以及NRF905无线收发模块(如下图所示)实现送餐机器人的远距离通讯与控制。当遇到通过的障碍时,通过终端对机器人输入指令,控制机器人运行。

HC-05 蓝牙模块与NRF905模块

三、程序代码

1. 示例程序

① 显示屏代码:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C mylcd(0x27,16,2);byte d[]={0B00000,0B00000,0B11011,0B11011,0B00000,0B11011,0B11011,0B00000};
byte a[]={0B00000,0B00100,0B01000,0B11111,0B11111,0B01000,0B00100,0B00000};
byte b[]={0B00000,0B00000,0B00000,0B11111,0B11111,0B00000,0B00000,0B00000};
byte c[]={0B00000,0B00100,0B00010,0B11111,0B11111,0B00010,0B00100,0B00000};
byte g[]={0B00000,0B11111,0B00100,0B00100,0B00100,0B00100,0B11111,0B00000};
byte h[]={0B00000,0B01010,0B10111,0B01010,0B01011,0B01010,0B01011,0B01010};
byte e[]={0B00000,0B11111,0B00010,0B01011,0B01010,0B01010,0B11111,0B00000};
byte f[]={0B00100,0B01110,0B11111,0B01110,0B01110,0B11111,0B10101,0B00100};void setup(){mylcd.init();mylcd.backlight();mylcd.createchar(1, d);mylcd.createchar(2, a);mylcd.createchar(3, b);mylcd.createchar(4, c);mylcd.createchar(5, g);mylcd.createchar(6, h);mylcd.createchar(7, e);mylcd.createchar(0, f);
}void loop(){mylcd.setCursor(1-1, 1-1);mylcd.print("1");mylcd.setCursor(2-1, 1-1);mylcd.print("2");mylcd.setCursor(3-1, 1-1);mylcd.write(1);mylcd.setCursor(4-1, 1-1);mylcd.print("3");mylcd.setCursor(5-1, 1-1);mylcd.print("8");mylcd.setCursor(7-1, 1-1);mylcd.print("A");mylcd.setCursor(8-1, 1-1);mylcd.write(2);mylcd.setCursor(9-1, 1-1);mylcd.write(3);mylcd.setCursor(10-1, 1-1);mylcd.write(4);mylcd.setCursor(11-1, 1-1);mylcd.print("B");mylcd.setCursor(13-1, 1-1);mylcd.print("4");mylcd.setCursor(14-1, 1-1);mylcd.print("4");mylcd.setCursor(15-1, 1-1);mylcd.print("0");mylcd.setCursor(16-1, 1-1);mylcd.print("4");mylcd.setCursor(1-1, 2-1);mylcd.print("5");mylcd.setCursor(2-1, 2-1);mylcd.print("6");mylcd.setCursor(3-1, 2-1);mylcd.print("c");mylcd.setCursor(4-1, 2-1);mylcd.print("m");mylcd.setCursor(6-1, 2-1);mylcd.write(5);mylcd.setCursor(7-1, 2-1);mylcd.write(6);mylcd.setCursor(8-1, 2-1);mylcd.write(7);mylcd.setCursor(9-1, 2-1);mylcd.write(0);mylcd.setCursor(11-1, 2-1);mylcd.print("1");mylcd.setCursor(12-1, 2-1);mylcd.print("√");mylcd.setCursor(13-1, 2-1);mylcd.print("2");mylcd.setCursor(14-1, 2-1);mylcd.print("#");mylcd.setCursor(15-1, 2-1);mylcd.print("3");mylcd.setCursor(16-1, 2-1);mylcd.print("x");
}

② 底座代码:

#include<SoftwareSerial.h>
SoftwareSerial LZC(A5,A4);
int a=80;
int b=220;
int c=250;
int d=220;
int e=250;
void chaoshengbo();
int i=0;
void setup() {Serial.begin(9600);pinMode(7, INPUT);pinMode(8, INPUT);pinMode(3, INPUT);pinMode(4, INPUT);pinMode(A5, OUTPUT);pinMode(A4, OUTPUT);//右灯pinMode(2, OUTPUT);pinMode(A3, OUTPUT);//左灯
}
void loop() {xunji();  
}
//封装小车前进动作子程序
void Forward() {analogWrite(5, 0);analogWrite(6, a);   //5   6左前     6前       analogWrite(9, 0);  analogWrite(10, a);//9   10右前 v    10前green();
}
//封装小车后退动作子程序
void Backward() {analogWrite(5, a);   //analogWrite(6, 0);analogWrite(9, a);   //analogWrite(10, 0);green();
}//封装小车停止动作子程序
void Stop() {analogWrite(5, 0);   //右轮后退analogWrite(6, 0);analogWrite(9, 0);   //左轮后退analogWrite(10, 0);red();
}//封装小车自转动作子程序
void turn_Left() {analogWrite(5, d);  analogWrite(6, 0);analogWrite(9, 0);  analogWrite(10, b);green();
}//封装小车自转动作子程序
void turn_Right() {analogWrite(5, 0);  analogWrite(6, b);analogWrite(9, d);  analogWrite(10, 0);green();
}//封装小车大半径右转子程序
void turn_Right_1() {analogWrite(5, 0);  analogWrite(6, c);analogWrite(9, e);  analogWrite(10, 0);green();
}//封装小车大半径左转子程序
void turn_Left_1() {analogWrite(5, e);  analogWrite(6, 0);analogWrite(9, 0);  analogWrite(10, c);green();
}void xunji() {int num1, num2, num3, num4;num1 = digitalRead(11);num2 = digitalRead(8);num3 = digitalRead(3);num4 = digitalRead(4);delay(5);//1111   0000    1011   1101     if (num1 == 1 && num2 == 1 && num3 == 1 && num4 == 1) {   //1111Forward();delay(5);}else if (num1 == 1 && num2 == 0 && num3 == 1 && num4 == 1 ) {turn_Left();delay(5);}else if (num1 == 1 && num2 == 1 && num3 == 0 && num4 == 1 ) {turn_Right();delay(5);}else if (num1 == 0 && num2 == 1 && num3 == 1 && num4 == 1 ) {turn_Left_1();delay(5);}else if (num1 == 1 && num2 == 1 && num3 == 1 && num4 == 0 ) {turn_Right_1();delay(5);}else if (num1 == 0 && num2 == 0 && num3 == 1 && num4 == 1 ) {turn_Left_1();delay(30);}else if (num1 == 1 && num2 == 1 && num3 == 0 && num4 == 0 ) {turn_Right_1();delay(5);}else if (num1 == 0 && num2 == 0 && num3 == 0 && num4 == 0) {    //0000Stop();}}
void red()
{digitalWrite( A5 , HIGH );digitalWrite( A4, LOW );digitalWrite( A3, LOW );digitalWrite( 2 , HIGH );
}
void green()
{digitalWrite( A5 , LOW );digitalWrite( A4 , HIGH );digitalWrite( A3 , LOW );digitalWrite( 2 , HIGH );
}

③ 机械臂代码:

#include<SoftwareSerial.h>
SoftwareSerial LZC(A5,A4);
#include <Servo.h>
#include <AccelStepper.h>  // 定义电机控制用常量
const int enablePin = 8;   // 使能控制引脚
const int zdirPin = 5;     // z方向控制引脚
const int zstepPin = 2;    // z步进控制引脚
int trigPin = A0;    //Trig
int echoPin = A1;    //Echo
long duration, cm=0, inches;
const int STEPS_PER_REV = 2800;
AccelStepper stepper3(1,zstepPin,zdirPin);//建立步进电机对象
char X;volatile int sj=25;
volatile int jdu=0;
Servo servo_11;
Servo servo_8;
Servo servo_3;
Servo servo_4;
Servo servo_7;
Servo servo_12;
void setup() {LZC.begin(9600);pinMode(zstepPin,OUTPUT);     // Arduino控制A4988z步进引脚为输出模式pinMode(zdirPin,OUTPUT);      // Arduino控制A4988z方向引脚为输出模式pinMode(enablePin,OUTPUT);   // Arduino控制A4988使能引脚为输出模式digitalWrite(enablePin,LOW); // 将使能控制引脚设置为低电平从而让pinMode(A3, OUTPUT);pinMode(2, OUTPUT);                       // 电机驱动板进入工作状态stepper3.setMaxSpeed(300.0);     // 设置电机最大速度300stepper3.setAcceleration(20.0);   // 设置电机加速度20.0servo_11.attach(11);servo_8.attach(8);servo_3.attach(3);servo_4.attach(4);servo_7.attach(7);servo_12.attach(12);LZC.begin(9600);servo_7.write(45);servo_11.write(135);delay(sj);delay(sj);digitalWrite(2,HIGH);digitalWrite(A3,LOW);for (int i = 150; i >= 105; i = i + (-1)) {servo_4.write(i);delay(sj);servo_3.write(i-10);delay(sj);servo_8.write(305-i);delay(sj);}for (int i = 105; i >= 70; i = i + (-1)) {servo_3.write(i-10);delay(sj);servo_8.write(325-i);delay(sj);}
}void loop() {if( Serial.available())
{X= Serial.read();LZC.print(X);   
}
if(LZC.available())
{X=LZC.read();   Serial.print(X);}switch(X){case 'a':digitalWrite(2,1);digitalWrite(A3,0);LZC.println("开始抓东西");servo_11.write(135);delay(sj);servo_8.write(135);delay(sj);servo_3.write(135);delay(sj);servo_4.write(135);delay(sj);servo_7.write(45);delay(sj);delay(1000);for (int i = 45; i <= 110; i = i + (1)) {servo_7.write(i);delay(sj);}for (int i = 135; i >= 110; i = i + (-1)) {servo_4.write(i);delay(sj);jdu = i;servo_3.write(jdu/2);delay(sj);}for (int i = 110; i <= 150; i = i + (1)) {servo_4.write(i);delay(sj);servo_8.write(255-i);delay(sj);}for (int i = 150; i <= 190; i = i + (1)) {servo_4.write(i);delay(sj);servo_3.write(i-100);delay(sj);}servo_11.write(190);delay(sj);delay(1000);for (int i = 190; i >= 150; i = i + (-1)) {servo_4.write(i);delay(sj);jdu = i;servo_3.write(i-20);delay(sj);servo_8.write(310-i);delay(sj);}for (int i = 150; i >= 125; i = i + (-1)) {servo_4.write(i);delay(sj);servo_3.write(i);delay(sj);servo_8.write(345-i);delay(sj);}for (int i = 110; i <= 170; i = i + (1)) {servo_7.write(i);delay(sj);}servo_11.write(135);delay(sj);delay(1000);for (int i = 170; i >= 42; i = i + (-1)) {servo_7.write(i);delay(sj);}for (int i = 150; i >= 105; i = i + (-1)) {servo_4.write(i);delay(sj);servo_3.write(i-10);delay(sj);servo_8.write(305-i);delay(sj);}delay(10000);break;case 'b':digitalWrite(2,HIGH);digitalWrite(A3,LOW);LZC.println("开始放东西");servo_11.write(135);delay(sj);servo_8.write(135);delay(sj);servo_3.write(135);delay(sj);servo_4.write(135);delay(sj);servo_7.write(45);delay(sj);for (int i = 45; i <= 170; i = i + (1)) {servo_7.write(i);delay(sj);}for (int i = 135; i >= 105; i = i + (-1)) {servo_4.write(i);delay(sj);servo_8.write(i+45);delay(sj);servo_3.write(i-10);delay(sj);}for (int i = 135; i <= 260; i = i + (1)) {servo_8.write(i);delay(sj);}servo_11.write(190);delay(sj);for (int i = 260; i >= 155; i = i + (-1)) {servo_8.write(i);delay(sj);}for (int i = 170; i >= 110; i = i + (-1)) {servo_7.write(i);delay(sj);}for (int i = 90; i <= 150; i = i + (1)) {servo_4.write(i);delay(sj);servo_8.write(i+10);delay(sj);servo_3.write(i-40);delay(sj);}delay(1000);servo_11.write(135);delay(sj);delay(1000);for (int i = 110; i >= 45; i = i + (-1)) {servo_7.write(i);delay(sj);}for (int i = 150; i >= 105; i = i + (-1)) {servo_4.write(i);delay(sj);servo_3.write(i-10);delay(sj);servo_3.write(i-10);delay(sj);servo_8.write(305-i);delay(sj);}for (int i = 105; i >= 70; i = i + (-1)) {servo_3.write(i-10);delay(sj);servo_8.write(325-i);delay(sj);}delay(10000);break;       case 'c':{digitalWrite(2,0);digitalWrite(A3,1);LZC.println("步进电机开始运动");digitalWrite(zdirPin,LOW);// 电机慢速旋转for(int x = 0; x < STEPS_PER_REV; x++) {digitalWrite(zstepPin,HIGH);delayMicroseconds(2000);digitalWrite(zstepPin,LOW);delayMicroseconds(2000);}// 等待一秒delay(10000);break;}case 'd':{   digitalWrite(2,0);digitalWrite(A3,1);LZC.println("步进电机开始运动");// 设置电机逆时针旋转digitalWrite(zdirPin,HIGH);// 电机快速旋转for(int x = 0; x < (STEPS_PER_REV * 2); x++) {digitalWrite(zstepPin,HIGH);delayMicroseconds(1000);digitalWrite(zstepPin,LOW);delayMicroseconds(1000);}// 等待一秒delay(10000);break;
}
case 'e':
{digitalWrite(2,0);digitalWrite(A3,1);LZC.println("云台开始运动");for (int i = 0; i <= 90; i = i + (1)) {servo_12.write(i);delay(15);}for (int i = 90; i >= 0; i = i + (-1)) {servo_12.write(i);delay(15);}break;}
case 'f':
{digitalWrite(2,0);digitalWrite(A3,1);for (int i = 150; i >= 105; i = i + (-1)) {servo_4.write(i);delay(sj);servo_3.write(i-10);delay(sj);servo_8.write(305-i);delay(sj);}for (int i = 105; i >= 70; i = i + (-1)) {servo_3.write(i-10);delay(sj);servo_8.write(325-i);delay(sj);}delay(15000);} }}

2. 资料下载

资料内容:

①程序源代码

②模型3D文件

③仿真渲染文件

④关键零件应力分析图

资料下载地址:送餐机器人

相关文章:

机器人制作开源方案 | 送餐机器人

作者&#xff1a;赖志彩、曹柳洲、王恩开、李雪儿、杨玉凯 单位&#xff1a;华北科技学院 指导老师&#xff1a;张伟杰、罗建国 一、作品简介 1. 场景调研 1.1项目目的 近年来&#xff0c;全国多地疫情频发&#xff0c;且其传染性极高&#xff0c;食品接触是传播途径之一。…...

Gradio部署应用到服务器不能正常访问

用Gradio部署一个基于ChatGLM-6B的应用&#xff0c;发布到团队的服务器上&#xff08;局域网&#xff0c;公网不能访问&#xff09;&#xff0c;我将gradio应用发布到服务器的9001端口 import gradio as gr with gr.Blocks() as demo:......demo.queue().launch(server_port90…...

数据暴涨时代,该如何数据治理?_光点科技

随着信息技术的迅猛发展&#xff0c;数据已经成为现代社会的核心资源。在这个被称为"数据暴涨时代"的时代里&#xff0c;大量的数据源源不断地被产生和积累&#xff0c;但如何有效地管理、分析和利用这些数据成为了一个迫切需要解决的问题。数据治理&#xff0c;作为…...

2021年03月 C/C++(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;找和为K的两个元素 在一个长度为n(n < 1000)的整数序列中&#xff0c;判断是否存在某两个元素之和为k。 时间限制&#xff1a;1000 内存限制&#xff1a;65536 输入 第一行输入序列的长度n和k&#xff0c;用空格分开。 第二行输入序列中的n个整数&#xff…...

GPT-5出世?OpenAI GPT-5商标已注册

OpenAI的GPT已经成为了业界标杆&#xff0c;升级速度之快让人瞠目&#xff0c;别人追GPT-3.5的时候GPT-4横空出世&#xff0c;差距被拉开了&#xff0c;现在GPT-5就要来了。 据商标律师泄露的消息&#xff0c;OpenAI已于7月18日注册了GPT-5商标。虽然注册商标并不罕见&#xf…...

优雅的使用 Dockerfile 定制镜像

一、使用 Dockerfile 定制镜像 1.1、Dockerfile 定制镜像 镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本&#xff0c;用这个脚本来构建、定制镜像&#xff0c;无法重复的问题、镜像构建透明性的问题、…...

limit的用法mysql

当你在 MySQL 数据库中使用 LIMIT 语句&#xff0c;它可以用于限制查询结果的行数。这在分页查询或者限制返回的数据量时非常有用。下面是一些示例&#xff1a; 返回前几行数据&#xff1a; SELECT * FROM Customers LIMIT 5;这将返回 Customers 表中的前 5 行数据。 分页查…...

clickhouse Checksum doesn‘t match: 问题修复

1. 问题描述 SQL 错误 [40] [07000]: Code: 40. DB::Exception: Checksum doesnt match: corrupted data. Reference: 50e8c1efa78de2881b725d44b04be1fe. Actual: 161c99eb681ec36b83540ecdd65ad8c9. Size of compressed block: 32846. The mismatch is caused by single bit…...

企业如何开展个人信息安全影响评估(PIA)二

基本概念 根据《信息安全 技术个人信息安全影响评估指南》&#xff08;GB/T 39335—2020&#xff1b;personal information security impact assessment&#xff0c;简称“PIA”&#xff09;&#xff0c;个人信息安全影响评估是指针对个人信息处理活动&#xff0c;检验其合法合…...

android TextView 超出长度使用省略号

在Android中最常见的需求&#xff0c;就是在在外部展示信息时&#xff0c;需要简要展示内容。TextView仅需在静态布局文件中设置以下几个属性&#xff1a; android:maxWidth“100dp” // 宽度是多少才算超出 android:maxLines"2" // 高度多少才算超出 android:elli…...

c++ | 字节转换 | 字长 | 机器位数

为什么有的时候脑子转不过来&#xff1f;&#xff1f; 为什么要对字节、机器长啊、位啊都要门清 位数 一般的就是指计算机的位数&#xff0c;比如64位/32位&#xff0c;更简单的理解&#xff0c;计算机就是在不停的做二进制的计算&#xff0c;比如32位计算机&#xff0c;在长…...

7-4 交换最小值和最大值

分数 15 全屏浏览题目 切换布局 作者 C课程组 单位 浙江大学 本题要求编写程序&#xff0c;先将输入的一系列整数中的最小值与第一个数交换&#xff0c;然后将最大值与最后一个数交换&#xff0c;最后输出交换后的序列。 注意&#xff1a;题目保证最大和最小值都是唯一的。…...

解决Pycharm的Settings中Project不见了也无法选择Python Interpreter的方法

目录 一、问题如下二、解决方法 一、问题如下 突然打开项目没有python解释器&#xff0c;也无法重新配置python Interpreter&#xff0c;而且整个文件夹是黄色高亮的形式&#xff0c;如下显示&#xff0c;而且重新安装了pycharm也没用甚至说打开File–>Setting–>Projec…...

AWS EKS 集群自动扩容 Cluster Autoscaler

文章目录 一&#xff0c;需求工作需求说明 二&#xff0c;部署精简命令执行1&#xff0c;要求2&#xff0c;查看EC2 Auto Scaling groups Tag3&#xff0c;创建Serviceaccount需要的Policy&#xff0c;Role4&#xff0c;部署Cluster Autoscaler5&#xff0c;验证6&#xff0c;常…...

excel中有哪些通配符、excel配置问题,数学函数篇1之sum系列

学习excel前需要明确的是事&#xff1a;   在学习excel函数之前&#xff0c;大家需要明确一件事&#xff0c;excel现在设计到了一些新函数&#xff0c;这些新函数只能存在于office365、office2019及更 新版本之中&#xff0c;所以建议大家在学习时安装较新的版本&#xff0c;…...

工控行业需要熟悉的工业级通信协议

1. Modbus RTU Modbus RTU 是一种串行通信协议&#xff0c;常用于工控行业。它具有以下特点和优势&#xff1a; 采用二进制编码&#xff0c;数据传输更加高效。支持多种传输介质&#xff0c;如RS-232、RS-485等。容易实现和使用&#xff0c;适用于各种设备。具备强大的错误检…...

力扣题解(1030. 距离顺序排列矩阵单元格),带注释

题目描述 链接:点我 注意&#xff1a;多看几遍题目&#xff0c;开始没看懂…相当于计算矩阵网格里面的点&#xff08;不要计算边界&#xff09; 我开了题解才明白题的意思 orz… 题解 class Solution {public int[][] allCellsDistOrder(int rows, int cols, int rCenter, …...

每天一道leetcode:剑指 Offer 34. 二叉树中和为某一值的路径(中等图论深度优先遍历递归)

今日份题目&#xff1a; 给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例1 输入&#xff1a;root [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSu…...

利用POM完成脚本分离实现企业级自动化(POM设计模式+页面的框架封装+测试报告截图)

利用POM完成脚本分离实现企业级自动化&#xff08;POM设计模式页面的框架封装测试报告截图&#xff09; 项目-测试-手工测试 项目-测试-手工测试 1.了解需求&#xff1b; 2.编写测试用例&#xff08;开始&#xff09;——功能测试组会去做的事情 3.执行测试用例——发送测试报…...

嵌入式设计中对于只有两种状态的变量存储设计,如何高效的对循迹小车进行偏差量化

前言 &#xff08;1&#xff09;在嵌入式程序设计中&#xff0c;我们常常会要对各类传感器进行数据存储。大多时候的传感器&#xff0c;例如红外光传感器&#xff0c;返回的数据要么是0&#xff0c;要么是1。因此&#xff0c;只需要一bit就能够存储。而很多人却常常使用char型数…...

day53 第九章 动态规划part14● 1143.最长公共子序列 ● 1035.不相交的线 ● 53. 最大子序和 动态规划

1143. 最长公共子序列 class Solution {public int longestCommonSubsequence(String text1, String text2) {int m text1.length();int n text2.length();int[][] dp new int[m 1][n 1];for (int i 1; i < m; i) {for (int j 1; j < n; j) {if (text1.charAt(i …...

shell编程 基础

将content.txt文件中的内容输出到控制台上 将content.txt中有tom的行输出到控制台 将$2文件中含有gree的行输出到控制台 case语法 简易计算器 查找有root的行 查找以root开头的行 查询时忽略大小写 grep -E 则适用于复杂的正则表达式&#xff0c;可以使用多项选择、重复和子表达…...

人工智能在网络安全中的应用: 分析人工智能、机器学习和深度学习等技术在预测、检测和应对网络攻击中的作用

第一章&#xff1a;引言 随着信息技术的迅猛发展&#xff0c;网络安全已成为当今社会不容忽视的重要议题。网络攻击手法日益复杂&#xff0c;传统的防御方法已经不再足够。在这一背景下&#xff0c;人工智能&#xff08;AI&#xff09;技术正逐渐崭露头角&#xff0c;为网络安…...

使用 Redis 实现异步队列

使用 Redis 实现异步队列 一、简介1 异步队列2 异步队列与同步队列 二、Redis 实现异步队列1 利用 Redis 的 List 数据类型实现异步队列2 利用 Redis 的 Pub/Sub 功能实现异步队列3 利用 Redis 的 Sorted Set 数据类型实现延迟队列 三、Redis 异步队列的实际应用场景4.1 异步任…...

RocketMQ、Dashboard部署以及安全设置

RocketMQ、dashboard部署以及安全设置 一、启动RocketMQ1.1 下载RocketMQ1.2 修改配置文件1.2.1 修改nameServer Jvm内存配置1.2.2 修改broker参数 1.3 启动1.3.1 启动NameServer1.3.2 启动Broker1.3.3 测试是否启动成功1.3.3.1 测试消息发送1.3.3.2 测试消息接收1.3.3.3 Java程…...

Android AlarmManager设置闹钟

官网镇楼&#xff1a;设置重复闹铃时间 闹钟具有以下特征&#xff1a; 它们可让您按设定的时间和/或间隔触发 intent。您可以将它们与广播接收器结合使用&#xff0c;以启动服务以及执行其他操作。它们在应用外部运行&#xff0c;因此即使应用未运行&#xff0c;或设备本身处…...

【C# 基础精讲】LINQ to XML查询

LINQ to XML 是 C# 中用于查询和操作 XML 数据的强大工具。它允许您使用 LINQ 查询语法对 XML 文档进行查询、过滤、投影等操作&#xff0c;从而更加方便地处理 XML 数据。本文将详细介绍 LINQ to XML 的基本概念、常见操作以及示例&#xff0c;帮助您了解如何在 C# 中使用 LIN…...

Java学习笔记——(20)标识符命名规则和规范

什么叫标识符 Java 对各种变量、方法和类等命名时使用的字符序列成为标识符凡是自己可以起名字的地方都叫标识符 标识符的命名规则&#xff08;必须遵守&#xff09; 由26个英文字母大小写&#xff0c;0-9&#xff0c;_ 或 $ 组成数字不可以开头不可以使用关键字和保留字Jav…...

过滤字符,绕过

构造不包含字母和数字的webshell <?phpecho "A"^""; ?>运行结果为! 代码中对字符"A"和字符”"进行了异或操作。在PHP中&#xff0c;两个变量进行异或时&#xff0c;先会将字符串转换成ASCII值&#xff0c;再将ASCII值转换成二进制…...

Apache Doris 入门教程32:物化视图

物化视图 物化视图是将预先计算&#xff08;根据定义好的 SELECT 语句&#xff09;好的数据集&#xff0c;存储在 Doris 中的一个特殊的表。 物化视图的出现主要是为了满足用户&#xff0c;既能对原始明细数据的任意维度分析&#xff0c;也能快速的对固定维度进行分析查询。 …...

PHP substr()函数详解,PHP截取字符串。

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 substr 一、截取字符串二、截取中文字符串三、leng…...

关于flink-sql-connector-phoenix的重写逻辑

目录 重写意义 代码结构 调用链路 POM文件配置 代码解析 一、PhoenixJdbcDynamicTableFactory...

Django进阶:DRF(Django REST framework)

什么是DRF&#xff1f; DRF即Django REST framework的缩写&#xff0c;官网上说&#xff1a;Django REST framework是一个强大而灵活的工具包&#xff0c;用于构建Web API。 简单来说&#xff1a;通过DRF创建API后&#xff0c;就可以通过HTTP请求来获取、创建、更新或删除数据(…...

Flink CDC系列之:Oracle CDC 导入 Elasticsearch

Flink CDC系列之&#xff1a;Oracle CDC 导入 Elasticsearch 一、深入理解Flink Oracle CDC Connector二、创建docker-compose.yml文件三、启动容器四、下载Flink Oracle CDC的jar包五、启动 Flink 集群&#xff0c;再启动 SQL CLI六、检查 ElasticSearch 中的结果七、在 Oracl…...

Linux忘记root密码解决方法

当我们忘记root密码进不去服务器怎么办&#xff1f;不要担心&#xff0c;可以进入到linux的救援模式修改root密码。 下面直接上干货&#xff0c;流程如下&#xff1a; 1.重启电脑&#xff0c;按上下键滑动&#xff0c;保证不进入开机流程&#xff0c;然后按e键 2.出现此页面…...

AR/VR眼镜转接器方案,实现同时传输视频快充方案

简介 虚拟现实头戴显示器设备&#xff0c;简称VR头显VR眼镜&#xff0c;是利用仿真技术与计算机图形学人机接口技术多媒体技术传感技术网络技术等多种技术集合的产品&#xff0c;是借助计算机及最新传感器技术创造的一种崭新的人机交互手段。VR头显VR眼镜是一个跨时代的产品。不…...

ASP.NET Core中路由规则匹配

RESTful约束&#xff0c;如果在一个控制器里面有多个Get、Post...的操作 1、在一个控制器里面可以定义多个API方法 2、通过路由规则来区分 /// <summary> /// 获取用户信息 /// </summary> /// <param name"user"></param> /// <returns…...

IDEA:Error running,Command line is too long. 解决方法

报错如下&#xff1a; Error running SendSmsUtil. Command line is too long. Shorten the command line via JAR manifest or via a classpath file and rerun.原因是启动命令过长。 解决方法&#xff1a; 1、打开Edit Configurations 2、点击Modify options设置&#x…...

什么是反射机制?为什么反射慢?

目录 面试回答 知识扩展 反射常见的使用方式 反射和 Class 的关系 面试回答 反射指的是程序在运行时能够获取自身的信息。在 java 中&#xff0c;只要给定类的名字&#xff0c;那么就可以通过反射机制来获得类的所有属性和方法。 Java 的反射可以&#xff1a; 在运行时判断…...

list元素

列表元素 列表元素分为有序列表和无序列表 有序列表 ol – order list – 有序列表 li – list item – 列表元素 <ol type"1"><li>有序列表1</li><li>有序列表2</li><li>有序列表3</li> </ol>属性 type type属…...

OkHttp 源码浅析一

演进之路:原生Android框架不好用 ---- HttpUrlConnect 和 Apache HTTPClient 第一版 底层使用HTTPURLConnect 第二版 Square构建 从Android4.4开始 基本使用: val okhttp OkHttpClient()val request Request.Builder().url("http://www.baidu.com").buil…...

【解决问题】远程仓库GitHub/GitLab添加了SSH Key之后依然无法clone的解决办法

GitHub/GitLab添加了SSH Key之后依然无法clone的解决办法 问题现象解决办法 问题现象 在Git远程仓库添加了自己的ssh key到账户下&#xff0c;git clone时&#xff0c;依然报错clone失败&#xff0c;请检查是否没有权限进行clone操作。 解决办法 在git的安装目录下&#xff…...

回归预测 | MATLAB实现SA-SVM模拟退火算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现SA-SVM模拟退火算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现SA-SVM模拟退火算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本…...

Spring事务和事务传播机制(1)

前言&#x1f36d; ❤️❤️❤️SSM专栏更新中&#xff0c;各位大佬觉得写得不错&#xff0c;支持一下&#xff0c;感谢了&#xff01;❤️❤️❤️ Spring Spring MVC MyBatis_冷兮雪的博客-CSDN博客 在Spring框架中&#xff0c;事务管理是一种用于维护数据库操作的一致性和…...

如何快速在vscode中实现不同python文件的对比查看

总体而言&#xff1a;两种方式。一种是直接点击vscode右上角的图标&#xff08;见下图&#xff09;。 另一种方式就是使用快捷键啦“**Ctrl**”&#xff0c;用的时候选中想要对比的python文件&#xff0c;然后快捷键就可以达到下图效果了&#xff1a; 建议大家直接使用第二种…...

网络安全---Ring3下动态链接库.so函数劫持

一、动态链接库劫持原理 1.1、原理 Unix操作系统中&#xff0c;程序运行时会按照一定的规则顺序去查找依赖的动态链接库&#xff0c;当查找到指定的so文件时&#xff0c;动态链接器(/lib/ld-linux.so.X)会将程序所依赖的共享对象进行装载和初始化&#xff0c;而为什么可以使用…...

leetcode283. 移动零

难度&#xff1a;简单题 题目 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 思路&#xff1a; 一开始想&#xff0c;从前往后遍历&am…...

GuLi商城-前端基础Vue-生命周期和钩子函数

下图展示了实例的生命周期。你不需要立马弄明白所有的东西&#xff0c;不过随着你的不断学习和使用&#xff0c;它 的参考价值会越来越高。 VUE 的生命周期指的是组件在创建、运行和销毁过程中所经历的一系列事件&#xff0c;通过这些事件可以 让开发者在不同阶段进行相应的…...

输入输出+暴力模拟入门:魔法之树、染色の树、矩阵、字母加密、玫瑰鸭

秋招实习刷题网站推荐&#xff1a;codefun2000.com&#xff0c;还有题解博客&#xff1a;blog.codefun2000.com/。以下内容都是来自塔子哥的~ 输入输出 2023.04.15-春招-第三题-魔法之树 //#include<bits/stdc.h> #include<vector> #include<iostream>usin…...

​Kubernetes的演变:从etcd到分布式SQL的过渡

DevRel领域专家Denis Magda表示&#xff0c;他偶然发现了一篇解释如何用PostgreSQL无缝替换etcd的文章。该文章指出&#xff0c;Kine项目作为外部etcd端点&#xff0c;可以将Kubernetes etcd请求转换为底层关系数据库的SQL查询。 受到这种方法的启发&#xff0c;Magda决定进一步…...