机器人制作开源方案 | 智能图书搬运机器人

作者:张宸豪 戚益凡 陈世达 高梓钦 谭清
单位:华北科技学院
指导老师:罗建国 韩红利


       阅读对于学生的重要性毋庸置疑,因此图书馆是一个校园非常重要的组成部分,图书馆的书籍借阅,能为学生提供非常大的学习平台。而学校图书馆藏书最少近万本,按照不同的类别进行摆放,加之图书馆每天庞大的人流量形成巨大的借阅量,图书的提取成为了一个非常繁重的工作(如下图所示)。为减轻工作人员的劳动量、提高效率及缩短图书的提取时间,本团队提出设计一个智能图书搬运机器人。本设计的主要任务是成功完成要用于完成图书的提取、搬运工作。因此要求机器人具有行走、自动识别图书类别、并将图书从书架上准确提取的功能。同时机器人应考虑到在人流量大场所中工作的安全稳定以及图书馆中作业的安静运行等特性。

图书馆

       经过反复考察,征求各方专家老师的意见,结合现阶段学校图书馆的现状,开发研制了专用校园智能图书搬运机器人。该机器包括了自动巡线、避障、取书、送书等功能,通过自行设计的独特机械结构,实现了书架上书籍的精确提取,操作人员对机器人的指令输入,机器人自行分析路径,稳定准确的行驶至对应的书架前,并实现取书、运书一体化,节约了大量的时间、人力、财力。
 

1. 作品简介

       智能图书搬运机器人(如下图所示),是基于校园图书馆内服务的一款机器人,该机器人具备自动循迹技术,可在图书馆内沿划定路线进行循迹自动行驶,并在达到目标位置时停止,机械臂运动,通过瞄-抽-夹-提-放5步,将目标书籍从书架上提取至机器人货仓,再循迹前往下一个目标位置。通过这些功能,可以完成帮助图书管理员取书的任务,图书管理员只需向机器人导入取书指令,机器人便可将目标书籍取回。同时,其安装有红外传感器、LED 显示屏、以及运行指示灯,可以在实际运行中,在运行轨迹上出现障碍物时紧急制动,并通过 LED 显示屏和指示灯向外界传达避让信息,保证了在人流活动场所中机器运行所必须考虑的安全性。智能图书搬运机器人具有全自动作业、工作容量大、安全稳定等优点。

智能图书搬运机器人

2. 作品设计

2.1 机械结构
       ① 底盘及行走结构:通过杆件和板块形成底盘,宽广而平整,配合两侧的栏杆,形成了理想的货仓。底盘下安装有四个驱动电机,形成四轮驱动,由arduino 单独控制左右侧轮的转速,形成差速转向,运动灵活敏捷,在校园图书馆内可进行安静平稳的循迹运动,将书籍安全地送至指定地点。模块化搭建,拆卸方便,利于维护修理,方便后期进行二次改造。底盘结构如下图所示:

底盘及行走结构

       ② 机械臂结构:机械臂由升降台和抓取臂两部分组成。升降台使用步进电机配合螺纹柱,形成抓取臂的竖直移动底座,方便完成不同书架高度的作业要求,通过对螺纹柱长度的加长,可以提高抓取臂的移动高度上限。升降台的底座,是270°舵机,其控制升降台旋转,带动了以升降台为轴的抓取臂的圆周运动,使机械臂灵活地在书架与货仓间转移。抓取臂采用两个舵机横向安装,形成两轴结构,使得抓取臂能在竖直平面上在一定范围内灵活、精准地运动,与升降台的互相配合,形成大范围作业区域广,小范围作业精度高的特点,抓取臂的头部是提取胶轮和机械爪,舵机驱动胶轮旋转,在摩擦力的作用下将目标书籍从书堆中分离,机械爪由舵机和杆件配合控制夹放,在胶轮提取后进行夹取运动,爪上套有橡皮套,在增大摩擦的同时,可以保护书籍,整套机械臂结构通仿生抽-夹-提的拿书动作,有效保证书籍提取的精确性稳定性。机械臂结构如下图所示:

机械臂结构

 2.2 运动分析
       ① 底盘行走分析:底盘开机,四轮默认转速为正转 130,形成匀速前进,由四个灰度传感器返回的值来判断小车巡线准确性,同时控制转向调整。若偏离航向,灰度传感器向 arduino 传递信号发生改变,Arduino 板驱动电机变速形成左右差速变向;例如,若巡线偏左,传感器数值由 1001 变为 1100,开发板接收到信号变化,控制右方两个电机速度变速为正转 205、左方两个电机变速为反转80,形成差速左转;经过不断调试后,我们将左转右转延迟设置为0.05秒,该延迟下既保证了巡线的准确度,也保证了车辆行进姿态的稳定。
       ② 机械臂运动分析:自下而上定义定义舵机号数为1、2、3、4、5,机械臂默认状态下为1号舵机90°、2号舵机180°、3 号舵机150°、4号舵机90°、5号舵机180°,折叠停放在货仓上方。小车抵达指定取书位置,3号舵机转至135°,前臂向上展开;1号舵机转至15°,机械臂向右转;2号舵机转至115°,机械臂前伸,胶轮压住目标书籍;随后5号舵机转至0°,胶轮开始缓慢转动,将目标书籍抽出;4号舵机转至0°,夹子抓紧,夹住目标书籍;夹取稳定后,2号舵机转至180°、1号舵机转至90°、3号舵机转至165°,机械臂回收至货仓上方;4号舵机转至45°,夹子放开;书落到小车架子上。机械臂运作示意图如下所示:

机械臂运作示意图

2.3 传感器应用
       ① 灰度传感器循迹:灰度传感器利用一只发光二极管和一只光敏电阻,通过反馈的形式给数字引脚提供具体数据。本机器采用四个灰度传感器集合的方式,进行黑色线寻迹,对线路的识别进行精准把控,arduino 控制板把四个传感器获得的数据进行位处理,对处理后的数字进行范围的判断,并通过选择语句对机器人的左转、右转、前进进行有序地调控,保证在无人操控的场景下,机器人能按照既定轨迹在取书台、阅览区、书库间执行运输任务,提高了容错率。
       ② 红外传感器避障:近红外传感器是一种开关量传感器,它可以检测到前方是否有物体存在,当检测到有物体存在时,传感器输出口会输出低电平;相反在未检测到前方有物体时,传感器输出口会输出一个高电平,通过电平变化向Aduino 控制板反映前方障碍物情况,我们在车辆前方安装有近红外传感器,用以调度车轮电机,在图书馆中巡线过程中,若有人进入小车循迹轨迹中,Arduino控制板接收到传感器高电平变为低电平,发出对驱动电机的停止指令,控制小车急停,前方人员离开后,红外传感器输出高电平,机器人继续执行循迹取书任务。

2.4 设备安装与调试
       ① 使用不同的零件拼装实体,搭载舵机电机,进行调试,调整舵机转向的角度,模拟小车转向移动使小车转向更加合理。增加灰度传感器、红外避障传感器等多项装置,增加其功能。
       ② 编写程序,控制抓取装置进行测试,测试出抓取装置的最远距离和最近距离,以及编写避障与循迹轨迹的程序,测试循迹和避障的实际效果,并进行轨迹调整和停留时间的修改。
       ③ 对轮距、机械臂位置进行调整,平衡机器人的重心,保证机器人的轮胎抓地力,提高过弯流畅性和夹取稳定性。
       ④ 测试夹取不同大小、厚度的书籍,观察抽取流畅度、夹取稳定性。及时对力臂长短、施压大小、夹取紧度进行调整,取综合最优值,使机器人在夹取不同类型书籍时既稳定可靠,又不会对书籍造成破坏。
       ⑤ 在不同的光照强度下进行模拟试验,模拟机器人穿越书库、阅览区等光照强度不同的场所,让小车完成一定轨迹的整套流程动作测试其性能使之能更加适应应用场景,并记录每次完成一整套动作的时间,用于判断节省的时间。
 

3. 作品创新点

3.1 胶轮式抓取结构
       在图书馆中,书籍多为成排立放与书架,书与书之间紧贴放置,无法直接使用机械爪直接夹取单本书,我们思考过仿人手设计,在原型机上设置了一个手指型的爪子先将书勾出一个角,但机械臂的力道控制无法达到生物级精度,考虑到钩子会对书产生损坏,我们转变思路,采用了胶轮结构(如下图所示),使用舵机配合带橡胶圈的圆片,安装在机械臂头部,组成提取结构,可以精确地将目标书籍从书堆中分离,并且对书籍的损害降到最低。对舵机旋转角度的设置即对图书抽离最远及最近距离的设置,方便接下来机械爪进行夹取动作。

胶轮式抓取结构

3.2 单柱式升降结构
       区别于传统螺纹柱加光滑柱组成的双柱升降结构,我们采用步进电机与螺纹杆连接,螺纹杆与升降模块相互配合,后方支柱限位升降模块的旋转,形成了单柱式升降结构,如下图 所示:

单柱式升降结构

       为解决传统单柱升降所产生的晃动,我们将升降模块通过卡扣紧贴与后方主支柱,如下图所示,让支柱同时充当升降模块的滑轨和支柱,达成了步进电机旋转带动机械臂平稳升降的效果,该结构既节省空间,又具备了双柱式的稳定性。

卡扣结构

3.3 遇障处理
       图书馆狭小的通道内,机器人的绕行避障实现困难,结合图书馆运行场所,我们机器人前部设置红外传感器,主要用于识别在规定航线上的路人,当前部的红外传感器识别到路人时,便会通过顶部显示屏,如下图所示,发出提醒字样,提醒路人注意避让。显示屏采用 LED 显示,LED 显示清晰,提示明显。

4. 示例程序

① 机械臂代码

#include <AccelStepper.h>         //调用步进电机库

#include <Servo.h>

volatile int ys;

const int moveSteps = 2000;

Servo servo_3;

Servo servo_4;

Servo servo_12;

Servo servo_8;

Servo servo_11;

const int xdirPin = 5;     // 方向控制引脚

const int xstepPin = 2;    // 步进控制引脚

const int xenablePin = 7;   // 使能控制引脚

AccelStepper stepper1(1,xstepPin,xdirPin);//建立步进电机对象

void jingzhi()   //机械臂调整到初位置

{

  servo_3.write(90);

  delay(0);

  servo_4.write(180);

  delay(0);

  servo_12.write(150);

  delay(0);

  servo_8.write(90);

  delay(0);

  servo_11.write(180);

  delay(0);

  delay(1000);

}

void zhuaqu()     //机械臂开始抓取

{

   ys = 30;

  servo_3.attach(3);

  servo_4.attach(4);

  servo_12.attach(12);

  servo_8.attach(8);

  servo_11.attach(11);

  servo_3.write(90);

  delay(0);

  servo_4.write(180);

  delay(0);

  servo_12.write(150);

  delay(0);

  servo_8.write(90);

  delay(0);

  servo_11.write(180);

  delay(0);

  delay(1000);

  for (int i = 180; i >= 135; i = i + (-1)) {

    servo_12.write(i);

    delay(ys);

  }

  for (int i = 90; i >= 15; i = i + (-1)) {

    servo_3.write(i);

    delay(ys);

  }

  for (int i = 180; i >= 115; i = i + (-1)) {

    servo_4.write(i);

    delay(ys);

  }

  for (int i = 120; i >= 0; i = i + (-1)) {

    servo_11.write(i);

    delay(ys);

  }

  for (int i = 90; i >= 0; i = i + (-2)) {

    servo_8.write(i);

    delay(ys);

  }

  for (int i = 115; i <= 180; i = i + (1)) {

    servo_4.write(i);

    delay(ys);

  }

  for (int i = 30; i <= 90; i = i + (1)) {

    servo_3.write(i);

    delay(ys);

  }

  for (int i = 135; i <= 165; i = i + (1)) {

    servo_12.write(i);

    delay(ys);

  }

  for (int i = 0; i <= 45; i = i + (1)) {

    servo_8.write(i);

    delay(ys);

  }

  while(true);

}

void bujin()        //控制步进电机

{

  if ( stepper1.currentPosition() == 0 )

  {

    stepper1.moveTo(moveSteps);             

    delay(20000);

  }

  else if ( stepper1.currentPosition() == moveSteps   )

  {

    stepper1.moveTo(0);           

  }         

  stepper1.run();   //步进电机运行

}

void setup(){

  pinMode(A0, INPUT);

  Serial.begin(9600);

  pinMode(xstepPin,OUTPUT);     //步进引脚设置为输出模式

  pinMode(xdirPin,OUTPUT);       //方向引脚设置为输出模式

  pinMode(xenablePin,OUTPUT);    //使能引脚设置为输出模式

  digitalWrite(xenablePin,LOW);   //将使能控制引脚设置为低电平从而让电机驱动板进入工作状态

  digitalWrite(xdirPin,LOW);

  stepper1.setMaxSpeed(300.0);     // 设置电机最大速度300

  stepper1.setAcceleration(50.0);   // 设置电机加速度50

}

void loop(){

Serial.println(digitalRead(A0));

if(!digitalRead(A0))

  {

    bujin();

    zhuaqu();

  }

  else

  {

   jingzhi();

  }

}

② 底盘代码

#include <U8g2lib.h>                                       //调用显示屏库函数

U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0,SCL,SDA); //配置构造函数

void runfoward();   //前进

void runback();     //后退

void turnL();       //左转

void turnR();       //右转

void stop();        //停止

void xunshujia();   //小车寻找书架

void red();         //亮红灯

void off();         //灯熄灭

void green();       //亮绿灯

void pingmu();      //显示屏工作

int c=66;           //定义常量

int a=205;

int b=80;

void runfoward()   //前进

{

  analogWrite(5, 130);

  analogWrite(6, 0);

  analogWrite(9, 130);

  analogWrite(10, 0);

}

void runback()   //后退

{

  digitalWrite(5, 0);

  digitalWrite(6, 130);  

  digitalWrite(9, 0);

  digitalWrite(10, 130);

}

void turnL()   //左转

{

  analogWrite(5, 0);

  analogWrite(6, b);

  analogWrite(9, a);

  analogWrite(10, 0);

}

void turnR()   //右转

{

  analogWrite(5, a);

  analogWrite(6, 0);

  analogWrite(9, 0);

  analogWrite(10, b);

}

void stop()   //停止

{

  analogWrite(5, 0);

  analogWrite(6, 0);

  analogWrite(9, 0);

  analogWrite(10, 0);

}

void xunshujia()    //小车寻找书架

{

    if (!digitalRead(A1))                    //A1引脚 近红外传感器

  {

    stop();

    red();

    delay(25000);

    runfoward();

    delay(2000);

  }

  else

  {

    runfoward();

    green();

  }

}

void red()   //亮红灯

{

  digitalWrite( 8 , HIGH );

  digitalWrite( 3 , LOW );

}

void off()   //灯熄灭

{

  digitalWrite( 8 , LOW );

  digitalWrite( 3 , LOW );

}

void green()   //亮绿灯

{

  digitalWrite( 8 , LOW );

  digitalWrite( 3 , HIGH );

}

void face()

{

    u8g2.clearBuffer();                                    //清空显示屏缓存

   

    u8g2.drawCircle(56,40,8,U8G2_DRAW_LOWER_LEFT);         //画四分之一圆,圆心坐标(56,44),半径8

    u8g2.drawCircle(56,40,8,U8G2_DRAW_LOWER_RIGHT);        //画四分之一圆

    u8g2.drawCircle(72,40,8,U8G2_DRAW_LOWER_LEFT);         //画四分之一圆

    u8g2.drawCircle(72,40,8,U8G2_DRAW_LOWER_RIGHT);        //画四分之一圆

    u8g2.drawCircle(56,41,8,U8G2_DRAW_LOWER_LEFT);         //加粗画四分之一圆

    u8g2.drawCircle(56,41,8,U8G2_DRAW_LOWER_RIGHT);        //加粗画四分之一圆

    u8g2.drawCircle(72,41,8,U8G2_DRAW_LOWER_LEFT);         //加粗画四分之一圆

    u8g2.drawCircle(72,41,8,U8G2_DRAW_LOWER_RIGHT);        //加粗画四分之一圆

    u8g2.drawLine(40,18,20,30);                            //画斜线,两端点坐标分别是(40,18)(20,30)

    u8g2.drawLine(88,18,108,30);                           //画斜线

    u8g2.drawLine(40,17,20,29);                            //加粗画斜线

    u8g2.drawLine(88,17,108,29);                           //加粗画斜线

   

    u8g2.sendBuffer();                                     //加载以上内容

}

void heart()

{

    u8g2.clearBuffer();                                    //清空显示屏缓存   

    u8g2.setFont(u8g2_font_open_iconic_human_2x_t);        //设置字体

    u8g2.drawGlyph(58,30,66);                              //画心

    u8g2.setFont(u8g2_font_unifont_t_chinese2);            //设置字体

    u8g2.drawUTF8(34,46,"ATTENTION");                      //显示英文

    u8g2.sendBuffer();                                     // 加载以上内容

}

void letter(int c)

{   

    u8g2.clearBuffer();                                    //清空显示屏缓存

    u8g2.setFont(u8g2_font_unifont_t_chinese2);            //设置字体

    u8g2.drawUTF8(32,32,"工作中");                         //显示文字

    u8g2.sendBuffer();                                     //显示内容

}

void pingmu()     //显示屏工作

{

    face();                                                //调用函数,显示图案

    delay(1000);                                           //持续一秒钟

    heart();                                               //调用函数,显示英文字母和图案

    delay(1000);                                           //持续一秒钟

    letter(c);                                             //调用函数,显示中文和变量

    delay(1000);                                           //持续一秒钟

}

void setup() {

  pinMode(9, OUTPUT);

  pinMode(10, OUTPUT);

  pinMode(5, OUTPUT);

  pinMode(6, OUTPUT);

  pinMode(A5, INPUT);

  pinMode(A2, INPUT);

  pinMode(A3, INPUT);

  pinMode(A4, INPUT);

  pinMode(A0, INPUT);

  pinMode(A1, INPUT);

  pinMode(8, OUTPUT);

  pinMode(3, OUTPUT);

  Serial.begin(9600);

  u8g2.begin();                                     //启动u8g2驱动程序

  u8g2.clearBuffer();                               //清空显示屏缓存

}

void loop() {

  int num1, num2, num3, num4;

  num1 = digitalRead(A5);

  num2 = digitalRead(A2);

  num3 = digitalRead(A3);

  num4 = digitalRead(A4);

  Serial.print(num1);         //读取串口数据

  Serial.print(num2);

  Serial.print(num3);

  Serial.print(num4);

  if (num1 == 1 && num2 == 1 && num3 == 1 && num4 == 1   ) {

    runfoward();

    green();

    delay(5);

  }

  else if (num1 == 1 && num2 == 0 && num3 == 1 && num4 == 1) {

    turnR();

    green();

    delay(50);

  }

  else if (num1 == 1 && num2 == 1 && num3 == 0 && num4 == 1) {

    turnL();

    green();

    delay(50);

  }

  else if (num1 == 0 && num2 == 0 && num3 == 0 && num4 == 0) {

    stop();

    red();

  }

  if ((!digitalRead(14)))         //前方有障碍物,小车停止

  {

    stop();

    red();

    pingmu();

  }

  else                          //小车继续运行,寻找书架

  {

    runfoward();

    green();

    xunshujia();

  }

}

5. 作品难点及解决方案

5.1 循迹稳定性
       在实际运行中,机器人要经过书库、阅览区,环境光线变化大,且移动的人影也容易造成较大干扰,受到以上不确定因素的影响,机器人很难准确识别循迹路线。为了提高循迹稳定性我们比较了灰度传感器、近红外传感器等多种方案,最后选用灰度传感器。
       我们在实验过程中,多次调整灰度传感器距离地面的高度,同时也对各传感器间距进行调整,提高了循迹精度。在转向时,常出现车辆出线和方向无法按轨迹转向的状况,我们通过降低转向时的速度,减少反应的延迟时间,让灰度传感器得到及时反应,最后通过左右两组电机间的差速,来让小车准确转向。下图为循迹行驶中的机器人:

循迹行驶中的机器人

5.2 机械臂稳定性
       最初设计了四轴的机械臂,由于悬臂结构过长,轴关节过多,造成稳定性与精度不高。我们最终改用了两轴的机械臂,如下图所示,防止机械臂重量过大和重心过远,避免了结构与运行不稳的情况出现。机械臂全部使用 270°舵机控制,结合升降平台的高度调整,使得取书更加稳定可靠方便。

运行中的机械臂

6. 作品前景应用

       ① 通过搭载多频段红外传感器、热成像传感器、室内 GPS 定位系统等传感器,将图书馆及藏书信息导入机器人信息库,辅以语音识别和检索系统,智能图书搬运机器人将来在校园图书馆内提供更加个性化、智能化的服务。
       ② 通过优化小车装载结构,让机器人可以实现不同类型书籍的装载,增大容错率,拓宽小车应用范围。
       ③ 通过小车的二次开发,应用在大型体育馆以及公共运动场馆等公共区域进行物资搬运。例如在高校突发疫情的时候运送防疫物资,可大大地降低搬运物资时间,保证物资能够及时送达学生手中,减轻防疫人员的负担。

* 更多详情请见 【S026】智能图书搬运机器人

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/183531.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

人工智能对网络安全的影响越来越大

如果问当前IT行业最热门的话题是什么&#xff0c;很少有人会回答除了人工智能&#xff08;AI&#xff09;之外的任何话题。 在不到 12 个月的时间里&#xff0c;人工智能已经从一项只有 IT 专业人员才能理解的技术发展成为从小学生到作家、程序员和艺术家的每个人都使用的工具…

基于单片机设计的大气气压检测装置(STC89C52+BMP180实现)

一、前言 本项目设计一个大气气压检测装置&#xff0c;该装置以单片机为基础&#xff0c;采用STC89C52作为核心控制芯片&#xff0c;结合BMP180模块作为气压传感器。大气气压&#xff0c;也就是由气体重力在大气层中产生的压力&#xff0c;其变化与天气预报、气象观测以及高度…

Python Pyvis库详解:创建交互式网络图

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是涛哥&#xff0c;今天为大家分享 Python Pyvis库详解&#xff1a;创建交互式网络图&#xff0c;文章4000字&#xff0c;阅读大约15分钟&#xff0c;大家enjoy~~ Pyvis是一个基于JavaScript库NetworkX的Pytho…

【matlab程序】南海土台风画法

【matlab程序】南海土台风画法 图片 往期推荐 图片 【python海洋专题一】查看数据nc文件的属性并输出属性到txt文件 【python海洋专题二】读取水深nc文件并水深地形图 【python海洋专题三】图像修饰之画布和坐标轴 【Python海洋专题四】之水深地图图像修饰 【Python海洋专…

U-boot(四):start_armboot

本文主要探讨210的uboot启动的第二阶段&#xff0c;主要函数为start_armboot。 uboot 一阶段初始化SoC内部部件(看门狗、时钟等),初始化DDR,重定位 二阶段初始化其余硬件(iNand、网卡芯片)以及命令、环境变量等 启动打印硬件信息,进入bootdelay,读秒完后执行bootc…

二十一、文档操作

目录 一、添加文档 1、编写代码 2、运行并查看 二、查询文档 1、编写代码 2、运行并查看 三、删除文档 1、编写代码 2、运行并查看 四、修改文档 方式一&#xff1a;全量修改&#xff0c;会删除旧文档&#xff0c;添加新文档 方式二&#xff1a;局部修改。增量修改&…

nodejs 如何将 Buffer 数据转为 String

问题说明 使用webSocket的时候出现了一个问题&#xff0c;前端小程序和nodejs后端建立websocket连接后&#xff0c;使用send方法发送到后端为buffer格式&#xff0c;以下为我前后端代码 1、前端小程序代码 //创建webSocket连接 const socket uni.connectSocket({url: wss…

工作中死循环害死人

背景&#xff1a;研发的一段代码&#xff0c;循环一直没有跳出&#xff0c;导致其他依赖逻辑有问题&#xff0c;生产事故导致9万左右数据不正常。 这里while&#xff08;true&#xff09;真的不要轻易用 &#xff0c;后来研发改动限制mysql的id切分步长&#xff0c;控制不会有数…

FreeRTOS源码阅读笔记4--semphr.h

信号量是特殊的队列--无法存储消息的队列&#xff0c;相关的接口函数声明在semphr.h中&#xff0c;通过宏定义替换队列函数实现。 4.1创建二值信号量xSemaphoreCreateBinary() 4.1.1函数原型 queueQUEUE_TYPE_BINARY_SEMAPHORE&#xff1a;一个宏&#xff0c;表示创建队列的…

gitt开源项目的意义,公司为什么会对在gitt上有开源项目的人更大机会

Git是一种分布式版本控制系统&#xff0c;它可以帮助程序员管理代码的历史版本和协同工作。同时&#xff0c;Git也成为了开源项目的主要托管平台之一。Git的开源项目意义重大&#xff0c;因为这种开源项目托管平台可以帮助开发者将代码和项目分享给全球的开发者&#xff0c;并且…

node版本管理工具-nvm

1、 下载地址 https://github.com/coreybutler/nvm-windows/releases/tag/1.1.11 2、 选择安装地址不能有空格&#xff0c;中文 3、 使用命令

微服务学习(十二):安装Minio

微服务学习&#xff08;十二&#xff09;&#xff1a;安装Minio 一、简介 MinIO 是一款基于Go语言发开的高性能、分布式的对象存储系统。客户端支持Java,Net,Python,Javacript, Golang语言。MinIO系统&#xff0c;非常适合于存储大容量非结构化的数据&#xff0c;例如图片、视…

linux上的通用拍照程序

最近因为工作需要&#xff0c;在ubuntu上开发了一个拍照程序。 为了找到合适的功能研究了好几种实现方式&#xff0c;在这里记录一下。 目录 太长不看版 探索过程 v4l2 QT opencv4.2 打开摄像头 为什么不直接打开第一个视频节点 获取所有分辨率 切换摄像头 太长不看…

MySQL错误之ONLY_FULL_GROUP_BY

报错信息&#xff1a; 翻译&#xff1a; 对该报错的解释 所以&#xff0c;实际上该报错是由于在SQL查询语句中有group by&#xff0c;而这个包含group by的SQL查询写的并不规范导致的&#xff0c;这个ONLY_FULL_GROUP_BY模式开启之后检查就会很严格&#xff0c;如果select列表…

51单片机IO口的四种工作状态切换

51单片机IO口的四种工作状态切换 1.概述 这篇文章介绍单片机IO引脚的四种工作模式&#xff0c;每个模式都有各自的用武之地&#xff0c;后面在驱动外设硬件时会用它不同的模式。 2.IO口四种工作模式介绍 PnM1PnM0I/O口工作模式00准双向口&#xff1a;灌电流达20mA&#xff…

leetcode:合并两个有序链表

题目描述 题目链接&#xff1a;21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09; 题目分析 这个算法思路很简单&#xff1a;就是直接找小尾插 定义一个tail和head&#xff0c;对比两个链表结点的val&#xff0c;小的尾插到tail->next&#xff0c;如果一个链表…

ebpf实战(一)-------监控udp延迟

问题背景: 为了分析udp数据通信中端到端的延迟,我们需要对整个通信链路的每个阶段进行监控,找出延迟最长的阶段. udp接收端有2个主要路径 1.数据包到达本机后&#xff0c;由软中断处理程序将数据包接收并放入udp socket的接收缓冲区 数据接收流程 2. 应用程序调用recvmsg等a…

如何解决tinder注册失败的问题?

tinder创立在2012年&#xff0c;是一款海外热门的交友软件。2020年&#xff0c;Tinder拥有620万用户和7500万月活跃用户。截至2021年&#xff0c;Tinder在全球范围内的匹配记录超过650亿。已成为全球最受欢迎的约会软件之一。 目前tinder暂时未对中国大陆开发使用&#xff0c;…

一个最简单的工业通讯数据分析例子

1.背景 对工业设备的通讯协议进行分析可以帮助我们更好地理解其工作原理和相关技术&#xff0c;并且有助于以下几个方面&#xff1a; 1. 优化工业设备的通讯效率&#xff1a;了解通讯协议的细节可以帮助我们找到通讯效率低下的原因并进行优化&#xff0c;提高设备的通讯效率和…

vue3实现验证码校验的功能

&#x1f4d3;最近想实现使用vue3实现一个简易的前端验证码校验的功能&#xff0c;就花了点时间实现了&#xff0c;这只是一个简易版的&#xff0c;但是用在项目中是没有啥问题的&#xff0c;废话不多说&#xff0c;先来看下最终实现的效果。 &#x1f4d3;现在让我们来一步一步…